diff --git a/frontend/src/components/Skeleton.module.css b/frontend/src/components/Skeleton.module.css new file mode 100644 index 0000000..c05035f --- /dev/null +++ b/frontend/src/components/Skeleton.module.css @@ -0,0 +1,56 @@ +.shimmer { + background: linear-gradient( + 90deg, + var(--skeleton-base) 25%, + var(--skeleton-shine) 50%, + var(--skeleton-base) 75% + ); + background-size: 200% 100%; + animation: skeletonShine 1.5s infinite; + border-radius: var(--radius); +} + +@keyframes skeletonShine { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +.text { + height: 16px; + margin-bottom: 10px; +} + +.textShort { + composes: text; + width: 60%; +} + +.textMedium { + composes: text; + width: 80%; +} + +.card { + height: 200px; + width: 100%; +} + +.tableRow { + display: flex; + gap: 16px; + margin-bottom: 12px; +} + +.tableCell { + height: 14px; + flex: 1; +} + +.tableCellNarrow { + height: 14px; + width: 80px; +} diff --git a/frontend/src/components/Skeleton.tsx b/frontend/src/components/Skeleton.tsx new file mode 100644 index 0000000..b31486a --- /dev/null +++ b/frontend/src/components/Skeleton.tsx @@ -0,0 +1,40 @@ +import styles from './Skeleton.module.css' + +interface SkeletonProps { + variant?: 'text' | 'card' | 'table' + lines?: number +} + +export default function Skeleton({ variant = 'text', lines = 3 }: SkeletonProps) { + if (variant === 'card') { + return
+ } + + if (variant === 'table') { + return ( += { pending: { label: '等待中', color: 'var(--text-muted)' }, @@ -42,8 +43,8 @@ export default function ProjectPage() { } return ( -
-
加载中...
+