feat(ui): Empty 组件重做为纯 CSS 图形体系并支持副文案

This commit is contained in:
ozh 2026-09-09 10:35:52 +08:00
parent 84942851cb
commit f3f6c0b5ce
3 changed files with 271 additions and 8 deletions

View File

@ -5,13 +5,215 @@
padding: 80px 0;
}
.icon {
font-size: 80px;
margin-bottom: 20px;
opacity: 0.4;
.iconWrap {
width: 160px;
height: 160px;
border-radius: $radius-circle;
background: $color-bg-white;
box-shadow: $shadow-card;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 28px;
}
.text {
font-size: 28px;
color: $color-text-secondary;
}
.subText {
margin-top: 12px;
font-size: 24px;
color: $color-text-tertiary;
}
// ===== message:铃铛(浅绿底块 + 品牌绿铃舌) =====
.bell {
position: relative;
width: 66px;
height: 66px;
}
.bellTop {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 15px;
height: 15px;
border-radius: $radius-circle;
background: $color-primary-light-bg;
}
.bellBody {
position: absolute;
top: 6px;
left: 50%;
transform: translateX(-50%);
width: 62px;
height: 48px;
background: $color-primary-light-bg;
border-radius: 31px 31px 8px 8px;
}
.bellBase {
position: absolute;
bottom: 4px;
left: 50%;
transform: translateX(-50%);
width: 24px;
height: 15px;
border-radius: 0 0 12px 12px;
background: $color-primary-light-bg;
}
.bellClapper {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%) rotate(18deg);
width: 5px;
height: 37px;
border-radius: 3px;
background: $color-primary;
}
.bellHammer {
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 8px;
border-radius: 0 0 8px 8px;
background: $color-primary;
}
// ===== list:清单板(浅绿板 + 中间绿底条 + 三行勾选框/横线) =====
.listIcon {
position: relative;
width: 60px;
height: 66px;
}
.listBoard {
position: absolute;
inset: 0;
background: $color-primary-light-bg;
border-radius: 10px 10px 14px 14px;
}
.listFoot {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 6px;
background: #b8ecd8;
border-radius: 0 0 14px 14px;
}
.listRow {
position: absolute;
left: 13px;
right: 13px;
display: flex;
align-items: center;
}
.listRow1 { top: 15px; }
.listRow2 { top: 31px; }
.listRow3 { top: 47px; }
.listBox {
width: 13px;
height: 13px;
border-radius: 3px;
background: $color-primary;
}
.listLine {
flex: 1;
height: 5px;
margin-left: 7px;
border-radius: 2px;
background: #b8ecd8;
}
// ===== wifi:信号(品牌绿点 + 两道弧线) =====
.wifiIcon {
position: relative;
width: 73px;
height: 60px;
}
.wifiDot {
position: absolute;
bottom: 6px;
left: 50%;
transform: translateX(-50%);
width: 17px;
height: 17px;
border-radius: $radius-circle;
background: $color-primary;
}
.wifiArcMid {
position: absolute;
bottom: 13px;
left: 50%;
transform: translateX(-50%) rotate(-45deg);
width: 36px;
height: 13px;
border-top: 5px solid #b8ecd8;
border-radius: 18px 18px 0 0;
}
.wifiArcOuter {
position: absolute;
bottom: 23px;
left: 50%;
transform: translateX(-50%) rotate(-45deg);
width: 63px;
height: 20px;
border-top: 5px solid $color-primary-light-bg;
border-radius: 32px 32px 0 0;
}
// ===== error:警示三角(浅红底 + 深红感叹号;clip-path 真机不兼容时降级圆角矩形) =====
.warnIcon {
position: relative;
width: 66px;
height: 59px;
}
.warnTriangle {
position: absolute;
inset: 0;
background: $color-danger-light-bg;
border-radius: 10px;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.warnBar {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
width: 7px;
height: 20px;
border-radius: 3px;
background: $color-danger-deep;
}
.warnDot {
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
width: 7px;
height: 7px;
border-radius: $radius-circle;
background: $color-danger-deep;
}

View File

@ -3,15 +3,76 @@ import styles from './index.module.scss'
interface Props {
text: string
subText?: string
mode?: 'list' | 'wifi' | 'error' | 'message'
}
export function Empty({ text, mode = 'list' }: Props) {
const icon = mode === 'wifi' ? '📡' : mode === 'error' ? '⚠️' : mode === 'message' ? '🔔' : '📋'
export function Empty({ text, subText, mode = 'list' }: Props) {
return (
<View className={styles.empty}>
<Text className={styles.icon}>{icon}</Text>
<View className={styles.iconWrap}>
{mode === 'message' && <BellIcon />}
{mode === 'list' && <ListIcon />}
{mode === 'wifi' && <WifiIcon />}
{mode === 'error' && <WarnIcon />}
</View>
<Text className={styles.text}>{text}</Text>
{subText && <Text className={styles.subText}>{subText}</Text>}
</View>
)
}
// ===== 空态图形:纯 View 嵌套 + border-radius/clip-path,白色圆底由 iconWrap 提供 =====
function BellIcon() {
return (
<View className={styles.bell}>
<View className={styles.bellTop} />
<View className={styles.bellBody} />
<View className={styles.bellBase} />
<View className={styles.bellClapper} />
<View className={styles.bellHammer} />
</View>
)
}
function ListIcon() {
return (
<View className={styles.listIcon}>
<View className={styles.listBoard} />
<View className={styles.listFoot} />
<View className={`${styles.listRow} ${styles.listRow1}`}>
<View className={styles.listBox} />
<View className={styles.listLine} />
</View>
<View className={`${styles.listRow} ${styles.listRow2}`}>
<View className={styles.listBox} />
<View className={styles.listLine} />
</View>
<View className={`${styles.listRow} ${styles.listRow3}`}>
<View className={styles.listBox} />
<View className={styles.listLine} />
</View>
</View>
)
}
function WifiIcon() {
return (
<View className={styles.wifiIcon}>
<View className={styles.wifiArcOuter} />
<View className={styles.wifiArcMid} />
<View className={styles.wifiDot} />
</View>
)
}
function WarnIcon() {
return (
<View className={styles.warnIcon}>
<View className={styles.warnTriangle} />
<View className={styles.warnBar} />
<View className={styles.warnDot} />
</View>
)
}

View File

@ -68,7 +68,7 @@ export default function Index() {
{unhandled.length === 0 && messages.length === 0 && (
<View className={styles.stateWrap}>
<Empty text="暂无告警消息" mode="message" />
<Empty text="暂无告警消息" mode="message" subText="家人的安全动态将在这里展示" />
</View>
)}
</>