@mystravil/hardpoint 0.0.0-stage → 0.2.0
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/CHANGELOG.md +38 -0
- package/LICENSE +25 -0
- package/README.md +64 -3
- package/dist/base.css +625 -0
- package/dist/components/AppShell.svelte +698 -0
- package/dist/components/AppShell.svelte.d.ts +77 -0
- package/dist/components/Button.svelte +174 -0
- package/dist/components/Button.svelte.d.ts +20 -0
- package/dist/components/Checkbox.svelte +235 -0
- package/dist/components/Checkbox.svelte.d.ts +23 -0
- package/dist/components/CheckboxGroup.svelte +207 -0
- package/dist/components/CheckboxGroup.svelte.d.ts +44 -0
- package/dist/components/Combobox.svelte +901 -0
- package/dist/components/Combobox.svelte.d.ts +72 -0
- package/dist/components/Dialog.svelte +359 -0
- package/dist/components/Dialog.svelte.d.ts +43 -0
- package/dist/components/Disclosure.svelte +201 -0
- package/dist/components/Disclosure.svelte.d.ts +27 -0
- package/dist/components/EmptyState.svelte +88 -0
- package/dist/components/EmptyState.svelte.d.ts +22 -0
- package/dist/components/ErrorState.svelte +135 -0
- package/dist/components/ErrorState.svelte.d.ts +26 -0
- package/dist/components/ImageViewer.svelte +764 -0
- package/dist/components/ImageViewer.svelte.d.ts +55 -0
- package/dist/components/KeyValueList.svelte +114 -0
- package/dist/components/KeyValueList.svelte.d.ts +43 -0
- package/dist/components/ListDetail.svelte +218 -0
- package/dist/components/ListDetail.svelte.d.ts +37 -0
- package/dist/components/LoadRegion.svelte +219 -0
- package/dist/components/LoadRegion.svelte.d.ts +27 -0
- package/dist/components/MediaFrame.svelte +110 -0
- package/dist/components/MediaFrame.svelte.d.ts +20 -0
- package/dist/components/MediaImage.svelte +256 -0
- package/dist/components/MediaImage.svelte.d.ts +16 -0
- package/dist/components/Menu.svelte +258 -0
- package/dist/components/Menu.svelte.d.ts +36 -0
- package/dist/components/MenuCheckboxItem.svelte +119 -0
- package/dist/components/MenuCheckboxItem.svelte.d.ts +15 -0
- package/dist/components/MenuGroup.svelte +50 -0
- package/dist/components/MenuGroup.svelte.d.ts +15 -0
- package/dist/components/MenuItem.svelte +94 -0
- package/dist/components/MenuItem.svelte.d.ts +19 -0
- package/dist/components/MenuRadioGroup.svelte +62 -0
- package/dist/components/MenuRadioGroup.svelte.d.ts +20 -0
- package/dist/components/MenuRadioItem.svelte +110 -0
- package/dist/components/MenuRadioItem.svelte.d.ts +17 -0
- package/dist/components/MenuSeparator.svelte +28 -0
- package/dist/components/MenuSeparator.svelte.d.ts +6 -0
- package/dist/components/Meter.svelte +283 -0
- package/dist/components/Meter.svelte.d.ts +66 -0
- package/dist/components/NativeSelect.svelte +135 -0
- package/dist/components/NativeSelect.svelte.d.ts +52 -0
- package/dist/components/Notice.svelte +262 -0
- package/dist/components/Notice.svelte.d.ts +30 -0
- package/dist/components/Pagination.svelte +132 -0
- package/dist/components/Pagination.svelte.d.ts +18 -0
- package/dist/components/Popover.svelte +222 -0
- package/dist/components/Popover.svelte.d.ts +35 -0
- package/dist/components/Progress.svelte +157 -0
- package/dist/components/Progress.svelte.d.ts +34 -0
- package/dist/components/RadioGroup.svelte +440 -0
- package/dist/components/RadioGroup.svelte.d.ts +50 -0
- package/dist/components/Select.svelte +471 -0
- package/dist/components/Select.svelte.d.ts +48 -0
- package/dist/components/Skeleton.svelte +149 -0
- package/dist/components/Skeleton.svelte.d.ts +24 -0
- package/dist/components/Spinner.svelte +118 -0
- package/dist/components/Spinner.svelte.d.ts +13 -0
- package/dist/components/Stat.svelte +253 -0
- package/dist/components/Stat.svelte.d.ts +46 -0
- package/dist/components/Steps.svelte +189 -0
- package/dist/components/Steps.svelte.d.ts +31 -0
- package/dist/components/Switch.svelte +222 -0
- package/dist/components/Switch.svelte.d.ts +18 -0
- package/dist/components/Table.svelte +504 -0
- package/dist/components/Table.svelte.d.ts +92 -0
- package/dist/components/Tabs.svelte +246 -0
- package/dist/components/Tabs.svelte.d.ts +44 -0
- package/dist/components/Tag.svelte +40 -0
- package/dist/components/Tag.svelte.d.ts +15 -0
- package/dist/components/TextArea.svelte +272 -0
- package/dist/components/TextArea.svelte.d.ts +28 -0
- package/dist/components/TextField.svelte +256 -0
- package/dist/components/TextField.svelte.d.ts +32 -0
- package/dist/components/Timeline.svelte +156 -0
- package/dist/components/Timeline.svelte.d.ts +30 -0
- package/dist/components/Toaster.svelte +411 -0
- package/dist/components/Toaster.svelte.d.ts +11 -0
- package/dist/components/Tooltip.svelte +200 -0
- package/dist/components/Tooltip.svelte.d.ts +38 -0
- package/dist/components/TooltipGroup.svelte +46 -0
- package/dist/components/TooltipGroup.svelte.d.ts +29 -0
- package/dist/components/internal/Scrim.svelte +52 -0
- package/dist/components/internal/Scrim.svelte.d.ts +15 -0
- package/dist/components/internal/Sheet.svelte +263 -0
- package/dist/components/internal/Sheet.svelte.d.ts +36 -0
- package/dist/components/internal/fade-in.d.ts +10 -0
- package/dist/components/internal/fade-in.js +20 -0
- package/dist/components/internal/groups.d.ts +14 -0
- package/dist/components/internal/groups.js +23 -0
- package/dist/components/internal/resolve.d.ts +8 -0
- package/dist/components/internal/resolve.js +247 -0
- package/dist/components/internal/swipe-dismiss.d.ts +47 -0
- package/dist/components/internal/swipe-dismiss.js +220 -0
- package/dist/components/internal/visual-viewport.svelte.d.ts +35 -0
- package/dist/components/internal/visual-viewport.svelte.js +79 -0
- package/dist/components/toast.svelte.d.ts +57 -0
- package/dist/components/toast.svelte.js +84 -0
- package/dist/fonts/OFL-geist-pixel.txt +92 -0
- package/dist/fonts/OFL.txt +93 -0
- package/dist/fonts/geist-latin-variable.woff2 +0 -0
- package/dist/fonts/geist-mono-latin-variable.woff2 +0 -0
- package/dist/fonts/geist-pixel-square.woff2 +0 -0
- package/dist/fonts.css +71 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +45 -0
- package/dist/motion/Motion.svelte +15 -0
- package/dist/motion/Motion.svelte.d.ts +9 -0
- package/dist/motion/context.d.ts +18 -0
- package/dist/motion/context.js +26 -0
- package/dist/motion/index.d.ts +3 -0
- package/dist/motion/index.js +3 -0
- package/dist/motion/transitions.d.ts +31 -0
- package/dist/motion/transitions.js +112 -0
- package/dist/tokens.css +283 -0
- package/package.json +76 -6
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { prefersReducedMotion } from 'svelte/motion';
|
|
2
|
+
/** A duration token on the element, such as `--dur-pop`, in milliseconds. */
|
|
3
|
+
export function duration(node, name) {
|
|
4
|
+
const value = getComputedStyle(node).getPropertyValue(name).trim();
|
|
5
|
+
const n = parseFloat(value);
|
|
6
|
+
if (Number.isNaN(n))
|
|
7
|
+
return 0;
|
|
8
|
+
return value.endsWith('ms') ? n : value.endsWith('s') ? n * 1000 : n;
|
|
9
|
+
}
|
|
10
|
+
const curves = new Map();
|
|
11
|
+
/** A `cubic-bezier()` token on the element, such as `--settle`, as an easing function. */
|
|
12
|
+
export function curve(node, name = '--settle') {
|
|
13
|
+
const value = getComputedStyle(node).getPropertyValue(name).trim();
|
|
14
|
+
let fn = curves.get(value);
|
|
15
|
+
if (!fn) {
|
|
16
|
+
const m = value.match(/cubic-bezier\(([^)]+)\)/);
|
|
17
|
+
const [x1, y1, x2, y2] = m ? m[1].split(',').map(Number) : [0.2, 0.7, 0.2, 1];
|
|
18
|
+
fn = bezier(x1, y1, x2, y2);
|
|
19
|
+
curves.set(value, fn);
|
|
20
|
+
}
|
|
21
|
+
return fn;
|
|
22
|
+
}
|
|
23
|
+
/** CSS cubic-bezier timing as a function of progress, solved for x by Newton steps, then bisection. */
|
|
24
|
+
function bezier(x1, y1, x2, y2) {
|
|
25
|
+
const cx = 3 * x1;
|
|
26
|
+
const bx = 3 * (x2 - x1) - cx;
|
|
27
|
+
const ax = 1 - cx - bx;
|
|
28
|
+
const cy = 3 * y1;
|
|
29
|
+
const by = 3 * (y2 - y1) - cy;
|
|
30
|
+
const ay = 1 - cy - by;
|
|
31
|
+
const sampleX = (t) => ((ax * t + bx) * t + cx) * t;
|
|
32
|
+
const sampleY = (t) => ((ay * t + by) * t + cy) * t;
|
|
33
|
+
const slopeX = (t) => (3 * ax * t + 2 * bx) * t + cx;
|
|
34
|
+
return (x) => {
|
|
35
|
+
if (x <= 0)
|
|
36
|
+
return 0;
|
|
37
|
+
if (x >= 1)
|
|
38
|
+
return 1;
|
|
39
|
+
let t = x;
|
|
40
|
+
for (let i = 0; i < 8; i++) {
|
|
41
|
+
const err = sampleX(t) - x;
|
|
42
|
+
if (Math.abs(err) < 1e-6)
|
|
43
|
+
return sampleY(t);
|
|
44
|
+
const d = slopeX(t);
|
|
45
|
+
if (Math.abs(d) < 1e-6)
|
|
46
|
+
break;
|
|
47
|
+
t -= err / d;
|
|
48
|
+
}
|
|
49
|
+
let lo = 0;
|
|
50
|
+
let hi = 1;
|
|
51
|
+
t = x;
|
|
52
|
+
while (hi - lo > 1e-6) {
|
|
53
|
+
if (sampleX(t) < x)
|
|
54
|
+
lo = t;
|
|
55
|
+
else
|
|
56
|
+
hi = t;
|
|
57
|
+
t = (lo + hi) / 2;
|
|
58
|
+
}
|
|
59
|
+
return sampleY(t);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Menus, popovers, select lists and tooltips: fade with a 4px move away from
|
|
64
|
+
* the trigger, `--dur-pop` in and `--dur-pop-exit` out. Reads Bits UI's
|
|
65
|
+
* `data-side` to move the right way. Reduced motion: fade only.
|
|
66
|
+
*/
|
|
67
|
+
export function pop(node, { distance = 4 } = {}) {
|
|
68
|
+
return ({ direction } = {}) => {
|
|
69
|
+
const side = node.getAttribute('data-side');
|
|
70
|
+
const move = prefersReducedMotion.current ? 0 : distance;
|
|
71
|
+
const [axis, sign] = side === 'top' ? ['Y', 1] : side === 'left' ? ['X', 1] : side === 'right' ? ['X', -1] : ['Y', -1];
|
|
72
|
+
return {
|
|
73
|
+
duration: duration(node, direction === 'out' ? '--dur-pop-exit' : '--dur-pop'),
|
|
74
|
+
easing: curve(node),
|
|
75
|
+
css: (t, u) => `opacity: ${t}; transform: translate${axis}(${sign * u * move}px)`
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Bottom sheets: slide up from the bottom edge, `--dur-sheet` in and
|
|
81
|
+
* `--dur-sheet-exit` out. Reduced motion: fade only.
|
|
82
|
+
*/
|
|
83
|
+
export function sheet(node) {
|
|
84
|
+
return ({ direction } = {}) => ({
|
|
85
|
+
duration: duration(node, direction === 'out' ? '--dur-sheet-exit' : '--dur-sheet'),
|
|
86
|
+
easing: curve(node),
|
|
87
|
+
css: prefersReducedMotion.current
|
|
88
|
+
? (t) => `opacity: ${t}`
|
|
89
|
+
: (_t, u) => `transform: translateY(${u * 100}%)`
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Side drawers: slide in from the left edge at the sheet timing,
|
|
94
|
+
* `--dur-sheet` in and `--dur-sheet-exit` out. Reduced motion: fade only.
|
|
95
|
+
*/
|
|
96
|
+
export function drawer(node) {
|
|
97
|
+
return ({ direction } = {}) => ({
|
|
98
|
+
duration: duration(node, direction === 'out' ? '--dur-sheet-exit' : '--dur-sheet'),
|
|
99
|
+
easing: curve(node),
|
|
100
|
+
css: prefersReducedMotion.current
|
|
101
|
+
? (t) => `opacity: ${t}`
|
|
102
|
+
: (_t, u) => `transform: translateX(${-u * 100}%)`
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** Scrims and other plain fades, timed with the overlay they belong to. */
|
|
106
|
+
export function fade(node, { pace = 'sheet' } = {}) {
|
|
107
|
+
return ({ direction } = {}) => ({
|
|
108
|
+
duration: duration(node, `--dur-${pace}${direction === 'out' ? '-exit' : ''}`),
|
|
109
|
+
easing: curve(node),
|
|
110
|
+
css: (t) => `opacity: ${t}`
|
|
111
|
+
});
|
|
112
|
+
}
|
package/dist/tokens.css
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/* Hardpoint tokens. Framework-free: plain custom properties and media queries,
|
|
2
|
+
no Svelte selectors, so vanilla apps (omp-remote) can import this file.
|
|
3
|
+
Dark by default, light through data-theme (see the light palette below).
|
|
4
|
+
Colours come from omp-remote's apps/web/public/styles.css; --border-control,
|
|
5
|
+
--surface-band and --surface-selected are new (see docs/BRIEF.md, Tokens).
|
|
6
|
+
|
|
7
|
+
Breakpoints (custom properties cannot be used in @media, so they live here
|
|
8
|
+
as a comment; components repeat the numbers):
|
|
9
|
+
compact < 600px
|
|
10
|
+
medium 600–899px
|
|
11
|
+
expanded 900–1199px
|
|
12
|
+
large >= 1200px */
|
|
13
|
+
|
|
14
|
+
:root {
|
|
15
|
+
color-scheme: dark;
|
|
16
|
+
|
|
17
|
+
/* Surfaces. Major surfaces stay literal black. */
|
|
18
|
+
--canvas: #000000;
|
|
19
|
+
--surface: #000000;
|
|
20
|
+
/* Small hover, active and expanded regions. */
|
|
21
|
+
--surface-hover: #0a0a0a;
|
|
22
|
+
/* The selected tint, under a 3px titanium edge. 1.17:1 on black, so it
|
|
23
|
+
shows; --text 14:1 and --muted 7.4:1 on it. */
|
|
24
|
+
--surface-selected: #191712;
|
|
25
|
+
/* Bubbles, option lists and tracks that must read as a layer. */
|
|
26
|
+
--surface-raised: #191712;
|
|
27
|
+
/* The table header band: one filled strip with caps column labels.
|
|
28
|
+
--text 9.3:1 and --muted 4.9:1 on it. */
|
|
29
|
+
--surface-band: #3a3632;
|
|
30
|
+
/* Dims the page behind a dialog or sheet. */
|
|
31
|
+
--scrim: #000000cc;
|
|
32
|
+
|
|
33
|
+
/* Inks. Two only: no third grey. */
|
|
34
|
+
--text: #e6e3dc; /* 16.4:1 on black */
|
|
35
|
+
--muted: #aaa69f; /* 8.7:1 on black */
|
|
36
|
+
|
|
37
|
+
/* Titanium accent and focus. Not a hue. */
|
|
38
|
+
--accent: #e6e3dc;
|
|
39
|
+
--focus: #e6e3dc;
|
|
40
|
+
|
|
41
|
+
/* Lines. --border is for dividers and decoration only (2.5:1); anything
|
|
42
|
+
that identifies a control uses --border-control (3:1 or more). */
|
|
43
|
+
--border: #514d48;
|
|
44
|
+
--border-control: #625d57; /* 3.2:1 on black, 3.0:1 on --surface-hover */
|
|
45
|
+
|
|
46
|
+
/* Status. Meaning only, never brand. */
|
|
47
|
+
--danger: #ff3b35; /* errors and failures */
|
|
48
|
+
--warn: #f2c14e; /* waiting, blocked, needs you */
|
|
49
|
+
--ok: #35c46b; /* done, success, online */
|
|
50
|
+
|
|
51
|
+
/* Glyphs drawn as backgrounds and masks. The chevron is a mask, painted
|
|
52
|
+
in --muted. */
|
|
53
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m3 6 5 5 5-5' fill='none' stroke='%23AAA69F' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
54
|
+
--status-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M3 3h14v14H3zM10 9v5M10 6v1' fill='none' stroke='%23E6E3DC' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
55
|
+
|
|
56
|
+
/* Faces. Each has a fixed role; see base.css type roles. The fallback
|
|
57
|
+
faces come from fonts.css: local fonts sized to Geist, so text keeps
|
|
58
|
+
its width when Geist arrives. Without fonts.css they are skipped. */
|
|
59
|
+
--sans: 'Geist', 'Geist Fallback Arial', 'Geist Fallback Roboto', sans-serif;
|
|
60
|
+
--mono: 'Geist Mono', 'Geist Mono Fallback', monospace;
|
|
61
|
+
--pixel: 'Geist Pixel Square', var(--mono);
|
|
62
|
+
|
|
63
|
+
/* Type scale. Inputs are 16px at every width. 14px is for dense UI on
|
|
64
|
+
fine pointers only. */
|
|
65
|
+
--type-label: 12px; /* tracked caps labels */
|
|
66
|
+
--type-caption: 13px;
|
|
67
|
+
--type-dense: 14px;
|
|
68
|
+
--type-body: 16px;
|
|
69
|
+
--type-section: 20px;
|
|
70
|
+
--type-page: 24px; /* 20px on compact */
|
|
71
|
+
/* The view title in the shell header, in tracked caps. */
|
|
72
|
+
--type-view: 20px; /* 16px on compact */
|
|
73
|
+
/* The subject only: 32px up to 400px wide, 56px from 1200px. */
|
|
74
|
+
--type-display: clamp(32px, 20px + 3vw, 56px);
|
|
75
|
+
/* Geist Pixel draws on a 0.038em module; only multiples of 26.32px land
|
|
76
|
+
the module on whole pixels. Line heights keep the baseline on a whole
|
|
77
|
+
pixel (Blink rounds ascent 1005 and descent 295 per size). */
|
|
78
|
+
--type-pixel: 26.32px;
|
|
79
|
+
--type-pixel-leading: 32px;
|
|
80
|
+
--type-pixel-lg: 52.63px;
|
|
81
|
+
--type-pixel-lg-leading: 63px;
|
|
82
|
+
|
|
83
|
+
/* The longest line of reading text: about 70 characters of English in
|
|
84
|
+
Geist, at any font size. In em, not ch: Geist's zero is 0.663em wide,
|
|
85
|
+
so 60ch held about 86 characters, and ch changes width when Geist
|
|
86
|
+
replaces the fallback. */
|
|
87
|
+
--measure: 32em;
|
|
88
|
+
|
|
89
|
+
/* Caps labels. Set --label-transform: none to turn caps off. */
|
|
90
|
+
--label-transform: uppercase;
|
|
91
|
+
--label-tracking: 0.06em;
|
|
92
|
+
|
|
93
|
+
/* Space: a 4px grid. Gaps between groups are at least twice the gap
|
|
94
|
+
within a group. Vertical rhythm multiplies by --density. */
|
|
95
|
+
--space-1: 4px;
|
|
96
|
+
--space-2: 8px;
|
|
97
|
+
--space-3: 12px;
|
|
98
|
+
--space-4: 16px;
|
|
99
|
+
--space-5: 20px;
|
|
100
|
+
--space-6: 24px;
|
|
101
|
+
--space-8: 32px;
|
|
102
|
+
--space-10: 40px;
|
|
103
|
+
--space-12: 48px;
|
|
104
|
+
--space-16: 64px;
|
|
105
|
+
/* Page edges, shared by every page. */
|
|
106
|
+
--gutter: 16px;
|
|
107
|
+
/* How far fills (table bands, row tints) reach past the text edge into
|
|
108
|
+
the gutter, so text keeps the page edge while fills extend further. */
|
|
109
|
+
--bleed: 16px;
|
|
110
|
+
/* The shell's one header row, before the top safe area. Sticky elements
|
|
111
|
+
below it offset by this; so does scroll-padding. */
|
|
112
|
+
--header-height: 56px;
|
|
113
|
+
|
|
114
|
+
/* Density scales vertical rhythm: 1 as designed, 0.625 compact. */
|
|
115
|
+
--density: 1;
|
|
116
|
+
/* Control height by pointer: 36px fine, 32px fine + compact, 44px coarse. */
|
|
117
|
+
--control-height: 36px;
|
|
118
|
+
/* Minimum hit area: 24px anywhere (WCAG 2.5.8), 44px on coarse pointers. */
|
|
119
|
+
--hit-target: 24px;
|
|
120
|
+
|
|
121
|
+
/* Motion. Durations by role (BRIEF, motion rule 4); exits are about 70
|
|
122
|
+
percent of entrances. Responses ease out with --settle; never ease in.
|
|
123
|
+
The JS transitions in ./motion read these from the element. */
|
|
124
|
+
--settle: cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
125
|
+
--dur-press: 80ms; /* :active feedback */
|
|
126
|
+
--dur-hover: 120ms; /* hover, fine pointers only */
|
|
127
|
+
/* Short motion on frequent actions (decided 2026-11-11): short enough to
|
|
128
|
+
be noticed, never in the way of daily use. Each one fades opacity or
|
|
129
|
+
colour on --settle, only when a value changes, never on the first
|
|
130
|
+
render or a mount. Quiet motion, so it runs in both tiers, and reduced
|
|
131
|
+
motion keeps it because nothing moves. The user chose these values on
|
|
132
|
+
/motion on 2026-11-11 ("smooth while being quick"); 0ms is a snap. */
|
|
133
|
+
--dur-mark: 80ms; /* a selection mark fading in at its new place: checkbox check and dash, menu marks, switch thumb */
|
|
134
|
+
--dur-panel: 100ms; /* a tab panel chosen by pointer or touch fading in; keys always cut */
|
|
135
|
+
--dur-segment: 120ms; /* progress segments lighting or going out, a steps edge and tint */
|
|
136
|
+
--dur-message: 120ms; /* a field error fading in with the well's edge; it clears at once */
|
|
137
|
+
--dur-pop: 160ms; /* menus, popovers, select lists, tooltips */
|
|
138
|
+
--dur-pop-exit: 110ms;
|
|
139
|
+
--dur-sheet: 240ms; /* dialogs and sheets */
|
|
140
|
+
--dur-sheet-exit: 170ms;
|
|
141
|
+
/* Disclosure: the height snaps open and the content fades in from 0 over
|
|
142
|
+
this time on --settle; closing cuts. The user chose height snaps and
|
|
143
|
+
content fades on 2026-11-11. Only a fade, so it also runs under
|
|
144
|
+
reduced motion. */
|
|
145
|
+
--dur-expand: 120ms;
|
|
146
|
+
/* Expressive stagger (motion rule 7): the first six items, 30ms apart,
|
|
147
|
+
each entering in 150ms, so the sequence ends by 300ms. */
|
|
148
|
+
--dur-enter: 150ms;
|
|
149
|
+
--stagger-step: 30ms;
|
|
150
|
+
/* Content replacing skeleton blocks (motion rule 2): LoadRegion
|
|
151
|
+
crossfades from the blocks to the content over this time when the
|
|
152
|
+
blocks were on screen. The user chose the fade over a cut on /motion
|
|
153
|
+
(2026-11-10); 0ms makes it a cut. Only a fade, so it also runs under
|
|
154
|
+
reduced motion. */
|
|
155
|
+
--dur-reveal: 150ms;
|
|
156
|
+
/* Number ticks (motion rule 5): old value to new on a change, never on
|
|
157
|
+
load. The user chose --settle on 2026-11-10 over the reel's counter
|
|
158
|
+
curve, cubic-bezier(0.37, 0, 0.63, 1). */
|
|
159
|
+
--tick: var(--settle);
|
|
160
|
+
--dur-tick: 400ms;
|
|
161
|
+
/* Image resolve (motion rule 10), expressive tier only: an image that
|
|
162
|
+
arrives after its skeleton showed sharpens from a mosaic in five steps
|
|
163
|
+
of this length (MediaImage). One reel frame at 24 fps. */
|
|
164
|
+
--resolve-step: 42ms;
|
|
165
|
+
/* Layer scale (z-index): sticky content < shell < dialog and sheet < popover, menu, select < toast < tooltip. */
|
|
166
|
+
--layer-sticky: 3;
|
|
167
|
+
--layer-shell: 5;
|
|
168
|
+
--layer-dialog: 40;
|
|
169
|
+
--layer-popover: 50;
|
|
170
|
+
/* The toast, over dialogs, sheets and popovers, so a toast fired from one shows; under tooltips. */
|
|
171
|
+
--layer-toast: 55;
|
|
172
|
+
--layer-tooltip: 60;
|
|
173
|
+
/* Spinner: the glyph steps every 167ms (4 frames of the reel) and appears only after 300ms of waiting. */
|
|
174
|
+
--spinner-step: 167ms;
|
|
175
|
+
--spinner-delay: 300ms;
|
|
176
|
+
/* Skeleton: blocks show only once a wait passes 300ms (motion rule 2). */
|
|
177
|
+
--skeleton-delay: 300ms;
|
|
178
|
+
/* AppShell navigation: the rail from 600px, the sidebar from 900px, the drawer's widest panel on compact. */
|
|
179
|
+
--rail-width: 80px;
|
|
180
|
+
--sidebar-width: 240px;
|
|
181
|
+
--drawer-width: 320px;
|
|
182
|
+
/* ListDetail: the list pane's width side by side, gutters included. The
|
|
183
|
+
narrowest phone's width, so a list laid out for the phone screen fits
|
|
184
|
+
the column as it is. */
|
|
185
|
+
--list-detail-width: 320px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Light palette (2026-11-11). An app picks the theme with data-theme on
|
|
189
|
+
<html>: 'light', 'dark' or 'system' (follows the device). Without the
|
|
190
|
+
attribute the theme is dark. Root only: overlays render in a portal on
|
|
191
|
+
<body>, so a theme set on a subtree would not reach them.
|
|
192
|
+
Values from omp-remote's light palette, except three tokens omp-remote
|
|
193
|
+
lacks (--surface-selected, --surface-band, --border-control) and --ok,
|
|
194
|
+
darkened from #1b7f45 so status text passes 4.5:1 on --surface-raised.
|
|
195
|
+
On --canvas: --text 15.9:1, --muted 6.0:1, --border 2.5:1 (decoration),
|
|
196
|
+
--border-control 3.4:1 (3.0:1 on --surface-hover). The chevron is a
|
|
197
|
+
mask, so its stroke only matters to apps that paint it as an image.
|
|
198
|
+
The two light blocks must stay identical. */
|
|
199
|
+
:root[data-theme='light'] {
|
|
200
|
+
color-scheme: light;
|
|
201
|
+
--canvas: #f7f5f0;
|
|
202
|
+
--surface: #f7f5f0;
|
|
203
|
+
--surface-hover: #edeae3;
|
|
204
|
+
/* 1.15:1 on --canvas, as the dark tint is 1.17:1 on black; --text 13.8:1
|
|
205
|
+
and --muted 5.2:1 on it. */
|
|
206
|
+
--surface-selected: #e9e5dc;
|
|
207
|
+
--surface-raised: #e9e5dc;
|
|
208
|
+
/* 1.30:1 on --canvas, the darkest band that keeps --muted at 4.5:1 or
|
|
209
|
+
more (disabled buttons and pages): --text 12.2:1, --muted 4.6:1. */
|
|
210
|
+
--surface-band: #ddd8cd;
|
|
211
|
+
--scrim: #1c1a1780;
|
|
212
|
+
--text: #1c1a17;
|
|
213
|
+
--muted: #625d55;
|
|
214
|
+
--accent: #1c1a17;
|
|
215
|
+
--focus: #1c1a17;
|
|
216
|
+
--border: #a39c92;
|
|
217
|
+
--border-control: #8c857b;
|
|
218
|
+
--danger: #c4211b; /* 5.4:1 on --canvas, 4.7:1 on --surface-raised */
|
|
219
|
+
--warn: #8a5c00; /* 5.3:1, 4.6:1 */
|
|
220
|
+
--ok: #18763f; /* 5.2:1, 4.5:1 */
|
|
221
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m3 6 5 5 5-5' fill='none' stroke='%23625D55' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
222
|
+
--status-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M3 3h14v14H3zM10 9v5M10 6v1' fill='none' stroke='%231C1A17' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@media (prefers-color-scheme: light) {
|
|
226
|
+
:root[data-theme='system'] {
|
|
227
|
+
color-scheme: light;
|
|
228
|
+
--canvas: #f7f5f0;
|
|
229
|
+
--surface: #f7f5f0;
|
|
230
|
+
--surface-hover: #edeae3;
|
|
231
|
+
--surface-selected: #e9e5dc;
|
|
232
|
+
--surface-raised: #e9e5dc;
|
|
233
|
+
--surface-band: #ddd8cd;
|
|
234
|
+
--scrim: #1c1a1780;
|
|
235
|
+
--text: #1c1a17;
|
|
236
|
+
--muted: #625d55;
|
|
237
|
+
--accent: #1c1a17;
|
|
238
|
+
--focus: #1c1a17;
|
|
239
|
+
--border: #a39c92;
|
|
240
|
+
--border-control: #8c857b;
|
|
241
|
+
--danger: #c4211b;
|
|
242
|
+
--warn: #8a5c00;
|
|
243
|
+
--ok: #18763f;
|
|
244
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m3 6 5 5 5-5' fill='none' stroke='%23625D55' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
245
|
+
--status-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M3 3h14v14H3zM10 9v5M10 6v1' fill='none' stroke='%231C1A17' stroke-width='1.5' stroke-linecap='square'/%3E%3C/svg%3E");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* Density applies to any subtree, not just the root, so a dense table can sit
|
|
250
|
+
inside a comfortable page. */
|
|
251
|
+
[data-density='compact'] {
|
|
252
|
+
--density: 0.625;
|
|
253
|
+
--control-height: 32px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* Compact density never shrinks touch targets. */
|
|
257
|
+
@media (pointer: coarse) {
|
|
258
|
+
:root,
|
|
259
|
+
[data-density='compact'] {
|
|
260
|
+
--control-height: 44px;
|
|
261
|
+
--hit-target: 44px;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@media (min-width: 600px) {
|
|
266
|
+
:root {
|
|
267
|
+
--gutter: 24px;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
@media (min-width: 900px) {
|
|
272
|
+
:root {
|
|
273
|
+
--gutter: 32px;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@media (max-width: 599px) {
|
|
278
|
+
:root {
|
|
279
|
+
--type-page: 20px;
|
|
280
|
+
--type-view: 16px;
|
|
281
|
+
--bleed: 8px;
|
|
282
|
+
}
|
|
283
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,76 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@mystravil/hardpoint",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Hardpoint: a Svelte 5 design system on Bits UI. AMOLED black, titanium ink, Geist, square solid blocks, banded mono tables, opt-in expressive motion, dark and light themes.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "MYSTRAVIL",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"svelte",
|
|
9
|
+
"svelte5",
|
|
10
|
+
"bits-ui",
|
|
11
|
+
"design-system",
|
|
12
|
+
"components"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"!dist/**/*.test.*",
|
|
17
|
+
"!dist/**/*.spec.*",
|
|
18
|
+
"CHANGELOG.md"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"**/*.css"
|
|
26
|
+
],
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"svelte": "./dist/index.js",
|
|
29
|
+
"imports": {
|
|
30
|
+
"#lib": "./src/lib/index.js",
|
|
31
|
+
"#lib/*": "./src/lib/*"
|
|
32
|
+
},
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"svelte": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./fonts.css": "./dist/fonts.css",
|
|
39
|
+
"./tokens.css": "./dist/tokens.css",
|
|
40
|
+
"./base.css": "./dist/base.css",
|
|
41
|
+
"./motion": {
|
|
42
|
+
"types": "./dist/motion/index.d.ts",
|
|
43
|
+
"svelte": "./dist/motion/index.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"dev": "vite dev",
|
|
48
|
+
"build": "vite build && npm run prepack",
|
|
49
|
+
"preview": "vite preview",
|
|
50
|
+
"prepare": "svelte-kit sync || echo ''",
|
|
51
|
+
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
52
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && node scripts/check-lib-imports.mjs",
|
|
53
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
54
|
+
"shot": "node scripts/shot.mjs",
|
|
55
|
+
"audit": "node scripts/audit.mjs"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@sveltejs/adapter-auto": "^8.0.0",
|
|
59
|
+
"@sveltejs/kit": "^3.0.0",
|
|
60
|
+
"@sveltejs/package": "^2.5.8",
|
|
61
|
+
"@sveltejs/vite-plugin-svelte": "^7.2.0",
|
|
62
|
+
"playwright": "^1.65.0",
|
|
63
|
+
"publint": "^0.3.21",
|
|
64
|
+
"svelte": "^5.57.2",
|
|
65
|
+
"svelte-check": "^4.6.0",
|
|
66
|
+
"typescript": "^6.0.3",
|
|
67
|
+
"vite": "^8.3.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"svelte": "^5.57.0"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@internationalized/date": "^3.8.1",
|
|
74
|
+
"bits-ui": "^2.20.6"
|
|
75
|
+
}
|
|
76
|
+
}
|