intable 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +102 -0
- package/docs/index-BaMALNy6.css +1 -1
- package/docs/index-CDN48t9E.js +2 -2
- package/index.html +13 -14
- package/package.json +9 -4
- package/packages/intable/package.json +1 -1
- package/packages/intable/src/index.tsx +25 -17
- package/packages/intable/src/plugins/CopyPastePlugin.tsx +49 -13
- package/packages/intable/src/plugins/DiffPlugin.tsx +31 -18
- package/packages/intable/src/theme/dark.scss +46 -0
- package/packages/intable/src/theme/github.scss +80 -0
- package/packages/intable/src/theme/material.scss +73 -0
- package/packages/intable/src/theme/shadcn.scss +66 -0
- package/packages/intable/src/theme/stripe.scss +57 -0
- package/packages/react/package.json +13 -8
- package/packages/react/src/index.ts +1 -1
- package/packages/vue/package.json +1 -1
- package/scripts/publish.js +1 -1
- package/src/index.tsx +20 -0
- package/src/pages/demo/BasicDemo.tsx +19 -0
- package/src/pages/demo/CellMergeDemo.tsx +41 -0
- package/src/pages/demo/CellSelectionDemo.tsx +24 -0
- package/src/pages/demo/CompositeDemo.tsx +60 -0
- package/src/pages/demo/CopyPasteDemo.tsx +26 -0
- package/src/pages/demo/DiffDemo.tsx +33 -0
- package/src/pages/demo/DragDemo.tsx +25 -0
- package/src/pages/demo/EditableDemo.tsx +58 -0
- package/src/pages/demo/ExpandDemo.tsx +32 -0
- package/src/pages/demo/HeaderGroupDemo.tsx +36 -0
- package/src/pages/demo/HistoryDemo.tsx +28 -0
- package/src/pages/demo/ReactDemo.tsx +59 -0
- package/src/pages/demo/ResizeDemo.tsx +24 -0
- package/src/pages/demo/RowGroupDemo.tsx +43 -0
- package/src/pages/demo/RowSelectionDemo.tsx +27 -0
- package/src/pages/demo/TreeDemo.tsx +45 -0
- package/src/pages/demo/VirtualScrollDemo.tsx +21 -0
- package/src/pages/demo/helpers.tsx +39 -0
- package/src/pages/demo/index.tsx +180 -0
- package/src/pages/index.tsx +2 -0
- package/src/pages/website.scss +37 -0
- package/src/pages/website.tsx +651 -0
- package/vite.config.ts +70 -63
- package/src/demo.tsx +0 -107
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* intable — Official Website
|
|
3
|
+
* Design: OLED Dark + Glassmorphism + Developer/Technical aesthetic
|
|
4
|
+
* Stack: SolidJS + UnoCSS (Wind4)
|
|
5
|
+
* Responsive: 375px · 768px · 1024px · 1440px
|
|
6
|
+
*/
|
|
7
|
+
import { createSignal, onMount, onCleanup, For, Show } from 'solid-js'
|
|
8
|
+
import { createMutable } from 'solid-js/store'
|
|
9
|
+
import { A } from '@solidjs/router'
|
|
10
|
+
import 'virtual:uno.css'
|
|
11
|
+
import './website.scss'
|
|
12
|
+
import { Intable } from '../../packages/intable/src'
|
|
13
|
+
import { CellSelectionPlugin } from '../../packages/intable/src/plugins/CellSelectionPlugin'
|
|
14
|
+
import { HistoryPlugin } from '../../packages/intable/src/plugins/HistoryPlugin'
|
|
15
|
+
import { ClipboardPlugin } from '../../packages/intable/src/plugins/CopyPastePlugin'
|
|
16
|
+
|
|
17
|
+
// ─── Data ───────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
const FEATURES = [
|
|
20
|
+
{
|
|
21
|
+
icon: (
|
|
22
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
23
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zm0 9.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zm9.75-9.75A2.25 2.25 0 0115.75 3.75H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zm0 9.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z" />
|
|
24
|
+
</svg>
|
|
25
|
+
),
|
|
26
|
+
title: '插件架构',
|
|
27
|
+
desc: '责任链插件体系,每个功能独立可拔插。按需组合,零冗余。',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
icon: (
|
|
31
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
32
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zm6.75-9.75A1.125 1.125 0 0110.875 2.25h2.25c.621 0 1.125.504 1.125 1.125V19.875c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V3.375zm6.75 4.5A1.125 1.125 0 0117.625 6.75h2.25c.621 0 1.125.504 1.125 1.125v12c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125v-12z" />
|
|
33
|
+
</svg>
|
|
34
|
+
),
|
|
35
|
+
title: '虚拟滚动',
|
|
36
|
+
desc: '自定义 Fenwick Tree 虚拟化引擎,百万行顺滑渲染。',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
icon: (
|
|
40
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
41
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" />
|
|
42
|
+
</svg>
|
|
43
|
+
),
|
|
44
|
+
title: '单元格编辑',
|
|
45
|
+
desc: '内置 10+ 编辑器,支持 Zod 数据校验,自定义编辑器无缝集成。',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
icon: (
|
|
49
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
50
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z" />
|
|
51
|
+
</svg>
|
|
52
|
+
),
|
|
53
|
+
title: '复制粘贴',
|
|
54
|
+
desc: '完整 Excel 式复制粘贴,支持区域平铺、CRLF 规范化、内部列过滤。',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
icon: (
|
|
58
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
59
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5" />
|
|
60
|
+
</svg>
|
|
61
|
+
),
|
|
62
|
+
title: '撤销重做',
|
|
63
|
+
desc: '完整历史记录,⌘Z / ⌘Y,命令式 API。支持与 DiffPlugin 联动。',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
icon: (
|
|
67
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-6 h-6">
|
|
68
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 7.5l3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0021 18V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v12a2.25 2.25 0 002.25 2.25z" />
|
|
69
|
+
</svg>
|
|
70
|
+
),
|
|
71
|
+
title: '多框架支持',
|
|
72
|
+
desc: 'SolidJS 核心 + React / Vue 包装器,Antd / Element Plus 编辑器适配。',
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
const PLUGINS = [
|
|
77
|
+
{ name: 'VirtualScrollPlugin', desc: '百万行虚拟化', badge: 'performance' },
|
|
78
|
+
{ name: 'EditablePlugin', desc: '单元格编辑 + 10+ 编辑器', badge: 'core' },
|
|
79
|
+
{ name: 'ZodValidatorPlugin', desc: 'Zod schema 数据校验', badge: 'validation' },
|
|
80
|
+
{ name: 'CellSelectionPlugin', desc: '矩形区域多选', badge: 'core' },
|
|
81
|
+
{ name: 'CopyPastePlugin', desc: 'Excel 式复制粘贴', badge: 'core' },
|
|
82
|
+
{ name: 'HistoryPlugin', desc: '撤销 / 重做', badge: 'core' },
|
|
83
|
+
{ name: 'DragPlugin', desc: '列 / 行拖拽排序', badge: 'ux' },
|
|
84
|
+
{ name: 'ResizePlugin', desc: '列宽 / 行高拖拽', badge: 'ux' },
|
|
85
|
+
{ name: 'ExpandPlugin', desc: '行展开自定义内容', badge: 'ux' },
|
|
86
|
+
{ name: 'RowGroupPlugin', desc: '多字段行分组', badge: 'data' },
|
|
87
|
+
{ name: 'TreePlugin', desc: '树形嵌套数据', badge: 'data' },
|
|
88
|
+
{ name: 'CellMergePlugin', desc: '单元格合并', badge: 'data' },
|
|
89
|
+
{ name: 'DiffPlugin', desc: '数据差异对比高亮', badge: 'data' },
|
|
90
|
+
{ name: 'HeaderGroupPlugin', desc: '多级分组表头', badge: 'ux' },
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
const BADGE_COLORS: Record<string, string> = {
|
|
94
|
+
performance: 'bg-emerald-500/20 text-emerald-400 border-emerald-500/30',
|
|
95
|
+
core: 'bg-indigo-500/20 text-indigo-400 border-indigo-500/30',
|
|
96
|
+
validation: 'bg-amber-500/20 text-amber-400 border-amber-500/30',
|
|
97
|
+
ux: 'bg-sky-500/20 text-sky-400 border-sky-500/30',
|
|
98
|
+
data: 'bg-violet-500/20 text-violet-400 border-violet-500/30',
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const FRAMEWORKS = [
|
|
102
|
+
{ name: 'SolidJS', color: '#4F83CC', label: 'Core' },
|
|
103
|
+
{ name: 'React', color: '#61DAFB', label: 'Wrapper' },
|
|
104
|
+
{ name: 'Vue', color: '#42D392', label: 'Wrapper' },
|
|
105
|
+
{ name: 'Antd', color: '#1677FF', label: 'UI Kit' },
|
|
106
|
+
{ name: 'Element+', color: '#409EFF', label: 'UI Kit' },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const CODE_SNIPPET = `import Intable from 'intable'
|
|
110
|
+
import { VirtualScrollPlugin } from 'intable/plugins/VirtualScrollPlugin'
|
|
111
|
+
|
|
112
|
+
const columns = [
|
|
113
|
+
{ id: 'name', name: '姓名', editable: true },
|
|
114
|
+
{ id: 'age', name: '年龄', editable: true, editor: 'number' },
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
export default () => (
|
|
118
|
+
<Intable
|
|
119
|
+
data={rows}
|
|
120
|
+
columns={columns}
|
|
121
|
+
plugins={[VirtualScrollPlugin]}
|
|
122
|
+
index border stickyHeader
|
|
123
|
+
onDataChange={setRows}
|
|
124
|
+
/>
|
|
125
|
+
)`
|
|
126
|
+
|
|
127
|
+
// ─── Typed code animation ────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
function useTypingEffect(text: string, speed = 18) {
|
|
130
|
+
const [displayed, setDisplayed] = createSignal('')
|
|
131
|
+
const [done, setDone] = createSignal(false)
|
|
132
|
+
onMount(() => {
|
|
133
|
+
let i = 0
|
|
134
|
+
const id = setInterval(() => {
|
|
135
|
+
i++
|
|
136
|
+
setDisplayed(text.slice(0, i))
|
|
137
|
+
if (i >= text.length) { clearInterval(id); setDone(true) }
|
|
138
|
+
}, speed)
|
|
139
|
+
onCleanup(() => clearInterval(id))
|
|
140
|
+
})
|
|
141
|
+
return { displayed, done }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─── Syntax highlight (minimal token colorizer) ─────────────────────────────
|
|
145
|
+
|
|
146
|
+
// Use inline styles so this is independent of UnoCSS class generation.
|
|
147
|
+
// Apply each pass only to the *text* content, not to already-emitted HTML tags,
|
|
148
|
+
// by using a placeholder strategy: collect spans and replace them at the end.
|
|
149
|
+
function highlight(code: string) {
|
|
150
|
+
const S = (color: string, text: string) => `<span style="color:${color}">${text}</span>`
|
|
151
|
+
return code
|
|
152
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
153
|
+
// strings (do before keywords so 'from' inside import path stays green)
|
|
154
|
+
.replace(/('[^']*')/g, (_, s) => S('#6ee7b7', s))
|
|
155
|
+
// numbers (do BEFORE adding any spans, avoiding matches inside class attrs)
|
|
156
|
+
.replace(/\b(\d+)\b/g, (_, n) => S('#fb923c', n))
|
|
157
|
+
// comments (full rest-of-line, escape first)
|
|
158
|
+
.replace(/(\/\/.*)/, (_, c) => S('#475569', c))
|
|
159
|
+
// keywords
|
|
160
|
+
.replace(/\b(import|from|export|default|const|return)\b/g, (_, k) => S('#c4b5fd', k))
|
|
161
|
+
// JSX component names
|
|
162
|
+
.replace(/(<\/?)(Intable)(\s|>)/g, (_, a, t, b) => a + S('#7dd3fc', t) + b)
|
|
163
|
+
// prop names (word before ={)
|
|
164
|
+
.replace(/\b(\w+)(?==\s*\{)/g, (_, p) => S('#fde68a', p))
|
|
165
|
+
// boolean props (standalone identifiers on their own "line")
|
|
166
|
+
.replace(/\b(index|border|stickyHeader)\b/g, (_, p) => S('#fde68a', p))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ─── Components ─────────────────────────────────────────────────────────────
|
|
170
|
+
|
|
171
|
+
function Navbar() {
|
|
172
|
+
const [open, setOpen] = createSignal(false)
|
|
173
|
+
const [scrolled, setScrolled] = createSignal(false)
|
|
174
|
+
onMount(() => {
|
|
175
|
+
const handler = () => setScrolled(window.scrollY > 40)
|
|
176
|
+
window.addEventListener('scroll', handler, { passive: true })
|
|
177
|
+
onCleanup(() => window.removeEventListener('scroll', handler))
|
|
178
|
+
})
|
|
179
|
+
return (
|
|
180
|
+
<header
|
|
181
|
+
class={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${
|
|
182
|
+
scrolled() ? 'backdrop-blur-xl border-b border-white/5 shadow-lg shadow-black/30' : 'bg-transparent'
|
|
183
|
+
}`}
|
|
184
|
+
style={scrolled() ? 'background:rgba(10,10,15,0.92)' : ''}
|
|
185
|
+
>
|
|
186
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
187
|
+
<div class="flex items-center justify-between h-16">
|
|
188
|
+
{/* Logo */}
|
|
189
|
+
<a href="#" class="flex items-center gap-2 group cursor-pointer">
|
|
190
|
+
<div class="w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center shadow-lg shadow-indigo-500/30 group-hover:shadow-indigo-500/50 transition-shadow duration-200">
|
|
191
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" class="w-4 h-4">
|
|
192
|
+
<rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" />
|
|
193
|
+
<rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" />
|
|
194
|
+
</svg>
|
|
195
|
+
</div>
|
|
196
|
+
<span class="font-mono font-bold text-white text-lg tracking-tight">intable</span>
|
|
197
|
+
</a>
|
|
198
|
+
{/* Desktop nav */}
|
|
199
|
+
<nav class="hidden md:flex items-center gap-1">
|
|
200
|
+
{(['功能', '插件', '快速开始', '文档'] as const).map(item => (
|
|
201
|
+
<a
|
|
202
|
+
href={`#${item}`}
|
|
203
|
+
class="px-4 py-2 text-sm text-slate-400 hover:text-white rounded-lg hover:bg-white/5 transition-colors duration-150 cursor-pointer"
|
|
204
|
+
>
|
|
205
|
+
{item}
|
|
206
|
+
</a>
|
|
207
|
+
))}
|
|
208
|
+
<A
|
|
209
|
+
href="/demo"
|
|
210
|
+
class="px-4 py-2 text-sm text-slate-400 hover:text-white rounded-lg hover:bg-white/5 transition-colors duration-150 cursor-pointer"
|
|
211
|
+
>
|
|
212
|
+
Demo
|
|
213
|
+
</A>
|
|
214
|
+
</nav>
|
|
215
|
+
{/* Actions */}
|
|
216
|
+
<div class="hidden md:flex items-center gap-3">
|
|
217
|
+
<a
|
|
218
|
+
href="https://github.com"
|
|
219
|
+
target="_blank"
|
|
220
|
+
rel="noopener noreferrer"
|
|
221
|
+
class="flex items-center gap-2 px-3 py-1.5 text-sm text-slate-400 hover:text-white border border-white/10 hover:border-white/20 rounded-lg transition-all duration-150 cursor-pointer"
|
|
222
|
+
>
|
|
223
|
+
<svg viewBox="0 0 24 24" fill="currentColor" class="w-4 h-4">
|
|
224
|
+
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
|
|
225
|
+
</svg>
|
|
226
|
+
GitHub
|
|
227
|
+
</a>
|
|
228
|
+
<a
|
|
229
|
+
href="#快速开始"
|
|
230
|
+
class="px-4 py-1.5 text-sm font-medium bg-indigo-600 hover:bg-indigo-500 text-white rounded-lg transition-colors duration-150 cursor-pointer"
|
|
231
|
+
>
|
|
232
|
+
开始使用
|
|
233
|
+
</a>
|
|
234
|
+
</div>
|
|
235
|
+
{/* Mobile menu toggle */}
|
|
236
|
+
<button
|
|
237
|
+
class="md:hidden p-2 text-slate-400 hover:text-white rounded-lg hover:bg-white/5 cursor-pointer transition-colors"
|
|
238
|
+
onClick={() => setOpen(o => !o)}
|
|
239
|
+
aria-label="菜单"
|
|
240
|
+
>
|
|
241
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-5 h-5">
|
|
242
|
+
<Show when={open()} fallback={<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />}>
|
|
243
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
244
|
+
</Show>
|
|
245
|
+
</svg>
|
|
246
|
+
</button>
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
{/* Mobile menu */}
|
|
250
|
+
<Show when={open()}>
|
|
251
|
+
<div class="md:hidden border-b border-white/5 px-4 pb-4 backdrop-blur-xl" style="background:rgba(10,10,15,0.97)">
|
|
252
|
+
{(['功能', '插件', '快速开始', '文档'] as const).map(item => (
|
|
253
|
+
<a
|
|
254
|
+
href={`#${item}`}
|
|
255
|
+
class="block px-3 py-3 text-sm text-slate-400 hover:text-white border-b border-white/5 last:border-0 cursor-pointer"
|
|
256
|
+
onClick={() => setOpen(false)}
|
|
257
|
+
>
|
|
258
|
+
{item}
|
|
259
|
+
</a>
|
|
260
|
+
))}
|
|
261
|
+
<A
|
|
262
|
+
href="/demo"
|
|
263
|
+
class="block px-3 py-3 text-sm text-slate-400 hover:text-white border-b border-white/5 cursor-pointer"
|
|
264
|
+
onClick={() => setOpen(false)}
|
|
265
|
+
>
|
|
266
|
+
Demo
|
|
267
|
+
</A>
|
|
268
|
+
<div class="flex gap-3 mt-3">
|
|
269
|
+
<a href="https://github.com" class="flex-1 py-2 text-center text-sm text-slate-400 border border-white/10 rounded-lg cursor-pointer">GitHub</a>
|
|
270
|
+
<a href="#快速开始" class="flex-1 py-2 text-center text-sm text-white bg-indigo-600 rounded-lg cursor-pointer">开始使用</a>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
</Show>
|
|
274
|
+
</header>
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function Hero() {
|
|
279
|
+
return (
|
|
280
|
+
<section class="relative min-h-screen flex flex-col items-center justify-center overflow-hidden pt-16">
|
|
281
|
+
{/* Ambient background */}
|
|
282
|
+
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
|
|
283
|
+
<div class="absolute top-1/4 left-1/2 -translate-x-1/2 w-[800px] h-[600px] bg-indigo-600/10 rounded-full blur-[120px]" />
|
|
284
|
+
<div class="absolute top-1/3 left-1/4 w-[400px] h-[400px] bg-violet-600/8 rounded-full blur-[100px]" />
|
|
285
|
+
<div class="absolute bottom-1/4 right-1/4 w-[300px] h-[300px] bg-sky-600/6 rounded-full blur-[80px]" />
|
|
286
|
+
{/* Grid lines */}
|
|
287
|
+
<div class="absolute inset-0 opacity-[0.03]" style="background-image: linear-gradient(rgba(99,102,241,.4) 1px,transparent 1px),linear-gradient(90deg,rgba(99,102,241,.4) 1px,transparent 1px); background-size: 60px 60px" />
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div class="relative max-w-5xl mx-auto px-4 sm:px-6 text-center">
|
|
291
|
+
{/* Badge */}
|
|
292
|
+
<div class="inline-flex items-center gap-2 px-3 py-1.5 mb-8 rounded-full bg-indigo-500/10 border border-indigo-500/20 text-indigo-400 text-xs font-mono">
|
|
293
|
+
<span class="w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse" />
|
|
294
|
+
Plugin-based · Virtual Scroll · Multi-Framework
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
{/* Title */}
|
|
298
|
+
<h1 class="text-5xl sm:text-6xl lg:text-7xl font-mono font-bold text-white leading-[1.1] tracking-tight mb-6">
|
|
299
|
+
类 Excel 表格
|
|
300
|
+
<br />
|
|
301
|
+
<span class="bg-gradient-to-r from-indigo-400 via-violet-400 to-sky-400 bg-clip-text text-transparent">
|
|
302
|
+
组件库
|
|
303
|
+
</span>
|
|
304
|
+
</h1>
|
|
305
|
+
|
|
306
|
+
<p class="text-lg sm:text-xl text-slate-400 max-w-2xl mx-auto mb-10 leading-relaxed">
|
|
307
|
+
基于 SolidJS 的高性能表格组件,插件化架构,虚拟滚动,单元格编辑,
|
|
308
|
+
多选复制粘贴,支持 React / Vue。
|
|
309
|
+
</p>
|
|
310
|
+
|
|
311
|
+
{/* CTA */}
|
|
312
|
+
<div class="flex flex-wrap items-center justify-center gap-4 mb-16">
|
|
313
|
+
<a
|
|
314
|
+
href="#快速开始"
|
|
315
|
+
class="inline-flex items-center gap-2 px-6 py-3 bg-indigo-600 hover:bg-indigo-500 text-white font-medium rounded-xl transition-all duration-200 shadow-lg shadow-indigo-500/25 hover:shadow-indigo-500/40 cursor-pointer"
|
|
316
|
+
>
|
|
317
|
+
快速开始
|
|
318
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-4 h-4">
|
|
319
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12m0 0l-7.5 7.5M21 12H3" />
|
|
320
|
+
</svg>
|
|
321
|
+
</a>
|
|
322
|
+
<a
|
|
323
|
+
href="#功能"
|
|
324
|
+
class="inline-flex items-center gap-2 px-6 py-3 text-slate-300 hover:text-white border border-white/10 hover:border-white/20 rounded-xl transition-all duration-200 cursor-pointer hover:bg-white/5"
|
|
325
|
+
>
|
|
326
|
+
查看功能
|
|
327
|
+
</a>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
{/* Stats */}
|
|
331
|
+
<div class="flex flex-wrap justify-center gap-8 sm:gap-16 text-center">
|
|
332
|
+
{[
|
|
333
|
+
{ val: '14+', label: '插件' },
|
|
334
|
+
{ val: '1M+', label: '行虚拟化' },
|
|
335
|
+
{ val: '3', label: '框架支持' },
|
|
336
|
+
{ val: '0', label: '外部依赖*' },
|
|
337
|
+
].map(s => (
|
|
338
|
+
<div>
|
|
339
|
+
<div class="text-2xl sm:text-3xl font-mono font-bold text-white">{s.val}</div>
|
|
340
|
+
<div class="text-sm text-slate-500 mt-0.5">{s.label}</div>
|
|
341
|
+
</div>
|
|
342
|
+
))}
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
{/* Scroll indicator */}
|
|
347
|
+
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-1 text-slate-600 animate-bounce">
|
|
348
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="w-5 h-5">
|
|
349
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
|
350
|
+
</svg>
|
|
351
|
+
</div>
|
|
352
|
+
</section>
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function Features() {
|
|
357
|
+
return (
|
|
358
|
+
<section id="功能" class="py-24 sm:py-32">
|
|
359
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
360
|
+
<div class="text-center mb-16">
|
|
361
|
+
<p class="text-sm font-mono text-indigo-400 mb-3 tracking-widest uppercase">Core Features</p>
|
|
362
|
+
<h2 class="text-3xl sm:text-4xl font-mono font-bold text-white mb-4">一切你需要的功能</h2>
|
|
363
|
+
<p class="text-slate-400 max-w-xl mx-auto">每个特性都是独立插件,按需引入,无额外体积负担。</p>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
|
367
|
+
<For each={FEATURES}>{(f, _i) => (
|
|
368
|
+
<div class="relative p-6 rounded-2xl border" style="background:rgba(255,255,255,0.015)"
|
|
369
|
+
>
|
|
370
|
+
{/* Glow on hover */}
|
|
371
|
+
<div class="absolute inset-0 rounded-2xl bg-gradient-to-br from-indigo-500/0 to-violet-500/0 group-hover:from-indigo-500/5 group-hover:to-violet-500/5 transition-all duration-300" />
|
|
372
|
+
<div class="relative">
|
|
373
|
+
<div class="w-10 h-10 rounded-xl bg-indigo-500/10 text-indigo-400 flex items-center justify-center mb-4 group-hover:bg-indigo-500/20 transition-colors duration-200">
|
|
374
|
+
{f.icon}
|
|
375
|
+
</div>
|
|
376
|
+
<h3 class="font-mono font-semibold text-white mb-2">{f.title}</h3>
|
|
377
|
+
<p class="text-sm text-slate-400 leading-relaxed">{f.desc}</p>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
)}</For>
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
</section>
|
|
384
|
+
)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function PluginsSection() {
|
|
388
|
+
return (
|
|
389
|
+
<section id="插件" class="py-24 sm:py-32 relative overflow-hidden">
|
|
390
|
+
{/* Background */}
|
|
391
|
+
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
|
|
392
|
+
<div class="absolute top-1/2 right-0 w-[500px] h-[500px] bg-violet-600/6 rounded-full blur-[100px]" />
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
396
|
+
<div class="lg:grid lg:grid-cols-2 lg:gap-16 lg:items-start">
|
|
397
|
+
{/* Left */}
|
|
398
|
+
<div class="mb-12 lg:mb-0 lg:sticky lg:top-24">
|
|
399
|
+
<p class="text-sm font-mono text-violet-400 mb-3 tracking-widest uppercase">Plugin System</p>
|
|
400
|
+
<h2 class="text-3xl sm:text-4xl font-mono font-bold text-white mb-6">责任链插件体系</h2>
|
|
401
|
+
<p class="text-slate-400 leading-relaxed mb-6">
|
|
402
|
+
所有功能通过 <code class="font-mono text-violet-300 bg-violet-500/10 px-1.5 py-0.5 rounded text-sm">rewriteProps</code> 管道链式变换。
|
|
403
|
+
每个插件接收上一个的输出,完全可组合、可替换。
|
|
404
|
+
</p>
|
|
405
|
+
<pre class="text-xs font-mono text-slate-400 border border-white/5 rounded-xl p-4 overflow-x-auto leading-relaxed" style="background:#0f0f1a">
|
|
406
|
+
{`<Intable
|
|
407
|
+
plugins={[
|
|
408
|
+
VirtualScrollPlugin,
|
|
409
|
+
EditablePlugin,
|
|
410
|
+
HistoryPlugin,
|
|
411
|
+
ClipboardPlugin,
|
|
412
|
+
]}
|
|
413
|
+
/>`}
|
|
414
|
+
</pre>
|
|
415
|
+
{/* Framework badges */}
|
|
416
|
+
<div class="mt-8">
|
|
417
|
+
<p class="text-xs text-slate-500 mb-3">多框架支持</p>
|
|
418
|
+
<div class="flex flex-wrap gap-2">
|
|
419
|
+
<For each={FRAMEWORKS}>{(fw) => (
|
|
420
|
+
<div class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-white/5 text-xs text-slate-300" style="background:rgba(255,255,255,0.03)">
|
|
421
|
+
<span class="w-2 h-2 rounded-full" style={`background:${fw.color}`} />
|
|
422
|
+
{fw.name}
|
|
423
|
+
<span class="text-slate-600">·</span>
|
|
424
|
+
<span class="text-slate-500">{fw.label}</span>
|
|
425
|
+
</div>
|
|
426
|
+
)}</For>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
{/* Right: plugin grid */}
|
|
432
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
433
|
+
<For each={PLUGINS}>{(p) => (
|
|
434
|
+
<div
|
|
435
|
+
class="flex items-start gap-3 p-4 rounded-xl border border-white/5 hover:border-violet-500/20 transition-all duration-200 group cursor-default"
|
|
436
|
+
style="background:rgba(255,255,255,0.015)"
|
|
437
|
+
>
|
|
438
|
+
<div class="mt-0.5 w-1.5 h-1.5 rounded-full bg-slate-600 group-hover:bg-violet-400 transition-colors flex-shrink-0" />
|
|
439
|
+
<div class="min-w-0">
|
|
440
|
+
<div class="flex items-center gap-2 flex-wrap mb-0.5">
|
|
441
|
+
<span class="font-mono text-xs text-white truncate">{p.name}</span>
|
|
442
|
+
<span class={`px-1.5 py-0.5 rounded text-[10px] font-medium border ${BADGE_COLORS[p.badge]}`}>
|
|
443
|
+
{p.badge}
|
|
444
|
+
</span>
|
|
445
|
+
</div>
|
|
446
|
+
<p class="text-xs text-slate-500">{p.desc}</p>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
)}</For>
|
|
450
|
+
</div>
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
</section>
|
|
454
|
+
)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function CodeSection() {
|
|
458
|
+
const { displayed, done } = useTypingEffect(CODE_SNIPPET, 16)
|
|
459
|
+
return (
|
|
460
|
+
<section id="快速开始" class="py-24 sm:py-32 relative overflow-hidden">
|
|
461
|
+
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
|
|
462
|
+
<div class="absolute bottom-0 left-1/4 w-[600px] h-[400px] bg-indigo-600/6 rounded-full blur-[100px]" />
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
466
|
+
<div class="text-center mb-16">
|
|
467
|
+
<p class="text-sm font-mono text-sky-400 mb-3 tracking-widest uppercase">Quick Start</p>
|
|
468
|
+
<h2 class="text-3xl sm:text-4xl font-mono font-bold text-white mb-4">几行代码,即刻上手</h2>
|
|
469
|
+
<p class="text-slate-400">安装包后,直接引入组件与需要的插件。</p>
|
|
470
|
+
</div>
|
|
471
|
+
|
|
472
|
+
<div class="grid lg:grid-cols-2 gap-8 items-start">
|
|
473
|
+
{/* Install steps */}
|
|
474
|
+
<div class="space-y-4">
|
|
475
|
+
{[
|
|
476
|
+
{ step: '01', label: '安装', cmd: 'pnpm add intable' },
|
|
477
|
+
{ step: '02', label: 'Vue', cmd: 'pnpm add @intable/vue' },
|
|
478
|
+
{ step: '03', label: 'React', cmd: 'pnpm add @intable/react' },
|
|
479
|
+
].map(s => (
|
|
480
|
+
<div class="flex items-center gap-4 p-4 rounded-xl border border-white/5" style="background:rgba(255,255,255,0.015)">
|
|
481
|
+
<span class="font-mono text-xs text-slate-600 w-6 shrink-0">{s.step}</span>
|
|
482
|
+
<div class="min-w-0">
|
|
483
|
+
<p class="text-xs text-slate-500 mb-1">{s.label}</p>
|
|
484
|
+
<code class="font-mono text-sm text-slate-200">{s.cmd}</code>
|
|
485
|
+
</div>
|
|
486
|
+
</div>
|
|
487
|
+
))}
|
|
488
|
+
|
|
489
|
+
{/* Key props */}
|
|
490
|
+
<div class="mt-8">
|
|
491
|
+
<p class="text-xs font-mono text-slate-500 mb-3 uppercase tracking-wider">常用 Props</p>
|
|
492
|
+
<div class="space-y-2 text-sm font-mono">
|
|
493
|
+
{[
|
|
494
|
+
['data', 'any[]', 'Table rows'],
|
|
495
|
+
['columns', 'Column[]', 'Column definitions'],
|
|
496
|
+
['plugins', 'Plugin[]', 'Feature plugins'],
|
|
497
|
+
['onDataChange', '(data) => void', 'Data mutation callback'],
|
|
498
|
+
['index', 'boolean', 'Show row numbers'],
|
|
499
|
+
['virtual', '{ x?, y? }', 'Virtual scroll config'],
|
|
500
|
+
].map(([prop, type, note]) => (
|
|
501
|
+
<div class="flex items-baseline gap-3 py-1.5 border-b border-white/3 last:border-0">
|
|
502
|
+
<span class="text-amber-300 shrink-0">{prop}</span>
|
|
503
|
+
<span class="text-slate-500 text-xs shrink-0">{type}</span>
|
|
504
|
+
<span class="text-slate-600 text-xs ml-auto text-right">{note}</span>
|
|
505
|
+
</div>
|
|
506
|
+
))}
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
|
|
511
|
+
{/* Code editor */}
|
|
512
|
+
<div class="rounded-2xl border border-white/8 overflow-hidden shadow-2xl shadow-black/50">
|
|
513
|
+
{/* Title bar */}
|
|
514
|
+
<div class="flex items-center gap-2 px-4 py-3 border-b border-white/5" style="background:#0f0f1a">
|
|
515
|
+
<span class="w-3 h-3 rounded-full bg-red-500/70" />
|
|
516
|
+
<span class="w-3 h-3 rounded-full bg-amber-500/70" />
|
|
517
|
+
<span class="w-3 h-3 rounded-full bg-green-500/70" />
|
|
518
|
+
<span class="ml-3 text-xs font-mono text-slate-500">App.tsx</span>
|
|
519
|
+
</div>
|
|
520
|
+
{/* Code */}
|
|
521
|
+
<div class="relative p-5 overflow-x-auto min-h-[320px]" style="background:#0a0a12">
|
|
522
|
+
<pre class="text-sm font-mono leading-relaxed">
|
|
523
|
+
<code
|
|
524
|
+
innerHTML={highlight(displayed())}
|
|
525
|
+
/>
|
|
526
|
+
<Show when={!done()}>
|
|
527
|
+
<span class="inline-block w-0.5 h-4 bg-indigo-400 animate-pulse ml-px align-text-bottom" />
|
|
528
|
+
</Show>
|
|
529
|
+
</pre>
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
</div>
|
|
533
|
+
</div>
|
|
534
|
+
</section>
|
|
535
|
+
)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function TableDemo() {
|
|
539
|
+
const cols = [
|
|
540
|
+
{ id: 'sku', name: 'SKU', editable: true },
|
|
541
|
+
{ id: 'product', name: '产品名', editable: true },
|
|
542
|
+
{ id: 'category', name: '分类', editable: true },
|
|
543
|
+
{ id: 'stock', name: '库存', editable: true },
|
|
544
|
+
{ id: 'price', name: '单价', editable: true },
|
|
545
|
+
]
|
|
546
|
+
const data = createMutable([
|
|
547
|
+
{ id: 0, sku: 'SKU-001', product: 'MacBook Pro 16"', category: '笔记本', stock: 12, price: '¥18999' },
|
|
548
|
+
{ id: 1, sku: 'SKU-002', product: 'iPad Air', category: '平板', stock: 28, price: '¥4599' },
|
|
549
|
+
{ id: 2, sku: 'SKU-003', product: 'AirPods Pro', category: '耳机', stock: 45, price: '¥1899' },
|
|
550
|
+
{ id: 3, sku: 'SKU-004', product: 'Apple Watch', category: '穿戴设备', stock: 18, price: '¥2999' },
|
|
551
|
+
{ id: 4, sku: 'SKU-005', product: 'Magic Mouse', category: '配件', stock: 67, price: '¥799' },
|
|
552
|
+
{ id: 5, sku: 'SKU-006', product: 'MacBook Air M3', category: '笔记本', stock: 34, price: '¥11999' },
|
|
553
|
+
{ id: 6, sku: 'SKU-007', product: 'iPad Pro 12.9"', category: '平板', stock: 15, price: '¥6899' },
|
|
554
|
+
{ id: 7, sku: 'SKU-008', product: 'AirPods Max', category: '耳机', stock: 8, price: '¥3999' },
|
|
555
|
+
{ id: 8, sku: 'SKU-009', product: 'Mac Mini M4', category: '台式机', stock: 22, price: '¥4399' },
|
|
556
|
+
{ id: 9, sku: 'SKU-010', product: 'Studio Display', category: '显示器', stock: 5, price: '¥11499' },
|
|
557
|
+
{ id: 10, sku: 'SKU-011', product: 'iPhone 16 Pro', category: '手机', stock: 56, price: '¥8999' },
|
|
558
|
+
{ id: 11, sku: 'SKU-012', product: 'Apple TV 4K', category: '配件', stock: 31, price: '¥1499' },
|
|
559
|
+
])
|
|
560
|
+
|
|
561
|
+
return (
|
|
562
|
+
<section class="py-16 sm:py-24">
|
|
563
|
+
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
564
|
+
<div class="text-center mb-10">
|
|
565
|
+
<p class="text-sm font-mono text-emerald-400 mb-3 tracking-widest uppercase">Live Demo</p>
|
|
566
|
+
<h2 class="text-2xl sm:text-3xl font-mono font-bold text-white">它长这样</h2>
|
|
567
|
+
<p class="text-sm text-slate-500 mt-2 font-mono">点击选择 · ⌘C 复制 · ⌘Z 撤销</p>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
<div class="wt-live-demo rounded-2xl border border-white/8 overflow-hidden shadow-2xl shadow-black/40">
|
|
571
|
+
<Intable
|
|
572
|
+
style="max-height:240px"
|
|
573
|
+
data={data}
|
|
574
|
+
onDataChange={v => v.forEach((row, i) => Object.assign(data[i], row))}
|
|
575
|
+
columns={cols}
|
|
576
|
+
index
|
|
577
|
+
border
|
|
578
|
+
stickyHeader
|
|
579
|
+
size="small"
|
|
580
|
+
plugins={[CellSelectionPlugin, HistoryPlugin, ClipboardPlugin]}
|
|
581
|
+
/>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
</section>
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function Footer() {
|
|
589
|
+
return (
|
|
590
|
+
<footer class="border-t border-white/5 py-12 mt-8">
|
|
591
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
592
|
+
<div class="flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
593
|
+
<div class="flex items-center gap-2">
|
|
594
|
+
<div class="w-6 h-6 rounded-md bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center">
|
|
595
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5" class="w-3 h-3">
|
|
596
|
+
<rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" />
|
|
597
|
+
<rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" />
|
|
598
|
+
</svg>
|
|
599
|
+
</div>
|
|
600
|
+
<span class="font-mono font-bold text-slate-400">intable</span>
|
|
601
|
+
</div>
|
|
602
|
+
<p class="text-xs text-slate-600 font-mono">MIT License · Built with SolidJS</p>
|
|
603
|
+
<div class="flex items-center gap-4 text-xs text-slate-600 font-mono">
|
|
604
|
+
<a href="#功能" class="hover:text-slate-400 transition-colors cursor-pointer">功能</a>
|
|
605
|
+
<a href="#插件" class="hover:text-slate-400 transition-colors cursor-pointer">插件</a>
|
|
606
|
+
<a href="#快速开始" class="hover:text-slate-400 transition-colors cursor-pointer">文档</a>
|
|
607
|
+
</div>
|
|
608
|
+
</div>
|
|
609
|
+
</div>
|
|
610
|
+
</footer>
|
|
611
|
+
)
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// ─── Root ────────────────────────────────────────────────────────────────────
|
|
615
|
+
|
|
616
|
+
export const Website = () => {
|
|
617
|
+
return (
|
|
618
|
+
<div style="background:#080810;color:#fff;min-height:100vh;font-family:'IBM Plex Sans',system-ui,sans-serif">
|
|
619
|
+
<style>{`
|
|
620
|
+
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap');
|
|
621
|
+
.font-mono { font-family: 'JetBrains Mono', ui-monospace, monospace; }
|
|
622
|
+
html { scroll-behavior: smooth; }
|
|
623
|
+
@media (prefers-reduced-motion: reduce) {
|
|
624
|
+
*, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
|
|
625
|
+
}
|
|
626
|
+
:focus-visible { outline: 2px solid #6366f1; outline-offset: 2px; border-radius: 6px; }
|
|
627
|
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
|
628
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
629
|
+
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }
|
|
630
|
+
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); }
|
|
631
|
+
`}</style>
|
|
632
|
+
|
|
633
|
+
{/* Skip to content (a11y) */}
|
|
634
|
+
<a href="#功能" class="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-[100] focus:px-4 focus:py-2 focus:bg-indigo-600 focus:text-white focus:rounded-lg focus:text-sm">
|
|
635
|
+
跳到主要内容
|
|
636
|
+
</a>
|
|
637
|
+
|
|
638
|
+
<Navbar />
|
|
639
|
+
<main>
|
|
640
|
+
<Hero />
|
|
641
|
+
<Features />
|
|
642
|
+
<TableDemo />
|
|
643
|
+
<PluginsSection />
|
|
644
|
+
<CodeSection />
|
|
645
|
+
</main>
|
|
646
|
+
<Footer />
|
|
647
|
+
</div>
|
|
648
|
+
)
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
export default Website
|