Files
yingqing/core/frontend/src/components/loading.tsx
T

89 lines
3.0 KiB
TypeScript

import type { ReactNode } from "react";
import { IconKitSvg } from "./IconKitSvg";
import "./loading.css";
export function SystemLoading({
variant = "page",
state = "loading",
title = "正在加载",
description = "正在同步最新数据,请稍候。",
icon = "activity",
reference,
actions,
}: {
variant?: "inline" | "page" | "fullscreen";
state?: "loading" | "error";
title?: string;
description?: string;
icon?: string;
reference?: string;
actions?: ReactNode;
}) {
return (
<div className={`system-loading system-loading--${variant}${state === "error" ? " is-error" : ""}`} role={state === "error" ? "alert" : "status"} aria-live="polite">
<div className="system-loading-card">
<span className="system-loading-corner corner-tl" aria-hidden="true">+</span>
<span className="system-loading-corner corner-tr" aria-hidden="true">+</span>
<span className="system-loading-corner corner-bl" aria-hidden="true">+</span>
<span className="system-loading-corner corner-br" aria-hidden="true">+</span>
<div className="system-loading-meta mono">
<span>[ AIRSHELF / SYSTEM ]</span>
<span>{state === "error" ? "[ CONNECTION ERROR ]" : "[ SYNCING ]"}</span>
</div>
<div className="system-loading-main">
<div className="system-loading-icon" aria-hidden="true">
<IconKitSvg name={icon} size={20} />
{state === "loading" && <span className="system-loading-orbit" />}
</div>
<div className="system-loading-copy">
<h2>{title}</h2>
<p>{description}</p>
</div>
</div>
{actions ? (
<div className="system-loading-actions">{actions}</div>
) : state === "loading" ? (
<div className="system-loading-progress" aria-hidden="true">
<span /><span /><span /><span /><span />
</div>
) : null}
<div className="system-loading-foot mono">
<span>{reference ? `// REF · ${reference}` : "// DATA SYNC"}</span>
<span>{state === "error" ? "RETRY AVAILABLE" : "DATA HYDRATION"}</span>
</div>
</div>
</div>
);
}
// 列表数据在途时的骨架屏(grid 卡片 / 行),替代「为空」状态,让用户看到「加载中」而非「没数据」。
export function SkeletonGrid({ count = 8 }: { count?: number }) {
return (
<div>
<div className="skeleton-loading-tag">// 加载中…</div>
<div className="skeleton-grid">
{Array.from({ length: count }).map((_, i) => (
<div className="skeleton-block skeleton-card" key={i} />
))}
</div>
</div>
);
}
export function SkeletonRows({ count = 6 }: { count?: number }) {
return (
<div>
<div className="skeleton-loading-tag">// 加载中…</div>
<div className="skeleton-rows">
{Array.from({ length: count }).map((_, i) => (
<div className="skeleton-block skeleton-line" key={i} />
))}
</div>
</div>
);
}