Files
vibe-registry/examples/playground/src/widgets.tsx
T
hellow-da-sb 21c8764993 feat(render): 布局模板画廊 —— live 缩略预览 + 点选完整预览
- LayoutGallery 升级:每模板卡片 = 真实渲染缩略图(scale 0.4),点选看完整预览
- demoPageFrom:由 preview.demoBlocks 构造可渲染 demo 页(预览即真实)
- playground 新增 dashboard 布局 + stat-grid widget;app-shell 验证 DefaultLayout 兜底
- 三个模板(admin/dashboard/app-shell)全部 live 渲染验证通过
2026-09-03 01:13:55 +08:00

103 lines
3.4 KiB
TypeScript

/**
* playground 业务 widget(真实 React 组件)
* 演示:注册表 widget → React 组件 → 渲染内核装配
*/
import React from 'react'
/** 页头 */
export function PageHeader({ title, subtitle }: { title?: string; subtitle?: string }): React.ReactElement {
return React.createElement(
'header',
{ style: { marginBottom: 16 } },
React.createElement('h1', { style: { margin: '0 0 4px', fontSize: 20 } }, title ?? '未命名'),
subtitle ? React.createElement('p', { style: { margin: 0, color: '#6b7280', fontSize: 13 } }, subtitle) : null,
)
}
/** 数据表格 */
export function DataTable({
columns = [],
rows = [],
}: {
columns?: Array<{ key: string; title: string }>
rows?: Array<Record<string, unknown>>
}): React.ReactElement {
return React.createElement(
'table',
{ style: { borderCollapse: 'collapse', width: '100%', fontSize: 13 } },
React.createElement(
'thead',
{},
React.createElement(
'tr',
{},
...(columns as Array<{ key: string; title: string }>).map((c) =>
React.createElement(
'th',
{ key: c.key, style: { textAlign: 'left', padding: '6px 8px', borderBottom: '1px solid #d1d5db' } },
c.title,
),
),
),
),
React.createElement(
'tbody',
{},
...(rows as Array<Record<string, unknown>>).map((r, i) =>
React.createElement(
'tr',
{ key: i },
...(columns as Array<{ key: string; title: string }>).map((c) =>
React.createElement('td', { key: c.key, style: { padding: '6px 8px', borderBottom: '1px solid #f3f4f6' } }, String(r[c.key] ?? '')),
),
),
),
),
)
}
/** 导航菜单 */
export function NavMenu({ items = [] }: { items?: Array<{ label: string; active?: boolean }> }): React.ReactElement {
return React.createElement(
'ul',
{ style: { listStyle: 'none', margin: 0, padding: 0 } },
...(items as Array<{ label: string; active?: boolean }>).map((it, i) =>
React.createElement(
'li',
{ key: i, style: { padding: '6px 8px', borderRadius: 6, marginBottom: 2, background: it.active ? '#e0e7ff' : 'transparent' } },
it.label,
),
),
)
}
/** 统计卡片(仪表盘用) */
export function StatCard({
label,
value,
delta,
}: {
label?: string
value?: unknown
delta?: string
}): React.ReactElement {
return React.createElement(
'div',
{ style: { border: '1px solid #e5e7eb', borderRadius: 8, padding: 16, background: '#fff' } },
React.createElement('div', { style: { fontSize: 12, color: '#6b7280' } }, label ?? ''),
React.createElement('div', { style: { fontSize: 24, fontWeight: 700, margin: '4px 0' } }, String(value ?? '-')),
delta ? React.createElement('div', { style: { fontSize: 12, color: delta.startsWith('-') ? '#dc2626' : '#16a34a' } }, delta) : null,
)
}
/** 指标格子容器(dashboard 布局的内容区 demo 用) */
export function StatGrid({ stats = [] }: { stats?: Array<{ label?: string; value?: unknown; delta?: string }> }): React.ReactElement {
return React.createElement(
'div',
{ style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: 12 } },
...(stats as Array<{ label?: string; value?: unknown; delta?: string }>).map((s, i) =>
React.createElement(StatCard, { key: i, label: s.label, value: s.value, delta: s.delta }),
),
)
}