@zylem/ui 0.1.0 → 0.1.1
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/chunk-VGOOWBSO.js +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +75 -2
- package/dist/index.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.js +1 -1
- package/package.json +7 -4
- package/src/components/Accordion/Accordion.tsx +60 -0
- package/src/components/Badge/Badge.css.ts +52 -0
- package/src/components/Badge/Badge.tsx +23 -0
- package/src/components/Button/Button.css.ts +124 -0
- package/src/components/Button/Button.tsx +34 -0
- package/src/components/Card/Card.css.ts +62 -0
- package/src/components/Card/Card.tsx +54 -0
- package/src/{global/checkbox.css.ts → components/Checkbox/Checkbox.css.ts} +23 -23
- package/src/components/Checkbox/Checkbox.tsx +41 -0
- package/src/components/Console/Console.css.ts +65 -0
- package/src/components/Console/Console.tsx +51 -0
- package/src/components/Dialog/Dialog.css.ts +86 -0
- package/src/components/Dialog/Dialog.tsx +89 -0
- package/src/components/DropdownMenu/DropdownMenu.css.ts +76 -0
- package/src/components/DropdownMenu/DropdownMenu.tsx +63 -0
- package/src/components/EmptyState/EmptyState.css.ts +29 -0
- package/src/components/EmptyState/EmptyState.tsx +32 -0
- package/src/components/Kbd/Kbd.css.ts +27 -0
- package/src/components/Kbd/Kbd.tsx +17 -0
- package/src/components/NumberField/NumberField.css.ts +47 -0
- package/src/components/NumberField/NumberField.tsx +66 -0
- package/src/components/Panel/Panel.css.ts +88 -0
- package/src/components/Panel/Panel.tsx +66 -0
- package/src/components/Progress/Progress.css.ts +51 -0
- package/src/components/Progress/Progress.tsx +43 -0
- package/src/components/Property/Property.css.ts +70 -0
- package/src/components/Property/Property.tsx +118 -0
- package/src/components/ScrollArea/ScrollArea.tsx +41 -0
- package/src/components/SearchInput/SearchInput.css.ts +25 -0
- package/src/components/SearchInput/SearchInput.tsx +31 -0
- package/src/components/Select/Select.css.ts +93 -0
- package/src/components/Select/Select.tsx +68 -0
- package/src/components/Separator/Separator.css.ts +22 -0
- package/src/components/Separator/Separator.tsx +18 -0
- package/src/components/Sidebar/Sidebar.css.ts +79 -0
- package/src/components/Sidebar/Sidebar.tsx +69 -0
- package/src/components/Slider/Slider.css.ts +91 -0
- package/src/components/Slider/Slider.tsx +51 -0
- package/src/components/Switch/Switch.css.ts +72 -0
- package/src/components/Switch/Switch.tsx +36 -0
- package/src/components/Tabs/Tabs.css.ts +70 -0
- package/src/components/Tabs/Tabs.tsx +79 -0
- package/src/components/TextField/TextField.css.ts +16 -0
- package/src/components/TextField/TextField.tsx +76 -0
- package/src/components/TitleBar/TitleBar.css.ts +46 -0
- package/src/components/TitleBar/TitleBar.tsx +60 -0
- package/src/components/Toolbar/Toolbar.css.ts +29 -0
- package/src/components/Toolbar/Toolbar.tsx +30 -0
- package/src/components/ToolbarButton/ToolbarButton.css.ts +64 -0
- package/src/components/ToolbarButton/ToolbarButton.tsx +42 -0
- package/src/components/Tooltip/Tooltip.css.ts +32 -0
- package/src/components/Tooltip/Tooltip.tsx +27 -0
- package/src/components/WindowControls/WindowControls.css.ts +59 -0
- package/src/components/WindowControls/WindowControls.tsx +51 -0
- package/src/components/index.ts +67 -6
- package/src/components/shared/field.css.ts +60 -0
- package/src/global/accordion.css.ts +32 -18
- package/src/global/common.css.ts +14 -17
- package/src/global/detached-panel.css.ts +31 -8
- package/src/global/editor-base.css.ts +72 -119
- package/src/global/entities.css.ts +19 -15
- package/src/global/hyperglass-base.css.ts +91 -0
- package/src/global/menu.css.ts +8 -3
- package/src/sprinkles.css.ts +22 -0
- package/src/styles.ts +32 -4
- package/src/theme.css.ts +190 -99
- package/dist/chunk-3R5KFBTB.js +0 -1
- package/src/components/Button.tsx +0 -19
- package/src/global/console.css.ts +0 -43
- package/src/global/sidebar.css.ts +0 -18
- package/src/global/toolbar.css.ts +0 -62
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Show } from 'solid-js';
|
|
2
|
+
import type { JSX } from 'solid-js';
|
|
3
|
+
import { Button } from '../Button/Button';
|
|
4
|
+
|
|
5
|
+
export interface ConsoleProps {
|
|
6
|
+
/** Console text content. */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Editable textarea input handler; omit for read-only display. */
|
|
9
|
+
onInput?: (value: string) => void;
|
|
10
|
+
onClear?: () => void;
|
|
11
|
+
readOnly?: boolean;
|
|
12
|
+
class?: string;
|
|
13
|
+
/** Extra action buttons rendered next to Clear. */
|
|
14
|
+
actions?: JSX.Element;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* HyperGlass console: dark low-gloss terminal field with a floating Clear
|
|
19
|
+
* action.
|
|
20
|
+
*/
|
|
21
|
+
export function Console(props: ConsoleProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
class={
|
|
25
|
+
props.class
|
|
26
|
+
? `zylem-console-container ${props.class}`
|
|
27
|
+
: 'zylem-console-container'
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
<div class="zylem-console-wrapper">
|
|
31
|
+
<textarea
|
|
32
|
+
class="zylem-console zylem-scroll"
|
|
33
|
+
value={props.value}
|
|
34
|
+
spellcheck={false}
|
|
35
|
+
readOnly={props.readOnly || !props.onInput}
|
|
36
|
+
onInput={(event) => props.onInput?.(event.currentTarget.value)}
|
|
37
|
+
/>
|
|
38
|
+
<Show when={props.onClear || props.actions}>
|
|
39
|
+
<div class="zylem-console-actions">
|
|
40
|
+
{props.actions}
|
|
41
|
+
<Show when={props.onClear}>
|
|
42
|
+
<Button size="sm" variant="ghost" onClick={() => props.onClear?.()}>
|
|
43
|
+
Clear
|
|
44
|
+
</Button>
|
|
45
|
+
</Show>
|
|
46
|
+
</div>
|
|
47
|
+
</Show>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { globalStyle, keyframes } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
const overlayEnter = keyframes({
|
|
5
|
+
from: { opacity: 0 },
|
|
6
|
+
to: { opacity: 1 },
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const contentEnter = keyframes({
|
|
10
|
+
from: { opacity: 0, transform: 'translateY(8px) scale(0.98)' },
|
|
11
|
+
to: { opacity: 1, transform: 'translateY(0) scale(1)' },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
globalStyle('.zylem-dialog-overlay', {
|
|
15
|
+
position: 'fixed',
|
|
16
|
+
inset: 0,
|
|
17
|
+
zIndex: 10000,
|
|
18
|
+
background: 'rgba(5, 10, 18, 0.6)',
|
|
19
|
+
backdropFilter: 'blur(3px)',
|
|
20
|
+
animation: `${overlayEnter} 0.15s ${vars.motion.easeOut}`,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
globalStyle('.zylem-dialog-positioner', {
|
|
24
|
+
position: 'fixed',
|
|
25
|
+
inset: 0,
|
|
26
|
+
zIndex: 10001,
|
|
27
|
+
display: 'flex',
|
|
28
|
+
alignItems: 'center',
|
|
29
|
+
justifyContent: 'center',
|
|
30
|
+
padding: vars.spacing.lg,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
globalStyle('.zylem-dialog-content', {
|
|
34
|
+
width: '100%',
|
|
35
|
+
maxWidth: '440px',
|
|
36
|
+
borderRadius: vars.radii.window,
|
|
37
|
+
border: '1px solid rgba(146, 205, 255, 0.54)',
|
|
38
|
+
background: vars.material.glassPanelDark,
|
|
39
|
+
boxShadow: vars.effects.shadowPanel,
|
|
40
|
+
backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
|
|
41
|
+
overflow: 'hidden',
|
|
42
|
+
animation: `${contentEnter} 0.16s ${vars.motion.easeOut}`,
|
|
43
|
+
'@supports': {
|
|
44
|
+
'not (backdrop-filter: blur(1px))': {
|
|
45
|
+
background: vars.colors.surface,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
globalStyle('.zylem-dialog-header', {
|
|
51
|
+
minHeight: '40px',
|
|
52
|
+
display: 'flex',
|
|
53
|
+
alignItems: 'center',
|
|
54
|
+
justifyContent: 'space-between',
|
|
55
|
+
gap: vars.spacing.sm,
|
|
56
|
+
padding: `0 ${vars.spacing.md}`,
|
|
57
|
+
background: vars.material.glossyBar,
|
|
58
|
+
borderBottom: '1px solid rgba(5, 18, 32, 0.85)',
|
|
59
|
+
boxShadow:
|
|
60
|
+
'inset 0 1px 0 rgba(255,255,255,0.62), inset 0 -1px 0 rgba(255,255,255,0.08)',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
globalStyle('.zylem-dialog-title', {
|
|
64
|
+
margin: 0,
|
|
65
|
+
fontSize: '13px',
|
|
66
|
+
fontWeight: 700,
|
|
67
|
+
letterSpacing: '0.02em',
|
|
68
|
+
color: '#F4FAFF',
|
|
69
|
+
fontFamily: vars.typography.fontFamily,
|
|
70
|
+
textShadow: '0 1px 1px rgba(0,0,0,0.65)',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
globalStyle('.zylem-dialog-body', {
|
|
74
|
+
padding: vars.spacing.lg,
|
|
75
|
+
color: vars.colors.text,
|
|
76
|
+
fontFamily: vars.typography.fontFamily,
|
|
77
|
+
fontSize: vars.typography.fontSize,
|
|
78
|
+
lineHeight: 1.45,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
globalStyle('.zylem-dialog-footer', {
|
|
82
|
+
display: 'flex',
|
|
83
|
+
justifyContent: 'flex-end',
|
|
84
|
+
gap: vars.spacing.sm,
|
|
85
|
+
padding: `0 ${vars.spacing.lg} ${vars.spacing.lg}`,
|
|
86
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Dialog as KDialog } from '@kobalte/core';
|
|
2
|
+
import { Show } from 'solid-js';
|
|
3
|
+
import type { JSX } from 'solid-js';
|
|
4
|
+
import { Button } from '../Button/Button';
|
|
5
|
+
import { WindowControls } from '../WindowControls/WindowControls';
|
|
6
|
+
|
|
7
|
+
export interface DialogProps {
|
|
8
|
+
open?: boolean;
|
|
9
|
+
onOpenChange?: (open: boolean) => void;
|
|
10
|
+
title?: JSX.Element;
|
|
11
|
+
children: JSX.Element;
|
|
12
|
+
/** Optional footer content (e.g. action buttons). */
|
|
13
|
+
footer?: JSX.Element;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* HyperGlass dialog: glass window with a glossy title bar and jewel close
|
|
18
|
+
* control, centered over a dimmed backdrop.
|
|
19
|
+
*/
|
|
20
|
+
export function Dialog(props: DialogProps) {
|
|
21
|
+
return (
|
|
22
|
+
<KDialog.Root open={props.open} onOpenChange={props.onOpenChange}>
|
|
23
|
+
<KDialog.Portal>
|
|
24
|
+
<KDialog.Overlay class="zylem-dialog-overlay" />
|
|
25
|
+
<div class="zylem-dialog-positioner">
|
|
26
|
+
<KDialog.Content class="zylem-dialog-content">
|
|
27
|
+
<div class="zylem-dialog-header">
|
|
28
|
+
<Show when={props.title}>
|
|
29
|
+
<KDialog.Title class="zylem-dialog-title">
|
|
30
|
+
{props.title}
|
|
31
|
+
</KDialog.Title>
|
|
32
|
+
</Show>
|
|
33
|
+
<WindowControls onClose={() => props.onOpenChange?.(false)} />
|
|
34
|
+
</div>
|
|
35
|
+
<KDialog.Description as="div" class="zylem-dialog-body">
|
|
36
|
+
{props.children}
|
|
37
|
+
</KDialog.Description>
|
|
38
|
+
<Show when={props.footer}>
|
|
39
|
+
<div class="zylem-dialog-footer">{props.footer}</div>
|
|
40
|
+
</Show>
|
|
41
|
+
</KDialog.Content>
|
|
42
|
+
</div>
|
|
43
|
+
</KDialog.Portal>
|
|
44
|
+
</KDialog.Root>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ConfirmDialogProps {
|
|
49
|
+
open: boolean;
|
|
50
|
+
onOpenChange: (open: boolean) => void;
|
|
51
|
+
title?: JSX.Element;
|
|
52
|
+
message: JSX.Element;
|
|
53
|
+
confirmLabel?: string;
|
|
54
|
+
cancelLabel?: string;
|
|
55
|
+
danger?: boolean;
|
|
56
|
+
onConfirm: () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Confirmation dialog built on Dialog — a drop-in replacement for
|
|
61
|
+
* `window.confirm()` flows.
|
|
62
|
+
*/
|
|
63
|
+
export function ConfirmDialog(props: ConfirmDialogProps) {
|
|
64
|
+
return (
|
|
65
|
+
<Dialog
|
|
66
|
+
open={props.open}
|
|
67
|
+
onOpenChange={props.onOpenChange}
|
|
68
|
+
title={props.title ?? 'Confirm'}
|
|
69
|
+
footer={
|
|
70
|
+
<>
|
|
71
|
+
<Button variant="ghost" onClick={() => props.onOpenChange(false)}>
|
|
72
|
+
{props.cancelLabel ?? 'Cancel'}
|
|
73
|
+
</Button>
|
|
74
|
+
<Button
|
|
75
|
+
variant={props.danger ? 'danger' : 'primary'}
|
|
76
|
+
onClick={() => {
|
|
77
|
+
props.onConfirm();
|
|
78
|
+
props.onOpenChange(false);
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{props.confirmLabel ?? 'Confirm'}
|
|
82
|
+
</Button>
|
|
83
|
+
</>
|
|
84
|
+
}
|
|
85
|
+
>
|
|
86
|
+
{props.message}
|
|
87
|
+
</Dialog>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { globalStyle, keyframes } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
const enter = keyframes({
|
|
5
|
+
from: { opacity: 0, transform: 'translateY(-4px)' },
|
|
6
|
+
to: { opacity: 1, transform: 'translateY(0)' },
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
globalStyle('.zylem-dropdown-content', {
|
|
10
|
+
zIndex: 10000,
|
|
11
|
+
minWidth: '180px',
|
|
12
|
+
padding: vars.spacing.xs,
|
|
13
|
+
borderRadius: vars.radii.control,
|
|
14
|
+
border: '1px solid rgba(97, 166, 232, 0.45)',
|
|
15
|
+
background: vars.material.glassPanelDark,
|
|
16
|
+
boxShadow: vars.effects.shadowPanel,
|
|
17
|
+
backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
|
|
18
|
+
outline: 'none',
|
|
19
|
+
'@supports': {
|
|
20
|
+
'not (backdrop-filter: blur(1px))': {
|
|
21
|
+
background: vars.colors.surface,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
globalStyle('.zylem-dropdown-content[data-expanded]', {
|
|
27
|
+
animation: `${enter} 0.12s ${vars.motion.easeOut}`,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
globalStyle('.zylem-dropdown-item', {
|
|
31
|
+
display: 'flex',
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
justifyContent: 'space-between',
|
|
34
|
+
gap: vars.spacing.md,
|
|
35
|
+
padding: `${vars.spacing.xs} ${vars.spacing.sm}`,
|
|
36
|
+
borderRadius: '4px',
|
|
37
|
+
color: vars.colors.text,
|
|
38
|
+
fontFamily: vars.typography.fontFamily,
|
|
39
|
+
fontSize: vars.typography.fontSize,
|
|
40
|
+
cursor: 'pointer',
|
|
41
|
+
userSelect: 'none',
|
|
42
|
+
outline: 'none',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
globalStyle('.zylem-dropdown-item[data-highlighted]', {
|
|
46
|
+
background: 'rgba(97, 166, 232, 0.22)',
|
|
47
|
+
color: '#F4FAFF',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
globalStyle('.zylem-dropdown-item[data-disabled]', {
|
|
51
|
+
opacity: 0.45,
|
|
52
|
+
cursor: 'not-allowed',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
globalStyle('.zylem-dropdown-item--danger', {
|
|
56
|
+
color: '#FF9C8F',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
globalStyle('.zylem-dropdown-item--danger[data-highlighted]', {
|
|
60
|
+
background: 'rgba(230, 69, 52, 0.25)',
|
|
61
|
+
color: '#FFD9D3',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
globalStyle('.zylem-dropdown-shortcut', {
|
|
65
|
+
fontSize: `calc(${vars.typography.fontSize} - 3px)`,
|
|
66
|
+
color: vars.colors.textSecondary,
|
|
67
|
+
letterSpacing: '0.06em',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
globalStyle('.zylem-dropdown-separator', {
|
|
71
|
+
height: '1px',
|
|
72
|
+
border: 'none',
|
|
73
|
+
margin: `${vars.spacing.xs} ${vars.spacing.sm}`,
|
|
74
|
+
background:
|
|
75
|
+
'linear-gradient(90deg, transparent, rgba(97, 166, 232, 0.35), transparent)',
|
|
76
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DropdownMenu as KDropdownMenu } from '@kobalte/core';
|
|
2
|
+
import { For, Show } from 'solid-js';
|
|
3
|
+
import type { JSX } from 'solid-js';
|
|
4
|
+
|
|
5
|
+
export interface DropdownMenuItemConfig {
|
|
6
|
+
id: string;
|
|
7
|
+
label: JSX.Element;
|
|
8
|
+
onSelect?: () => void;
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
danger?: boolean;
|
|
12
|
+
/** Render a separator line above this item. */
|
|
13
|
+
separatorAbove?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DropdownMenuProps {
|
|
17
|
+
/** Trigger element; rendered inside a Kobalte trigger button. */
|
|
18
|
+
trigger: JSX.Element;
|
|
19
|
+
items: DropdownMenuItemConfig[];
|
|
20
|
+
placement?: 'bottom-start' | 'bottom-end' | 'bottom' | 'top-start' | 'top-end' | 'top' | 'right-start' | 'left-start';
|
|
21
|
+
/** Class applied to the trigger button. */
|
|
22
|
+
triggerClass?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* HyperGlass dropdown menu: floating glass sheet with highlight rows.
|
|
27
|
+
*/
|
|
28
|
+
export function DropdownMenu(props: DropdownMenuProps) {
|
|
29
|
+
return (
|
|
30
|
+
<KDropdownMenu.Root placement={props.placement ?? 'bottom-start'}>
|
|
31
|
+
<KDropdownMenu.Trigger class={props.triggerClass}>
|
|
32
|
+
{props.trigger}
|
|
33
|
+
</KDropdownMenu.Trigger>
|
|
34
|
+
<KDropdownMenu.Portal>
|
|
35
|
+
<KDropdownMenu.Content class="zylem-dropdown-content">
|
|
36
|
+
<For each={props.items}>
|
|
37
|
+
{(item) => (
|
|
38
|
+
<>
|
|
39
|
+
<Show when={item.separatorAbove}>
|
|
40
|
+
<KDropdownMenu.Separator class="zylem-dropdown-separator" />
|
|
41
|
+
</Show>
|
|
42
|
+
<KDropdownMenu.Item
|
|
43
|
+
class={
|
|
44
|
+
item.danger
|
|
45
|
+
? 'zylem-dropdown-item zylem-dropdown-item--danger'
|
|
46
|
+
: 'zylem-dropdown-item'
|
|
47
|
+
}
|
|
48
|
+
disabled={item.disabled}
|
|
49
|
+
onSelect={item.onSelect}
|
|
50
|
+
>
|
|
51
|
+
<span>{item.label}</span>
|
|
52
|
+
<Show when={item.shortcut}>
|
|
53
|
+
<span class="zylem-dropdown-shortcut">{item.shortcut}</span>
|
|
54
|
+
</Show>
|
|
55
|
+
</KDropdownMenu.Item>
|
|
56
|
+
</>
|
|
57
|
+
)}
|
|
58
|
+
</For>
|
|
59
|
+
</KDropdownMenu.Content>
|
|
60
|
+
</KDropdownMenu.Portal>
|
|
61
|
+
</KDropdownMenu.Root>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
globalStyle('.zylem-empty-state', {
|
|
5
|
+
display: 'flex',
|
|
6
|
+
flexDirection: 'column',
|
|
7
|
+
alignItems: 'center',
|
|
8
|
+
justifyContent: 'center',
|
|
9
|
+
gap: vars.spacing.sm,
|
|
10
|
+
padding: vars.spacing.xl,
|
|
11
|
+
textAlign: 'center',
|
|
12
|
+
borderRadius: vars.radii.card,
|
|
13
|
+
border: '1px dashed rgba(97, 166, 232, 0.3)',
|
|
14
|
+
background: 'rgba(8, 19, 31, 0.3)',
|
|
15
|
+
color: vars.colors.textSecondary,
|
|
16
|
+
fontFamily: vars.typography.fontFamily,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
globalStyle('.zylem-empty-state-title', {
|
|
20
|
+
fontSize: vars.typography.fontSize,
|
|
21
|
+
fontWeight: 600,
|
|
22
|
+
color: vars.colors.text,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
globalStyle('.zylem-empty-state-message', {
|
|
26
|
+
fontSize: `calc(${vars.typography.fontSize} - 1px)`,
|
|
27
|
+
lineHeight: 1.45,
|
|
28
|
+
maxWidth: '360px',
|
|
29
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Show } from 'solid-js';
|
|
2
|
+
import type { JSX } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface EmptyStateProps {
|
|
5
|
+
title?: JSX.Element;
|
|
6
|
+
children?: JSX.Element;
|
|
7
|
+
/** Optional action (e.g. a Button). */
|
|
8
|
+
action?: JSX.Element;
|
|
9
|
+
class?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* HyperGlass empty state: dashed glass placeholder card for empty lists and
|
|
14
|
+
* unbuilt modes.
|
|
15
|
+
*/
|
|
16
|
+
export function EmptyState(props: EmptyStateProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
class={
|
|
20
|
+
props.class ? `zylem-empty-state ${props.class}` : 'zylem-empty-state'
|
|
21
|
+
}
|
|
22
|
+
>
|
|
23
|
+
<Show when={props.title}>
|
|
24
|
+
<div class="zylem-empty-state-title">{props.title}</div>
|
|
25
|
+
</Show>
|
|
26
|
+
<Show when={props.children}>
|
|
27
|
+
<div class="zylem-empty-state-message">{props.children}</div>
|
|
28
|
+
</Show>
|
|
29
|
+
{props.action}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Keyboard hint chip: tiny beveled glass key cap.
|
|
6
|
+
*/
|
|
7
|
+
globalStyle('.zylem-kbd', {
|
|
8
|
+
display: 'inline-flex',
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
justifyContent: 'center',
|
|
11
|
+
minWidth: '18px',
|
|
12
|
+
padding: `1px ${vars.spacing.xs}`,
|
|
13
|
+
borderRadius: '4px',
|
|
14
|
+
border: '1px solid rgba(97, 166, 232, 0.4)',
|
|
15
|
+
background:
|
|
16
|
+
'linear-gradient(180deg, rgba(60, 85, 115, 0.7), rgba(20, 32, 48, 0.85))',
|
|
17
|
+
boxShadow:
|
|
18
|
+
'inset 0 1px 0 rgba(255,255,255,0.28), inset 0 -1px 0 rgba(0,0,0,0.45), 0 1px 2px rgba(0,0,0,0.4)',
|
|
19
|
+
color: vars.colors.text,
|
|
20
|
+
fontFamily: vars.typography.fontFamily,
|
|
21
|
+
fontSize: '10px',
|
|
22
|
+
fontWeight: 700,
|
|
23
|
+
letterSpacing: '0.04em',
|
|
24
|
+
textTransform: 'uppercase',
|
|
25
|
+
userSelect: 'none',
|
|
26
|
+
whiteSpace: 'nowrap',
|
|
27
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { JSX } from 'solid-js';
|
|
2
|
+
|
|
3
|
+
export interface KbdProps {
|
|
4
|
+
children: JSX.Element;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* HyperGlass keyboard hint: tiny beveled glass key cap for shortcut hints.
|
|
10
|
+
*/
|
|
11
|
+
export function Kbd(props: KbdProps) {
|
|
12
|
+
return (
|
|
13
|
+
<kbd class={props.class ? `zylem-kbd ${props.class}` : 'zylem-kbd'}>
|
|
14
|
+
{props.children}
|
|
15
|
+
</kbd>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
import '../shared/field.css';
|
|
4
|
+
|
|
5
|
+
globalStyle('.zylem-numberfield-group', {
|
|
6
|
+
display: 'inline-flex',
|
|
7
|
+
alignItems: 'stretch',
|
|
8
|
+
position: 'relative',
|
|
9
|
+
width: '100%',
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
globalStyle('.zylem-numberfield-input', {
|
|
13
|
+
width: '100%',
|
|
14
|
+
height: '28px',
|
|
15
|
+
paddingRight: '26px',
|
|
16
|
+
fontVariantNumeric: 'tabular-nums',
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
globalStyle('.zylem-numberfield-stepper', {
|
|
20
|
+
position: 'absolute',
|
|
21
|
+
right: '3px',
|
|
22
|
+
width: '20px',
|
|
23
|
+
height: '11px',
|
|
24
|
+
display: 'flex',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
cursor: 'pointer',
|
|
28
|
+
border: '1px solid rgba(150, 210, 255, 0.4)',
|
|
29
|
+
borderRadius: '4px',
|
|
30
|
+
background: vars.material.buttonGlass,
|
|
31
|
+
color: '#F4FAFF',
|
|
32
|
+
fontSize: '8px',
|
|
33
|
+
lineHeight: 1,
|
|
34
|
+
padding: 0,
|
|
35
|
+
transition: `filter ${vars.motion.fast} ${vars.motion.easeOut}`,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
globalStyle('.zylem-numberfield-stepper:hover', {
|
|
39
|
+
filter: 'brightness(1.25)',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
globalStyle('.zylem-numberfield-stepper:active', {
|
|
43
|
+
filter: 'brightness(0.85)',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
globalStyle('.zylem-numberfield-stepper--up', { top: '3px' });
|
|
47
|
+
globalStyle('.zylem-numberfield-stepper--down', { bottom: '3px' });
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NumberField as KNumberField } from '@kobalte/core';
|
|
2
|
+
import { Show } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
export interface NumberFieldProps {
|
|
5
|
+
label?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
value?: number;
|
|
8
|
+
onChange?: (value: number) => void;
|
|
9
|
+
minValue?: number;
|
|
10
|
+
maxValue?: number;
|
|
11
|
+
step?: number;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
class?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* HyperGlass number field: inset glass input with square jewel steppers.
|
|
20
|
+
*/
|
|
21
|
+
export function NumberField(props: NumberFieldProps) {
|
|
22
|
+
return (
|
|
23
|
+
<KNumberField.Root
|
|
24
|
+
class={props.class ? `zylem-field-root ${props.class}` : 'zylem-field-root'}
|
|
25
|
+
rawValue={props.value}
|
|
26
|
+
onRawValueChange={(value) => {
|
|
27
|
+
if (props.onChange && !Number.isNaN(value)) props.onChange(value);
|
|
28
|
+
}}
|
|
29
|
+
minValue={props.minValue}
|
|
30
|
+
maxValue={props.maxValue}
|
|
31
|
+
step={props.step}
|
|
32
|
+
disabled={props.disabled}
|
|
33
|
+
name={props.name}
|
|
34
|
+
validationState={props.error ? 'invalid' : 'valid'}
|
|
35
|
+
>
|
|
36
|
+
<Show when={props.label}>
|
|
37
|
+
<KNumberField.Label class="zylem-field-label">
|
|
38
|
+
{props.label}
|
|
39
|
+
</KNumberField.Label>
|
|
40
|
+
</Show>
|
|
41
|
+
<div class="zylem-numberfield-group">
|
|
42
|
+
<KNumberField.Input
|
|
43
|
+
class="zylem-field zylem-numberfield-input"
|
|
44
|
+
placeholder={props.placeholder}
|
|
45
|
+
/>
|
|
46
|
+
<KNumberField.IncrementTrigger
|
|
47
|
+
class="zylem-numberfield-stepper zylem-numberfield-stepper--up"
|
|
48
|
+
aria-label="Increment"
|
|
49
|
+
>
|
|
50
|
+
▲
|
|
51
|
+
</KNumberField.IncrementTrigger>
|
|
52
|
+
<KNumberField.DecrementTrigger
|
|
53
|
+
class="zylem-numberfield-stepper zylem-numberfield-stepper--down"
|
|
54
|
+
aria-label="Decrement"
|
|
55
|
+
>
|
|
56
|
+
▼
|
|
57
|
+
</KNumberField.DecrementTrigger>
|
|
58
|
+
</div>
|
|
59
|
+
<Show when={props.error}>
|
|
60
|
+
<KNumberField.ErrorMessage class="zylem-field-error">
|
|
61
|
+
{props.error}
|
|
62
|
+
</KNumberField.ErrorMessage>
|
|
63
|
+
</Show>
|
|
64
|
+
</KNumberField.Root>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { globalStyle } from '@vanilla-extract/css';
|
|
2
|
+
import { vars } from '../../theme.css';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Glass card: transparent panel with 1px electric-blue border, inner
|
|
6
|
+
* highlight, subtle blur, and rounded panel corners.
|
|
7
|
+
*/
|
|
8
|
+
globalStyle('.zylem-panel', {
|
|
9
|
+
boxSizing: 'border-box',
|
|
10
|
+
display: 'flex',
|
|
11
|
+
flexDirection: 'column',
|
|
12
|
+
minHeight: 0,
|
|
13
|
+
borderRadius: vars.radii.panel,
|
|
14
|
+
border: '1px solid rgba(97, 166, 232, 0.38)',
|
|
15
|
+
background: vars.material.glassPanelDark,
|
|
16
|
+
boxShadow:
|
|
17
|
+
'0 16px 36px rgba(0,0,0,0.36), inset 0 1px 0 rgba(255,255,255,0.09)',
|
|
18
|
+
backdropFilter: `blur(${vars.effects.blurSm}) saturate(1.14)`,
|
|
19
|
+
overflow: 'hidden',
|
|
20
|
+
'@supports': {
|
|
21
|
+
'not (backdrop-filter: blur(1px))': {
|
|
22
|
+
background: vars.colors.surface,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Borderless variant: drops the outline, outer shadow, and background so a
|
|
29
|
+
* panel can sit flush inside an already-outlined region (fewer outlines).
|
|
30
|
+
*/
|
|
31
|
+
globalStyle('.zylem-panel--borderless', {
|
|
32
|
+
border: 'none',
|
|
33
|
+
borderRadius: 0,
|
|
34
|
+
background: 'transparent',
|
|
35
|
+
boxShadow: 'none',
|
|
36
|
+
backdropFilter: 'none',
|
|
37
|
+
'@supports': {
|
|
38
|
+
'not (backdrop-filter: blur(1px))': {
|
|
39
|
+
background: 'transparent',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** Brighter blue-glass variant for hero/window surfaces. */
|
|
45
|
+
globalStyle('.zylem-panel--window', {
|
|
46
|
+
borderRadius: vars.radii.window,
|
|
47
|
+
border: '1px solid rgba(146, 205, 255, 0.54)',
|
|
48
|
+
boxShadow: vars.effects.shadowPanel,
|
|
49
|
+
backdropFilter: `blur(${vars.effects.blurMd}) saturate(1.22)`,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/** Aqua-inspired glossy header strip for panels. */
|
|
53
|
+
globalStyle('.zylem-panel-header', {
|
|
54
|
+
boxSizing: 'border-box',
|
|
55
|
+
minHeight: '32px',
|
|
56
|
+
display: 'flex',
|
|
57
|
+
alignItems: 'center',
|
|
58
|
+
justifyContent: 'space-between',
|
|
59
|
+
gap: vars.spacing.sm,
|
|
60
|
+
padding: `0 ${vars.spacing.md}`,
|
|
61
|
+
borderBottom: '1px solid rgba(97, 166, 232, 0.22)',
|
|
62
|
+
background: vars.material.panelHeaderGloss,
|
|
63
|
+
boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.15)',
|
|
64
|
+
userSelect: 'none',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
globalStyle('.zylem-panel-header-title', {
|
|
68
|
+
fontSize: '11px',
|
|
69
|
+
fontWeight: 700,
|
|
70
|
+
letterSpacing: '0.09em',
|
|
71
|
+
textTransform: 'uppercase',
|
|
72
|
+
color: vars.colors.text,
|
|
73
|
+
fontFamily: vars.typography.fontFamily,
|
|
74
|
+
textShadow: '0 1px 1px rgba(0,0,0,0.55)',
|
|
75
|
+
overflow: 'hidden',
|
|
76
|
+
textOverflow: 'ellipsis',
|
|
77
|
+
whiteSpace: 'nowrap',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
globalStyle('.zylem-panel-body', {
|
|
81
|
+
flex: 1,
|
|
82
|
+
minHeight: 0,
|
|
83
|
+
padding: vars.spacing.md,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
globalStyle('.zylem-panel-body--flush', {
|
|
87
|
+
padding: 0,
|
|
88
|
+
});
|