@hanzo/ui 8.0.6 → 8.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/dist/ThemeToggleNext-7727UR5W.js +4 -0
- package/dist/ThemeToggleNext-7727UR5W.js.map +1 -0
- package/dist/ThemeToggleNext-ICB5KL5J.cjs +19 -0
- package/dist/ThemeToggleNext-ICB5KL5J.cjs.map +1 -0
- package/dist/billing.cjs +15 -0
- package/dist/billing.cjs.map +1 -0
- package/{types → dist}/billing.d.ts +0 -1
- package/dist/billing.js +4 -0
- package/dist/billing.js.map +1 -0
- package/dist/canvas.cjs +15 -0
- package/dist/canvas.cjs.map +1 -0
- package/dist/canvas.d.ts +1 -0
- package/dist/canvas.js +4 -0
- package/dist/canvas.js.map +1 -0
- package/{types → dist}/cd/layout.d.ts +0 -1
- package/{types → dist}/cd/status.d.ts +0 -1
- package/{types → dist}/cd/time.d.ts +0 -1
- package/{types → dist}/cd/types.d.ts +0 -1
- package/dist/chunk-42CU5GSF.js +98 -0
- package/dist/chunk-42CU5GSF.js.map +1 -0
- package/dist/chunk-GDGVXU7W.js +1999 -0
- package/dist/chunk-GDGVXU7W.js.map +1 -0
- package/dist/chunk-HSPMQQVJ.cjs +2066 -0
- package/dist/chunk-HSPMQQVJ.cjs.map +1 -0
- package/dist/chunk-YBXVUV7P.cjs +103 -0
- package/dist/chunk-YBXVUV7P.cjs.map +1 -0
- package/dist/dashboard.cjs +15 -0
- package/dist/dashboard.cjs.map +1 -0
- package/dist/dashboard.d.ts +1 -0
- package/dist/dashboard.js +4 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/data.cjs +15 -0
- package/dist/data.cjs.map +1 -0
- package/dist/data.d.ts +1 -0
- package/dist/data.js +4 -0
- package/dist/data.js.map +1 -0
- package/dist/gitops.cjs +15 -0
- package/dist/gitops.cjs.map +1 -0
- package/dist/gitops.d.ts +1 -0
- package/dist/gitops.js +4 -0
- package/dist/gitops.js.map +1 -0
- package/dist/index.cjs +291 -0
- package/dist/index.cjs.map +1 -0
- package/{types → dist}/index.d.ts +0 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/network.cjs +15 -0
- package/dist/network.cjs.map +1 -0
- package/{types → dist}/network.d.ts +0 -1
- package/dist/network.js +4 -0
- package/dist/network.js.map +1 -0
- package/dist/primitives/bases/data/index.cjs +15 -0
- package/dist/primitives/bases/data/index.cjs.map +1 -0
- package/dist/primitives/bases/data/index.d.ts +1 -0
- package/dist/primitives/bases/data/index.js +4 -0
- package/dist/primitives/bases/data/index.js.map +1 -0
- package/{types → dist}/product/AppHeader.d.ts +0 -1
- package/{types → dist}/product/BrandMark.d.ts +0 -1
- package/{types → dist}/product/Charts.d.ts +0 -1
- package/{types → dist}/product/ComboBox.d.ts +0 -1
- package/{types → dist}/product/DataTable.d.ts +0 -1
- package/{types → dist}/product/Donut.d.ts +0 -1
- package/{types → dist}/product/EmptyState.d.ts +0 -1
- package/{types → dist}/product/FadeIn.d.ts +0 -1
- package/{types → dist}/product/Field.d.ts +0 -1
- package/{types → dist}/product/HanzoMark.d.ts +0 -1
- package/{types → dist}/product/Metric.d.ts +0 -1
- package/{types → dist}/product/OrgSwitcher.d.ts +0 -1
- package/{types → dist}/product/PageHeader.d.ts +0 -1
- package/{types → dist}/product/PrimaryButton.d.ts +0 -1
- package/{types → dist}/product/ProductIcon.d.ts +0 -1
- package/{types → dist}/product/ProviderLogo.d.ts +0 -1
- package/{types → dist}/product/Reorder.d.ts +0 -1
- package/{types → dist}/product/SelectMenu.d.ts +7 -6
- package/{types → dist}/product/SlideOver.d.ts +0 -1
- package/{types → dist}/product/StatusTag.d.ts +0 -1
- package/dist/product/ThemeToggle.d.ts +21 -0
- package/dist/product/ThemeToggleNext.d.ts +4 -0
- package/{types → dist}/product/Toast.d.ts +0 -1
- package/{types → dist}/product/color.d.ts +0 -1
- package/{types → dist}/product/combobox/filter.d.ts +0 -1
- package/dist/product/index.cjs +278 -0
- package/dist/product/index.cjs.map +1 -0
- package/{types → dist}/product/index.d.ts +2 -1
- package/dist/product/index.js +5 -0
- package/dist/product/index.js.map +1 -0
- package/dist/product/menu/ContextMenu.d.ts +21 -0
- package/dist/product/menu/DropdownMenu.d.ts +29 -0
- package/dist/product/menu/FloatingMenu.d.ts +36 -0
- package/dist/product/menu/index.d.ts +5 -0
- package/dist/product/menu/items.d.ts +68 -0
- package/dist/product/menu/portal-theme.d.ts +28 -0
- package/dist/product/menu/roving.d.ts +8 -0
- package/{types → dist}/product/scope.d.ts +0 -1
- package/{types → dist}/product/surfaces.data.d.ts +0 -1
- package/dist/usage.cjs +15 -0
- package/dist/usage.cjs.map +1 -0
- package/dist/usage.d.ts +1 -0
- package/dist/usage.js +4 -0
- package/dist/usage.js.map +1 -0
- package/dist/wallet.cjs +15 -0
- package/dist/wallet.cjs.map +1 -0
- package/{types → dist}/wallet.d.ts +0 -1
- package/dist/wallet.js +4 -0
- package/dist/wallet.js.map +1 -0
- package/package.json +58 -32
- package/src/billing.ts +0 -9
- package/src/canvas.ts +0 -11
- package/src/cd/layout.ts +0 -184
- package/src/cd/status.ts +0 -158
- package/src/cd/time.ts +0 -52
- package/src/cd/types.ts +0 -318
- package/src/dashboard.ts +0 -8
- package/src/data.ts +0 -12
- package/src/gitops.ts +0 -5
- package/src/gui-env.d.ts +0 -27
- package/src/index.ts +0 -22
- package/src/network.ts +0 -11
- package/src/primitives/bases/data/index.ts +0 -13
- package/src/product/AppHeader.tsx +0 -183
- package/src/product/BrandMark.tsx +0 -27
- package/src/product/Charts.tsx +0 -471
- package/src/product/ComboBox.tsx +0 -147
- package/src/product/DataTable.tsx +0 -99
- package/src/product/Donut.tsx +0 -83
- package/src/product/EmptyState.tsx +0 -129
- package/src/product/FadeIn.tsx +0 -38
- package/src/product/Field.tsx +0 -160
- package/src/product/HanzoMark.tsx +0 -31
- package/src/product/Metric.tsx +0 -253
- package/src/product/OrgSwitcher.tsx +0 -332
- package/src/product/PageHeader.tsx +0 -31
- package/src/product/PrimaryButton.tsx +0 -17
- package/src/product/ProductIcon.tsx +0 -61
- package/src/product/ProviderLogo.tsx +0 -137
- package/src/product/Reorder.test.ts +0 -41
- package/src/product/Reorder.tsx +0 -110
- package/src/product/SelectMenu.tsx +0 -94
- package/src/product/SlideOver.tsx +0 -197
- package/src/product/StatusTag.tsx +0 -49
- package/src/product/ThemeToggle.tsx +0 -25
- package/src/product/Toast.tsx +0 -166
- package/src/product/color.ts +0 -17
- package/src/product/combobox/filter.test.ts +0 -51
- package/src/product/combobox/filter.ts +0 -39
- package/src/product/index.ts +0 -70
- package/src/product/scope.test.ts +0 -92
- package/src/product/scope.ts +0 -123
- package/src/product/surfaces.data.ts +0 -42
- package/src/usage.ts +0 -8
- package/src/wallet.ts +0 -11
- package/types/billing.d.ts.map +0 -1
- package/types/canvas.d.ts +0 -2
- package/types/canvas.d.ts.map +0 -1
- package/types/cd/layout.d.ts.map +0 -1
- package/types/cd/status.d.ts.map +0 -1
- package/types/cd/time.d.ts.map +0 -1
- package/types/cd/types.d.ts.map +0 -1
- package/types/dashboard.d.ts +0 -2
- package/types/dashboard.d.ts.map +0 -1
- package/types/data.d.ts +0 -2
- package/types/data.d.ts.map +0 -1
- package/types/gitops.d.ts +0 -2
- package/types/gitops.d.ts.map +0 -1
- package/types/index.d.ts.map +0 -1
- package/types/network.d.ts.map +0 -1
- package/types/primitives/bases/data/index.d.ts +0 -2
- package/types/primitives/bases/data/index.d.ts.map +0 -1
- package/types/product/AppHeader.d.ts.map +0 -1
- package/types/product/BrandMark.d.ts.map +0 -1
- package/types/product/Charts.d.ts.map +0 -1
- package/types/product/ComboBox.d.ts.map +0 -1
- package/types/product/DataTable.d.ts.map +0 -1
- package/types/product/Donut.d.ts.map +0 -1
- package/types/product/EmptyState.d.ts.map +0 -1
- package/types/product/FadeIn.d.ts.map +0 -1
- package/types/product/Field.d.ts.map +0 -1
- package/types/product/HanzoMark.d.ts.map +0 -1
- package/types/product/Metric.d.ts.map +0 -1
- package/types/product/OrgSwitcher.d.ts.map +0 -1
- package/types/product/PageHeader.d.ts.map +0 -1
- package/types/product/PrimaryButton.d.ts.map +0 -1
- package/types/product/ProductIcon.d.ts.map +0 -1
- package/types/product/ProviderLogo.d.ts.map +0 -1
- package/types/product/Reorder.d.ts.map +0 -1
- package/types/product/SelectMenu.d.ts.map +0 -1
- package/types/product/SlideOver.d.ts.map +0 -1
- package/types/product/StatusTag.d.ts.map +0 -1
- package/types/product/ThemeToggle.d.ts +0 -2
- package/types/product/ThemeToggle.d.ts.map +0 -1
- package/types/product/Toast.d.ts.map +0 -1
- package/types/product/color.d.ts.map +0 -1
- package/types/product/combobox/filter.d.ts.map +0 -1
- package/types/product/index.d.ts.map +0 -1
- package/types/product/scope.d.ts.map +0 -1
- package/types/product/surfaces.data.d.ts.map +0 -1
- package/types/usage.d.ts +0 -2
- package/types/usage.d.ts.map +0 -1
- package/types/wallet.d.ts.map +0 -1
- /package/{src → dist}/styles/hanzo-motion.css +0 -0
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generic data table — the shared list primitive for every product module.
|
|
5
|
-
*
|
|
6
|
-
* Rows are typed `<T>`; columns declare a key, header, and optional cell
|
|
7
|
-
* renderer. Built on Hanzo GUI Stacks (shorthand style props per the v5 config)
|
|
8
|
-
* so it adapts across platforms. Loading and empty states are first-class.
|
|
9
|
-
*/
|
|
10
|
-
import type { ReactNode } from 'react'
|
|
11
|
-
import { Spinner, Text, XStack, YStack } from '@hanzo/gui'
|
|
12
|
-
|
|
13
|
-
export type Column<T> = {
|
|
14
|
-
key: string
|
|
15
|
-
header: string
|
|
16
|
-
/** Cell renderer; defaults to `String(row[key])`. */
|
|
17
|
-
render?: (row: T) => ReactNode
|
|
18
|
-
/** Fixed width (px) for the column; otherwise flexes. */
|
|
19
|
-
width?: number
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function DataTable<T>({
|
|
23
|
-
columns,
|
|
24
|
-
rows,
|
|
25
|
-
loading,
|
|
26
|
-
empty = 'Nothing here yet.',
|
|
27
|
-
rowKey,
|
|
28
|
-
onRowPress,
|
|
29
|
-
}: {
|
|
30
|
-
columns: Column<T>[]
|
|
31
|
-
rows: T[]
|
|
32
|
-
loading?: boolean
|
|
33
|
-
empty?: string
|
|
34
|
-
rowKey: (row: T) => string
|
|
35
|
-
onRowPress?: (row: T) => void
|
|
36
|
-
}) {
|
|
37
|
-
if (loading) {
|
|
38
|
-
return (
|
|
39
|
-
<XStack p="$6" justify="center">
|
|
40
|
-
<Spinner size="large" color="$color11" />
|
|
41
|
-
</XStack>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (rows.length === 0) {
|
|
46
|
-
return (
|
|
47
|
-
<YStack p="$6" items="center" borderWidth={1} borderColor="$borderColor" rounded="$4">
|
|
48
|
-
<Text color="$color11">{empty}</Text>
|
|
49
|
-
</YStack>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<YStack borderWidth={1} borderColor="$borderColor" rounded="$4" overflow="hidden">
|
|
55
|
-
<XStack bg="$color2" py="$2.5" px="$3" gap="$3">
|
|
56
|
-
{columns.map((c) => (
|
|
57
|
-
<Text
|
|
58
|
-
key={c.key}
|
|
59
|
-
width={c.width}
|
|
60
|
-
flex={c.width ? undefined : 1}
|
|
61
|
-
fontSize="$2"
|
|
62
|
-
fontWeight="700"
|
|
63
|
-
color="$color11"
|
|
64
|
-
>
|
|
65
|
-
{c.header}
|
|
66
|
-
</Text>
|
|
67
|
-
))}
|
|
68
|
-
</XStack>
|
|
69
|
-
<YStack>
|
|
70
|
-
{rows.map((row) => (
|
|
71
|
-
<XStack
|
|
72
|
-
key={rowKey(row)}
|
|
73
|
-
py="$2.5"
|
|
74
|
-
px="$3"
|
|
75
|
-
gap="$3"
|
|
76
|
-
borderTopWidth={1}
|
|
77
|
-
borderColor="$borderColor"
|
|
78
|
-
items="center"
|
|
79
|
-
hoverStyle={onRowPress ? { bg: '$color2' } : undefined}
|
|
80
|
-
cursor={onRowPress ? 'pointer' : undefined}
|
|
81
|
-
onPress={onRowPress ? () => onRowPress(row) : undefined}
|
|
82
|
-
>
|
|
83
|
-
{columns.map((c) => (
|
|
84
|
-
<YStack key={c.key} width={c.width} flex={c.width ? undefined : 1}>
|
|
85
|
-
{c.render ? (
|
|
86
|
-
c.render(row)
|
|
87
|
-
) : (
|
|
88
|
-
<Text fontSize="$3" numberOfLines={1}>
|
|
89
|
-
{String((row as Record<string, unknown>)[c.key] ?? '')}
|
|
90
|
-
</Text>
|
|
91
|
-
)}
|
|
92
|
-
</YStack>
|
|
93
|
-
))}
|
|
94
|
-
</XStack>
|
|
95
|
-
))}
|
|
96
|
-
</YStack>
|
|
97
|
-
</YStack>
|
|
98
|
-
)
|
|
99
|
-
}
|
package/src/product/Donut.tsx
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Donut — a tiny dependency-free SVG ring for a categorical breakdown
|
|
5
|
-
* (e.g. machines by status). Standard library first: no chart dependency for a
|
|
6
|
-
* single ring. It renders ONLY the real segments it is given and returns `null`
|
|
7
|
-
* when the total is zero, so the caller shows an honest empty state instead of an
|
|
8
|
-
* empty circle. Purely presentational — all values come from the caller.
|
|
9
|
-
*/
|
|
10
|
-
export type DonutSegment = { label: string; value: number; color: string }
|
|
11
|
-
|
|
12
|
-
export function Donut({
|
|
13
|
-
segments,
|
|
14
|
-
size = 160,
|
|
15
|
-
thickness = 18,
|
|
16
|
-
centerValue,
|
|
17
|
-
centerLabel,
|
|
18
|
-
trackColor = '#2a2d2e',
|
|
19
|
-
valueColor = '#ecedee',
|
|
20
|
-
labelColor = '#9ba1a6',
|
|
21
|
-
}: {
|
|
22
|
-
segments: DonutSegment[]
|
|
23
|
-
size?: number
|
|
24
|
-
thickness?: number
|
|
25
|
-
/** Big number in the middle (e.g. total). */
|
|
26
|
-
centerValue?: string
|
|
27
|
-
/** Caption under the center value. */
|
|
28
|
-
centerLabel?: string
|
|
29
|
-
/** Unfilled-ring color (explicit hex so it never depends on theme var names). */
|
|
30
|
-
trackColor?: string
|
|
31
|
-
valueColor?: string
|
|
32
|
-
labelColor?: string
|
|
33
|
-
}) {
|
|
34
|
-
const total = segments.reduce((n, s) => n + Math.max(0, s.value), 0)
|
|
35
|
-
if (total <= 0) return null
|
|
36
|
-
|
|
37
|
-
const r = (size - thickness) / 2
|
|
38
|
-
const cx = size / 2
|
|
39
|
-
const cy = size / 2
|
|
40
|
-
const circ = 2 * Math.PI * r
|
|
41
|
-
|
|
42
|
-
let offset = 0
|
|
43
|
-
const arcs = segments
|
|
44
|
-
.filter((s) => s.value > 0)
|
|
45
|
-
.map((s) => {
|
|
46
|
-
const frac = s.value / total
|
|
47
|
-
const dash = frac * circ
|
|
48
|
-
const node = (
|
|
49
|
-
<circle
|
|
50
|
-
key={s.label}
|
|
51
|
-
cx={cx}
|
|
52
|
-
cy={cy}
|
|
53
|
-
r={r}
|
|
54
|
-
fill="none"
|
|
55
|
-
stroke={s.color}
|
|
56
|
-
strokeWidth={thickness}
|
|
57
|
-
strokeDasharray={`${dash} ${circ - dash}`}
|
|
58
|
-
strokeDashoffset={-offset}
|
|
59
|
-
/>
|
|
60
|
-
)
|
|
61
|
-
offset += dash
|
|
62
|
-
return node
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} role="img" aria-label="Donut chart">
|
|
67
|
-
{/* track */}
|
|
68
|
-
<circle cx={cx} cy={cy} r={r} fill="none" stroke={trackColor} strokeWidth={thickness} />
|
|
69
|
-
{/* segments, drawn from 12 o'clock */}
|
|
70
|
-
<g transform={`rotate(-90 ${cx} ${cy})`}>{arcs}</g>
|
|
71
|
-
{centerValue ? (
|
|
72
|
-
<text x={cx} y={cy - 2} textAnchor="middle" fontSize={size * 0.2} fontWeight="800" fill={valueColor}>
|
|
73
|
-
{centerValue}
|
|
74
|
-
</text>
|
|
75
|
-
) : null}
|
|
76
|
-
{centerLabel ? (
|
|
77
|
-
<text x={cx} y={cy + size * 0.13} textAnchor="middle" fontSize={size * 0.08} fill={labelColor}>
|
|
78
|
-
{centerLabel}
|
|
79
|
-
</text>
|
|
80
|
-
) : null}
|
|
81
|
-
</svg>
|
|
82
|
-
)
|
|
83
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Rich empty state — the ONE way the console turns a real, honest "nothing here
|
|
5
|
-
* yet" into a helpful onboarding moment (DigitalOcean / Vercel class) instead of
|
|
6
|
-
* a dead screen.
|
|
7
|
-
*
|
|
8
|
-
* It is NOT a fabricated-data fallback: callers render it only when a load
|
|
9
|
-
* genuinely succeeded with zero rows (or a resource has no surface yet). It shows
|
|
10
|
-
* the product icon, a one-line "what this is", a couple of guidance bullets, a
|
|
11
|
-
* single primary call-to-action (Deploy / Create / Connect …) and an optional
|
|
12
|
-
* secondary link (Docs / CLI). Orthogonal to `BackendStateCard` (failures) and
|
|
13
|
-
* `DataTable`'s thin inline empty (in-table) — this is the full-bleed first-run
|
|
14
|
-
* surface a module shows in place of its table.
|
|
15
|
-
*/
|
|
16
|
-
import type { ReactElement, ReactNode } from 'react'
|
|
17
|
-
import { Button, Card, Text, XStack, YStack } from '@hanzo/gui'
|
|
18
|
-
import { ArrowRight, Check, ExternalLink } from '@hanzogui/lucide-icons-2'
|
|
19
|
-
|
|
20
|
-
import type { IconLike } from './color'
|
|
21
|
-
import { PrimaryButton } from './PrimaryButton'
|
|
22
|
-
|
|
23
|
-
/** A single call-to-action — primary (filled) or a secondary/external link. */
|
|
24
|
-
export type EmptyAction = {
|
|
25
|
-
label: string
|
|
26
|
-
/** In-app navigation / handler. */
|
|
27
|
-
onPress?: () => void
|
|
28
|
-
/** External URL — opens in a new tab with an external-link affordance. */
|
|
29
|
-
href?: string
|
|
30
|
-
icon?: ReactElement
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Open an external URL in a new tab (no-opener), guarded for SSR. */
|
|
34
|
-
function openHref(href: string): void {
|
|
35
|
-
if (typeof window !== 'undefined') window.open(href, '_blank', 'noopener')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function EmptyState({
|
|
39
|
-
icon: Icon,
|
|
40
|
-
title,
|
|
41
|
-
description,
|
|
42
|
-
bullets,
|
|
43
|
-
primary,
|
|
44
|
-
secondary,
|
|
45
|
-
}: {
|
|
46
|
-
/** Product/section icon — any lucide/Gui icon component (size + optional color). */
|
|
47
|
-
icon: IconLike
|
|
48
|
-
title: string
|
|
49
|
-
description: string
|
|
50
|
-
/** Optional "here's how to get started" guidance bullets. */
|
|
51
|
-
bullets?: string[]
|
|
52
|
-
/** The single high-emphasis action (Deploy / Create / Connect). */
|
|
53
|
-
primary?: EmptyAction
|
|
54
|
-
/** An optional lower-emphasis action (Docs / CLI / Learn more). */
|
|
55
|
-
secondary?: EmptyAction
|
|
56
|
-
}) {
|
|
57
|
-
return (
|
|
58
|
-
<Card
|
|
59
|
-
borderWidth={1}
|
|
60
|
-
borderColor="$borderColor"
|
|
61
|
-
borderStyle="dashed"
|
|
62
|
-
p="$6"
|
|
63
|
-
gap="$4"
|
|
64
|
-
items="center"
|
|
65
|
-
maxWidth={640}
|
|
66
|
-
self="center"
|
|
67
|
-
width="100%"
|
|
68
|
-
>
|
|
69
|
-
<YStack
|
|
70
|
-
width={48}
|
|
71
|
-
height={48}
|
|
72
|
-
items="center"
|
|
73
|
-
justify="center"
|
|
74
|
-
rounded="$4"
|
|
75
|
-
bg="$color3"
|
|
76
|
-
>
|
|
77
|
-
<Icon size={24} />
|
|
78
|
-
</YStack>
|
|
79
|
-
|
|
80
|
-
<YStack gap="$2" items="center" maxW={480}>
|
|
81
|
-
<Text fontSize="$6" fontWeight="800" text="center">
|
|
82
|
-
{title}
|
|
83
|
-
</Text>
|
|
84
|
-
<Text fontSize="$3" color="$color11" text="center">
|
|
85
|
-
{description}
|
|
86
|
-
</Text>
|
|
87
|
-
</YStack>
|
|
88
|
-
|
|
89
|
-
{bullets && bullets.length ? (
|
|
90
|
-
<YStack gap="$2" self="stretch" maxW={420} mx="auto">
|
|
91
|
-
{bullets.map((b) => (
|
|
92
|
-
<XStack key={b} gap="$2" items="flex-start">
|
|
93
|
-
<YStack pt="$1">
|
|
94
|
-
<Check size={14} color="$color10" />
|
|
95
|
-
</YStack>
|
|
96
|
-
<Text fontSize="$3" color="$color11" flex={1}>
|
|
97
|
-
{b}
|
|
98
|
-
</Text>
|
|
99
|
-
</XStack>
|
|
100
|
-
))}
|
|
101
|
-
</YStack>
|
|
102
|
-
) : null}
|
|
103
|
-
|
|
104
|
-
{primary || secondary ? (
|
|
105
|
-
<XStack gap="$2" items="center" flexWrap="wrap" justify="center">
|
|
106
|
-
{primary ? (
|
|
107
|
-
<PrimaryButton
|
|
108
|
-
icon={primary.icon}
|
|
109
|
-
iconAfter={primary.href ? <ExternalLink size={15} /> : <ArrowRight size={15} />}
|
|
110
|
-
onPress={() => (primary.href ? openHref(primary.href) : primary.onPress?.())}
|
|
111
|
-
>
|
|
112
|
-
{primary.label}
|
|
113
|
-
</PrimaryButton>
|
|
114
|
-
) : null}
|
|
115
|
-
{secondary ? (
|
|
116
|
-
<Button
|
|
117
|
-
chromeless
|
|
118
|
-
icon={secondary.icon}
|
|
119
|
-
iconAfter={secondary.href ? <ExternalLink size={14} /> : undefined}
|
|
120
|
-
onPress={() => (secondary.href ? openHref(secondary.href) : secondary.onPress?.())}
|
|
121
|
-
>
|
|
122
|
-
{secondary.label}
|
|
123
|
-
</Button>
|
|
124
|
-
) : null}
|
|
125
|
-
</XStack>
|
|
126
|
-
) : null}
|
|
127
|
-
</Card>
|
|
128
|
-
)
|
|
129
|
-
}
|
package/src/product/FadeIn.tsx
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* FadeIn — the ONE entrance animation for the console.
|
|
5
|
-
*
|
|
6
|
-
* A thin wrapper that applies the shared `.hz-fade-up` keyframe (defined once in
|
|
7
|
-
* globals.css) plus an optional stagger delay, so sections and cards rise in the
|
|
8
|
-
* way the hanzo.ai marketing surface does. Framework-free (no animation driver,
|
|
9
|
-
* no JS observers) so it works under static export and honors
|
|
10
|
-
* `prefers-reduced-motion` (handled in the CSS). Pass `index` to stagger a list
|
|
11
|
-
* (delay = index * step), or `delayMs` for an explicit delay.
|
|
12
|
-
*/
|
|
13
|
-
import type { CSSProperties, ReactNode } from 'react'
|
|
14
|
-
|
|
15
|
-
export function FadeIn({
|
|
16
|
-
children,
|
|
17
|
-
index = 0,
|
|
18
|
-
step = 50,
|
|
19
|
-
delayMs,
|
|
20
|
-
style,
|
|
21
|
-
}: {
|
|
22
|
-
children: ReactNode
|
|
23
|
-
/** Position in a list — staggers the entrance by `index * step` ms. */
|
|
24
|
-
index?: number
|
|
25
|
-
/** Per-index stagger in ms (default 50). */
|
|
26
|
-
step?: number
|
|
27
|
-
/** Explicit delay in ms; overrides the index-based stagger. */
|
|
28
|
-
delayMs?: number
|
|
29
|
-
/** Extra styles for the wrapper (e.g. layout/centering). */
|
|
30
|
-
style?: CSSProperties
|
|
31
|
-
}) {
|
|
32
|
-
const delay = delayMs ?? index * step
|
|
33
|
-
return (
|
|
34
|
-
<div className="hz-fade-up" style={{ animationDelay: `${delay}ms`, ...style }}>
|
|
35
|
-
{children}
|
|
36
|
-
</div>
|
|
37
|
-
)
|
|
38
|
-
}
|
package/src/product/Field.tsx
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Form field primitives — labeled rows over Hanzo GUI inputs.
|
|
5
|
-
*
|
|
6
|
-
* One way to render a labeled control. Every editor field goes through these, so
|
|
7
|
-
* spacing, disabled styling, and the label column stay consistent. Style props
|
|
8
|
-
* use the v5 shorthand set (p/px/items/justify/...).
|
|
9
|
-
*/
|
|
10
|
-
import type { ReactNode } from 'react'
|
|
11
|
-
import {
|
|
12
|
-
Input,
|
|
13
|
-
Label,
|
|
14
|
-
Select,
|
|
15
|
-
Switch,
|
|
16
|
-
TextArea,
|
|
17
|
-
Slider,
|
|
18
|
-
Text,
|
|
19
|
-
XStack,
|
|
20
|
-
YStack,
|
|
21
|
-
} from '@hanzo/gui'
|
|
22
|
-
import { ChevronDown } from '@hanzogui/lucide-icons-2'
|
|
23
|
-
|
|
24
|
-
/** Labeled row: fixed label column + flexing control. */
|
|
25
|
-
export function FieldRow({ label, children }: { label: string; children: ReactNode }) {
|
|
26
|
-
return (
|
|
27
|
-
<XStack gap="$3" items="flex-start" flexWrap="wrap">
|
|
28
|
-
<Label width={180} pt="$2" color="$color11" fontSize="$3">
|
|
29
|
-
{label}
|
|
30
|
-
</Label>
|
|
31
|
-
<YStack flex={1} minW={240}>
|
|
32
|
-
{children}
|
|
33
|
-
</YStack>
|
|
34
|
-
</XStack>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function FieldText({
|
|
39
|
-
value,
|
|
40
|
-
onChange,
|
|
41
|
-
disabled,
|
|
42
|
-
secure,
|
|
43
|
-
placeholder,
|
|
44
|
-
}: {
|
|
45
|
-
value: string
|
|
46
|
-
onChange: (v: string) => void
|
|
47
|
-
disabled?: boolean
|
|
48
|
-
secure?: boolean
|
|
49
|
-
placeholder?: string
|
|
50
|
-
}) {
|
|
51
|
-
return (
|
|
52
|
-
<Input
|
|
53
|
-
value={value}
|
|
54
|
-
onChangeText={onChange}
|
|
55
|
-
disabled={disabled}
|
|
56
|
-
secureTextEntry={secure}
|
|
57
|
-
placeholder={placeholder}
|
|
58
|
-
autoCapitalize="none"
|
|
59
|
-
/>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function FieldTextArea({
|
|
64
|
-
value,
|
|
65
|
-
onChange,
|
|
66
|
-
disabled,
|
|
67
|
-
rows = 6,
|
|
68
|
-
}: {
|
|
69
|
-
value: string
|
|
70
|
-
onChange: (v: string) => void
|
|
71
|
-
disabled?: boolean
|
|
72
|
-
rows?: number
|
|
73
|
-
}) {
|
|
74
|
-
return (
|
|
75
|
-
<TextArea value={value} onChangeText={onChange} disabled={disabled} numberOfLines={rows} />
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function FieldSwitch({
|
|
80
|
-
checked,
|
|
81
|
-
onChange,
|
|
82
|
-
disabled,
|
|
83
|
-
}: {
|
|
84
|
-
checked: boolean
|
|
85
|
-
onChange: (v: boolean) => void
|
|
86
|
-
disabled?: boolean
|
|
87
|
-
}) {
|
|
88
|
-
return (
|
|
89
|
-
<Switch checked={checked} onCheckedChange={onChange} disabled={disabled} size="$3">
|
|
90
|
-
<Switch.Thumb />
|
|
91
|
-
</Switch>
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function FieldSelect({
|
|
96
|
-
value,
|
|
97
|
-
options,
|
|
98
|
-
onChange,
|
|
99
|
-
disabled,
|
|
100
|
-
}: {
|
|
101
|
-
value: string
|
|
102
|
-
options: string[]
|
|
103
|
-
onChange: (v: string) => void
|
|
104
|
-
disabled?: boolean
|
|
105
|
-
}) {
|
|
106
|
-
return (
|
|
107
|
-
<Select value={value} onValueChange={onChange} disablePreventBodyScroll native>
|
|
108
|
-
<Select.Trigger disabled={disabled} iconAfter={<ChevronDown size={16} />}>
|
|
109
|
-
<Select.Value placeholder="Select…" />
|
|
110
|
-
</Select.Trigger>
|
|
111
|
-
<Select.Content>
|
|
112
|
-
<Select.Viewport>
|
|
113
|
-
{options.map((opt, i) => (
|
|
114
|
-
<Select.Item key={opt} index={i} value={opt}>
|
|
115
|
-
<Select.ItemText>{opt}</Select.ItemText>
|
|
116
|
-
</Select.Item>
|
|
117
|
-
))}
|
|
118
|
-
</Select.Viewport>
|
|
119
|
-
</Select.Content>
|
|
120
|
-
</Select>
|
|
121
|
-
)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function FieldSlider({
|
|
125
|
-
value,
|
|
126
|
-
min,
|
|
127
|
-
max,
|
|
128
|
-
step,
|
|
129
|
-
onChange,
|
|
130
|
-
disabled,
|
|
131
|
-
}: {
|
|
132
|
-
value: number
|
|
133
|
-
min: number
|
|
134
|
-
max: number
|
|
135
|
-
step: number
|
|
136
|
-
onChange: (v: number) => void
|
|
137
|
-
disabled?: boolean
|
|
138
|
-
}) {
|
|
139
|
-
return (
|
|
140
|
-
<XStack gap="$3" items="center">
|
|
141
|
-
<Text width={56} fontSize="$3" color="$color11">
|
|
142
|
-
{value}
|
|
143
|
-
</Text>
|
|
144
|
-
<Slider
|
|
145
|
-
flex={1}
|
|
146
|
-
min={min}
|
|
147
|
-
max={max}
|
|
148
|
-
step={step}
|
|
149
|
-
value={[value]}
|
|
150
|
-
onValueChange={(v) => onChange(v[0] ?? min)}
|
|
151
|
-
disabled={disabled}
|
|
152
|
-
>
|
|
153
|
-
<Slider.Track>
|
|
154
|
-
<Slider.TrackActive />
|
|
155
|
-
</Slider.Track>
|
|
156
|
-
<Slider.Thumb index={0} circular />
|
|
157
|
-
</Slider>
|
|
158
|
-
</XStack>
|
|
159
|
-
)
|
|
160
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The Hanzo "H" mark — the canonical 7-path shaded glyph: five body blocks +
|
|
5
|
-
* two shade slivers (geometry canon: @hanzo/logo `MARK_PATHS`).
|
|
6
|
-
*
|
|
7
|
-
* Rendered as inline SVG with `fill: currentColor` (shade at reduced opacity),
|
|
8
|
-
* so it inherits the surrounding text color and adapts to the dark/light theme
|
|
9
|
-
* with no per-theme asset. ONE source for the mark across the chrome.
|
|
10
|
-
*/
|
|
11
|
-
export function HanzoMark({ size = 22, color = 'currentColor' }: { size?: number; color?: string }) {
|
|
12
|
-
return (
|
|
13
|
-
<svg
|
|
14
|
-
width={size}
|
|
15
|
-
height={size}
|
|
16
|
-
viewBox="0 0 67 67"
|
|
17
|
-
role="img"
|
|
18
|
-
aria-label="Hanzo"
|
|
19
|
-
fill={color}
|
|
20
|
-
style={{ display: 'block', flexShrink: 0 }}
|
|
21
|
-
>
|
|
22
|
-
<path d="M22.21 67V44.6369H0V67H22.21Z" />
|
|
23
|
-
<path opacity={0.55} d="M0 44.6369L22.21 46.8285V44.6369H0Z" />
|
|
24
|
-
<path d="M66.7038 22.3184H22.2534L0.0878906 44.6367H44.4634L66.7038 22.3184Z" />
|
|
25
|
-
<path d="M22.21 0H0V22.3184H22.21V0Z" />
|
|
26
|
-
<path d="M66.7198 0H44.5098V22.3184H66.7198V0Z" />
|
|
27
|
-
<path opacity={0.55} d="M66.6753 22.3185L44.5098 20.0822V22.3185H66.6753Z" />
|
|
28
|
-
<path d="M66.7198 67V44.6369H44.5098V67H66.7198Z" />
|
|
29
|
-
</svg>
|
|
30
|
-
)
|
|
31
|
-
}
|