239 lines
7.4 KiB
TypeScript
239 lines
7.4 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { Toaster } from '../src'
|
|
import { Avatars } from './sections/Avatars'
|
|
import { Breadcrumbs } from './sections/Breadcrumbs'
|
|
import { Buttons } from './sections/Buttons'
|
|
import { Cards } from './sections/Cards'
|
|
import { Covers } from './sections/Covers'
|
|
import { Checkboxes } from './sections/Checkboxes'
|
|
import { Composition } from './sections/Composition'
|
|
import { Drawers } from './sections/Drawers'
|
|
import { Feedback } from './sections/Feedback'
|
|
import { Icons } from './sections/Icons'
|
|
import { Images } from './sections/Images'
|
|
import { Inputs } from './sections/Inputs'
|
|
import { Layouts } from './sections/Layouts'
|
|
import { Marks } from './sections/Marks'
|
|
import { MenuSection } from './sections/MenuSection'
|
|
import { Modals } from './sections/Modals'
|
|
import { Overview } from './sections/Overview'
|
|
import { PageLayout } from './sections/PageLayout'
|
|
import { Paginations } from './sections/Paginations'
|
|
import { Progresses } from './sections/Progresses'
|
|
import { RadioGroups } from './sections/RadioGroups'
|
|
import { Results } from './sections/Results'
|
|
import { ScrollTopSection } from './sections/ScrollTopSection'
|
|
import { Segmenteds } from './sections/Segmenteds'
|
|
import { Selects } from './sections/Selects'
|
|
import { Skeletons } from './sections/Skeletons'
|
|
import { Spinners } from './sections/Spinners'
|
|
import { StepsSection } from './sections/StepsSection'
|
|
import { Switches } from './sections/Switches'
|
|
import { Tables } from './sections/Tables'
|
|
import { TabsSection } from './sections/TabsSection'
|
|
import { Toasts } from './sections/Toasts'
|
|
import { Tooltips } from './sections/Tooltips'
|
|
import { Typographies } from './sections/Typographies'
|
|
|
|
/**
|
|
* 组件展示站:左侧目录 + 右侧示例。
|
|
*
|
|
* 页面只负责摆示例,所有样式都来自组件库本身;
|
|
* 站点自己的排版样式收在 `app.css`,不污染组件。
|
|
*/
|
|
const NAV = [
|
|
{
|
|
title: '基础',
|
|
items: [
|
|
{ id: 'overview', label: '设计令牌' },
|
|
{ id: 'typography', label: '排版 Typography' },
|
|
{ id: 'icons', label: '图标 Icon' },
|
|
{ id: 'buttons', label: '按钮 Button' },
|
|
],
|
|
},
|
|
{
|
|
title: '展示',
|
|
items: [
|
|
{ id: 'cards', label: '卡片 Card' },
|
|
{ id: 'cover', label: '封面卡 Cover' },
|
|
{ id: 'image', label: '图片 Image' },
|
|
{ id: 'marks', label: '标记 Tag / Badge' },
|
|
{ id: 'avatars', label: '头像 Avatar' },
|
|
{ id: 'table', label: '表格 Table' },
|
|
{ id: 'result', label: '结果 Result' },
|
|
{ id: 'progress', label: '进度 Progress' },
|
|
{ id: 'steps', label: '步骤 Steps' },
|
|
],
|
|
},
|
|
{
|
|
title: '表单',
|
|
items: [
|
|
{ id: 'inputs', label: '输入框 Input' },
|
|
{ id: 'select', label: '下拉 Select' },
|
|
{ id: 'switch', label: '开关 Switch' },
|
|
{ id: 'checkbox', label: '复选框 Checkbox' },
|
|
{ id: 'radio', label: '单选 Radio' },
|
|
{ id: 'segmented', label: '分段 Segmented' },
|
|
],
|
|
},
|
|
{
|
|
title: '导航',
|
|
items: [
|
|
{ id: 'breadcrumb', label: '面包屑 Breadcrumb' },
|
|
{ id: 'tabs', label: '标签页 Tabs' },
|
|
{ id: 'menu', label: '菜单 Menu' },
|
|
],
|
|
},
|
|
{
|
|
title: '交互',
|
|
items: [
|
|
{ id: 'skeleton', label: '骨架屏 Skeleton' },
|
|
{ id: 'spinner', label: '加载 Spinner' },
|
|
{ id: 'feedback', label: '提示与空态' },
|
|
{ id: 'toast', label: '轻提示 Toast' },
|
|
{ id: 'modal', label: '弹窗 Modal' },
|
|
{ id: 'drawer', label: '抽屉 Drawer' },
|
|
{ id: 'pagination', label: '分页 Pagination' },
|
|
{ id: 'scrolltop', label: '回到顶部' },
|
|
{ id: 'tooltip', label: '工具提示 Tooltip' },
|
|
],
|
|
},
|
|
{
|
|
title: '布局与组合',
|
|
items: [
|
|
{ id: 'layout', label: '页面骨架 Layout' },
|
|
{ id: 'layouts', label: '网格与间距' },
|
|
{ id: 'composition', label: '组合示例' },
|
|
],
|
|
},
|
|
] as const
|
|
|
|
const SECTION_IDS = NAV.flatMap((group) => group.items.map((item) => item.id))
|
|
|
|
/** 滚动监听:当前视口里最靠上的那一节高亮 */
|
|
function useActiveSection(): string {
|
|
const [active, setActive] = useState<string>(SECTION_IDS[0])
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
const visible = entries
|
|
.filter((entry) => entry.isIntersecting)
|
|
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)
|
|
|
|
if (visible.length > 0) setActive(visible[0].target.id)
|
|
},
|
|
{ rootMargin: '-72px 0px -68% 0px' },
|
|
)
|
|
|
|
for (const id of SECTION_IDS) {
|
|
const element = document.getElementById(id)
|
|
if (element !== null) observer.observe(element)
|
|
}
|
|
|
|
return () => observer.disconnect()
|
|
}, [])
|
|
|
|
return active
|
|
}
|
|
|
|
export function App() {
|
|
const active = useActiveSection()
|
|
|
|
return (
|
|
<div className="doc-shell">
|
|
<aside className="doc-sidebar">
|
|
<a className="doc-brand" href="#overview">
|
|
<span className="doc-brand-mark">S</span>
|
|
<span>
|
|
<strong>Stash UI</strong>
|
|
<em>v0.1.0</em>
|
|
</span>
|
|
</a>
|
|
|
|
<p className="doc-brand-desc">
|
|
一套按 Alright 主题打磨的基础组件,供 Stash 控制台与后续页面组合使用。
|
|
</p>
|
|
|
|
<nav className="doc-nav" aria-label="组件目录">
|
|
{NAV.map((group) => (
|
|
<section key={group.title}>
|
|
<h2>{group.title}</h2>
|
|
<ul>
|
|
{group.items.map((item) => (
|
|
<li key={item.id}>
|
|
<a href={`#${item.id}`} className={active === item.id ? 'is-active' : undefined}>
|
|
{item.label}
|
|
</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
))}
|
|
</nav>
|
|
|
|
<footer className="doc-sidebar-footer">
|
|
令牌定义:<code>src/theme/tokens.css</code>
|
|
<a className="doc-demo-link" href="/demo.html">
|
|
整页拼装示例 →
|
|
</a>
|
|
</footer>
|
|
</aside>
|
|
|
|
<main className="doc-main">
|
|
<header className="doc-hero">
|
|
<p className="doc-eyebrow">DESIGN SYSTEM</p>
|
|
<h1>Stash UI</h1>
|
|
<p className="doc-hero-desc">
|
|
独立于应用的设计系统项目:令牌、基础组件、以及一个可以直接翻的组件展示页。
|
|
组件只依赖令牌,不依赖任何页面数据,所以换页面、换应用都能直接拼。
|
|
</p>
|
|
<div className="doc-hero-meta">
|
|
<span>40 个基础组件</span>
|
|
<span>零运行时依赖</span>
|
|
<span>CSS Modules + 设计令牌</span>
|
|
<span>对齐 Alright 参考站</span>
|
|
</div>
|
|
</header>
|
|
|
|
<Overview />
|
|
<Typographies />
|
|
<Icons />
|
|
<Buttons />
|
|
<Cards />
|
|
<Covers />
|
|
<Images />
|
|
<Marks />
|
|
<Avatars />
|
|
<Tables />
|
|
<Results />
|
|
<Progresses />
|
|
<StepsSection />
|
|
<Inputs />
|
|
<Selects />
|
|
<Switches />
|
|
<Checkboxes />
|
|
<RadioGroups />
|
|
<Segmenteds />
|
|
<Breadcrumbs />
|
|
<TabsSection />
|
|
<MenuSection />
|
|
<Skeletons />
|
|
<Spinners />
|
|
<Feedback />
|
|
<Toasts />
|
|
<Modals />
|
|
<Drawers />
|
|
<Paginations />
|
|
<ScrollTopSection />
|
|
<Tooltips />
|
|
<PageLayout />
|
|
<Layouts />
|
|
<Composition />
|
|
</main>
|
|
|
|
<Toaster />
|
|
</div>
|
|
)
|
|
}
|