@sovereignfs/ui 0.21.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/LICENSE +661 -0
- package/NOTICE +24 -0
- package/dist/Avatar.module.css +38 -0
- package/dist/Badge.module.css +88 -0
- package/dist/Button.module.css +77 -0
- package/dist/Card.module.css +34 -0
- package/dist/Dialog.module.css +188 -0
- package/dist/Drawer.module.css +30 -0
- package/dist/EmptyState.module.css +27 -0
- package/dist/FormField.module.css +28 -0
- package/dist/Icon.module.css +22 -0
- package/dist/Input.module.css +37 -0
- package/dist/NavTabs.module.css +48 -0
- package/dist/PageHeader.module.css +32 -0
- package/dist/Popover.module.css +44 -0
- package/dist/SegmentedControl.module.css +53 -0
- package/dist/Select.module.css +69 -0
- package/dist/Spinner.module.css +39 -0
- package/dist/SystemBanner.module.css +67 -0
- package/dist/Tabs.module.css +49 -0
- package/dist/Toast.module.css +130 -0
- package/dist/Toggle.module.css +52 -0
- package/dist/Tooltip.module.css +51 -0
- package/dist/index.d.ts +327 -0
- package/dist/index.js +1370 -0
- package/dist/tokens/primitives.css +99 -0
- package/dist/tokens/semantic.css +111 -0
- package/dist/tokens.css +5 -0
- package/package.json +50 -0
- package/src/components/Avatar/Avatar.module.css +38 -0
- package/src/components/Avatar/Avatar.tsx +42 -0
- package/src/components/Badge/Badge.module.css +88 -0
- package/src/components/Badge/Badge.stories.tsx +118 -0
- package/src/components/Badge/Badge.tsx +59 -0
- package/src/components/Badge/__tests__/Badge.test.tsx +64 -0
- package/src/components/Button/Button.module.css +77 -0
- package/src/components/Button/Button.stories.tsx +76 -0
- package/src/components/Button/Button.tsx +36 -0
- package/src/components/Button/__tests__/Button.test.tsx +37 -0
- package/src/components/Card/Card.module.css +34 -0
- package/src/components/Card/Card.tsx +34 -0
- package/src/components/Dialog/Dialog.module.css +188 -0
- package/src/components/Dialog/Dialog.stories.tsx +97 -0
- package/src/components/Dialog/Dialog.tsx +137 -0
- package/src/components/Dialog/__tests__/Dialog.test.tsx +73 -0
- package/src/components/Drawer/Drawer.module.css +30 -0
- package/src/components/Drawer/Drawer.stories.tsx +88 -0
- package/src/components/Drawer/Drawer.tsx +103 -0
- package/src/components/Drawer/__tests__/Drawer.test.tsx +56 -0
- package/src/components/EmptyState/EmptyState.module.css +27 -0
- package/src/components/EmptyState/EmptyState.tsx +27 -0
- package/src/components/FormField/FormField.module.css +28 -0
- package/src/components/FormField/FormField.tsx +53 -0
- package/src/components/Icon/Icon.module.css +22 -0
- package/src/components/Icon/Icon.stories.tsx +94 -0
- package/src/components/Icon/Icon.tsx +43 -0
- package/src/components/Icon/__tests__/Icon.test.tsx +40 -0
- package/src/components/Icon/icons/activity.tsx +20 -0
- package/src/components/Icon/icons/alert-triangle.tsx +22 -0
- package/src/components/Icon/icons/bell.tsx +21 -0
- package/src/components/Icon/icons/check.tsx +20 -0
- package/src/components/Icon/icons/chevron-down.tsx +20 -0
- package/src/components/Icon/icons/chevron-left.tsx +20 -0
- package/src/components/Icon/icons/chevron-right.tsx +20 -0
- package/src/components/Icon/icons/chevron-up.tsx +20 -0
- package/src/components/Icon/icons/eye-off.tsx +23 -0
- package/src/components/Icon/icons/eye.tsx +21 -0
- package/src/components/Icon/icons/grid-2x2.tsx +22 -0
- package/src/components/Icon/icons/house.tsx +21 -0
- package/src/components/Icon/icons/index.ts +122 -0
- package/src/components/Icon/icons/info.tsx +22 -0
- package/src/components/Icon/icons/lock.tsx +21 -0
- package/src/components/Icon/icons/log-out.tsx +22 -0
- package/src/components/Icon/icons/mail.tsx +21 -0
- package/src/components/Icon/icons/package.tsx +23 -0
- package/src/components/Icon/icons/pencil.tsx +21 -0
- package/src/components/Icon/icons/plus.tsx +21 -0
- package/src/components/Icon/icons/rotate-ccw.tsx +21 -0
- package/src/components/Icon/icons/search.tsx +21 -0
- package/src/components/Icon/icons/settings.tsx +21 -0
- package/src/components/Icon/icons/shield.tsx +20 -0
- package/src/components/Icon/icons/sliders-horizontal.tsx +28 -0
- package/src/components/Icon/icons/terminal.tsx +19 -0
- package/src/components/Icon/icons/trash-2.tsx +24 -0
- package/src/components/Icon/icons/user.tsx +21 -0
- package/src/components/Icon/icons/x.tsx +21 -0
- package/src/components/Input/Input.module.css +37 -0
- package/src/components/Input/Input.stories.tsx +86 -0
- package/src/components/Input/Input.tsx +14 -0
- package/src/components/Input/__tests__/Input.test.tsx +22 -0
- package/src/components/NavTabs/NavTabs.module.css +48 -0
- package/src/components/NavTabs/NavTabs.tsx +33 -0
- package/src/components/PageHeader/PageHeader.module.css +32 -0
- package/src/components/PageHeader/PageHeader.tsx +21 -0
- package/src/components/Popover/Popover.module.css +44 -0
- package/src/components/Popover/Popover.stories.tsx +232 -0
- package/src/components/Popover/Popover.tsx +75 -0
- package/src/components/Popover/__tests__/Popover.test.tsx +98 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +53 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +118 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +56 -0
- package/src/components/SegmentedControl/__tests__/SegmentedControl.test.tsx +63 -0
- package/src/components/Select/Select.module.css +69 -0
- package/src/components/Select/Select.stories.tsx +115 -0
- package/src/components/Select/Select.tsx +40 -0
- package/src/components/Select/__tests__/Select.test.tsx +59 -0
- package/src/components/Spinner/Spinner.module.css +39 -0
- package/src/components/Spinner/Spinner.tsx +23 -0
- package/src/components/SystemBanner/SystemBanner.module.css +67 -0
- package/src/components/SystemBanner/SystemBanner.stories.tsx +86 -0
- package/src/components/SystemBanner/SystemBanner.tsx +50 -0
- package/src/components/SystemBanner/__tests__/SystemBanner.test.tsx +50 -0
- package/src/components/Tabs/Tabs.module.css +49 -0
- package/src/components/Tabs/Tabs.stories.tsx +100 -0
- package/src/components/Tabs/Tabs.tsx +46 -0
- package/src/components/Tabs/__tests__/Tabs.test.tsx +45 -0
- package/src/components/Toast/Toast.module.css +130 -0
- package/src/components/Toast/Toast.stories.tsx +191 -0
- package/src/components/Toast/Toast.tsx +139 -0
- package/src/components/Toggle/Toggle.module.css +52 -0
- package/src/components/Toggle/Toggle.stories.tsx +95 -0
- package/src/components/Toggle/Toggle.tsx +39 -0
- package/src/components/Toggle/__tests__/Toggle.test.tsx +47 -0
- package/src/components/Tooltip/Tooltip.module.css +51 -0
- package/src/components/Tooltip/Tooltip.tsx +30 -0
- package/src/css-modules.d.ts +4 -0
- package/src/index.ts +45 -0
- package/src/stories/Avatar.stories.tsx +44 -0
- package/src/stories/Card.stories.tsx +35 -0
- package/src/stories/DesignSystemOverview.stories.tsx +1683 -0
- package/src/stories/EmptyState.stories.tsx +33 -0
- package/src/stories/FormField.stories.tsx +47 -0
- package/src/stories/MobilePatterns.stories.tsx +1285 -0
- package/src/stories/NavTabs.stories.tsx +35 -0
- package/src/stories/PageHeader.stories.tsx +31 -0
- package/src/stories/Spinner.stories.tsx +25 -0
- package/src/stories/TokenGallery.stories.tsx +355 -0
- package/src/stories/Tooltip.stories.tsx +59 -0
- package/src/tokens/primitives.css +99 -0
- package/src/tokens/semantic.css +111 -0
- package/src/tokens.css +5 -0
package/NOTICE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Sovereign Design System (@sovereignfs/ui)
|
|
2
|
+
Copyright (C) Sovereign contributors
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This package includes icons derived from Lucide (https://lucide.dev).
|
|
7
|
+
|
|
8
|
+
Lucide
|
|
9
|
+
Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part of
|
|
10
|
+
Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2022.
|
|
11
|
+
|
|
12
|
+
ISC License
|
|
13
|
+
|
|
14
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
15
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
16
|
+
copyright notice and this permission notice appear in all copies.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
19
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
20
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
21
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
22
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
23
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
24
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.avatar {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
border-radius: 50%;
|
|
6
|
+
background: var(--sv-color-surface-raised);
|
|
7
|
+
border: 1px solid var(--sv-color-border);
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
flex-shrink: 0;
|
|
10
|
+
font-weight: var(--sv-font-weight-medium);
|
|
11
|
+
color: var(--sv-color-text-primary);
|
|
12
|
+
font-family: var(--sv-font-family);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.sm {
|
|
16
|
+
width: 24px;
|
|
17
|
+
height: 24px;
|
|
18
|
+
font-size: var(--sv-font-size-label);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.md {
|
|
22
|
+
width: 32px;
|
|
23
|
+
height: 32px;
|
|
24
|
+
font-size: var(--sv-font-size-xs);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.lg {
|
|
28
|
+
width: 40px;
|
|
29
|
+
height: 40px;
|
|
30
|
+
font-size: var(--sv-font-size-sm);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.img {
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
object-fit: cover;
|
|
37
|
+
display: block;
|
|
38
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
.badge {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: var(--sv-space-1);
|
|
5
|
+
border-radius: var(--sv-radius-sm);
|
|
6
|
+
font-family: var(--sv-font-family);
|
|
7
|
+
font-size: var(--sv-font-size-xs);
|
|
8
|
+
line-height: 1;
|
|
9
|
+
white-space: nowrap;
|
|
10
|
+
user-select: none;
|
|
11
|
+
text-transform: uppercase;
|
|
12
|
+
letter-spacing: 0.05em;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* role — neutral fill, border, title case */
|
|
16
|
+
.role {
|
|
17
|
+
padding: 2px var(--sv-space-2);
|
|
18
|
+
background: var(--sv-color-surface-sunken);
|
|
19
|
+
border: 1px solid var(--sv-color-border);
|
|
20
|
+
color: var(--sv-color-text-primary);
|
|
21
|
+
font-size: var(--sv-font-size-label);
|
|
22
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* status — tinted chip with leading colour dot; colour set by chip* classes below */
|
|
26
|
+
.status {
|
|
27
|
+
padding: 2px var(--sv-space-2) 2px var(--sv-space-1);
|
|
28
|
+
font-weight: var(--sv-font-weight-medium);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.chipGreen {
|
|
32
|
+
background: var(--sv-color-success-surface);
|
|
33
|
+
border: 1px solid var(--sv-color-success-border);
|
|
34
|
+
color: var(--sv-color-success-text);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.chipAmber {
|
|
38
|
+
background: var(--sv-color-warning-surface);
|
|
39
|
+
border: 1px solid var(--sv-color-warning-border);
|
|
40
|
+
color: var(--sv-color-warning-text);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.chipRed {
|
|
44
|
+
background: var(--sv-color-error-surface);
|
|
45
|
+
border: 1px solid var(--sv-color-error-border);
|
|
46
|
+
color: var(--sv-color-error-text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.chipNeutral {
|
|
50
|
+
background: var(--sv-color-surface-sunken);
|
|
51
|
+
border: 1px solid var(--sv-color-border);
|
|
52
|
+
color: var(--sv-color-text-muted);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* mono — monospace font, neutral surface, for type tags / versions */
|
|
56
|
+
.mono {
|
|
57
|
+
padding: 2px var(--sv-space-2);
|
|
58
|
+
background: var(--sv-color-surface-sunken);
|
|
59
|
+
border: 1px solid var(--sv-color-border);
|
|
60
|
+
color: var(--sv-color-text-muted);
|
|
61
|
+
font-family: var(--sv-font-family-mono);
|
|
62
|
+
font-size: var(--sv-font-size-xs);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* Status dot */
|
|
66
|
+
.dot {
|
|
67
|
+
display: inline-block;
|
|
68
|
+
width: 6px;
|
|
69
|
+
height: 6px;
|
|
70
|
+
border-radius: var(--sv-radius-full);
|
|
71
|
+
flex-shrink: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.dotGreen {
|
|
75
|
+
background: var(--sv-color-success-text);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.dotRed {
|
|
79
|
+
background: var(--sv-color-error-text);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.dotAmber {
|
|
83
|
+
background: var(--sv-color-warning-text);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.dotGrey {
|
|
87
|
+
background: var(--sv-color-text-muted);
|
|
88
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
.button {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
gap: var(--sv-space-2);
|
|
6
|
+
border: 1px solid transparent;
|
|
7
|
+
border-radius: var(--sv-radius-md);
|
|
8
|
+
font-family: var(--sv-font-family);
|
|
9
|
+
font-weight: var(--sv-font-weight-medium);
|
|
10
|
+
line-height: 1;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
transition:
|
|
13
|
+
background-color 0.15s ease,
|
|
14
|
+
border-color 0.15s ease,
|
|
15
|
+
color 0.15s ease;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.button:focus-visible {
|
|
19
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
20
|
+
outline-offset: 2px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.button:disabled {
|
|
24
|
+
opacity: 0.5;
|
|
25
|
+
cursor: not-allowed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Sizes */
|
|
29
|
+
.sm {
|
|
30
|
+
padding: var(--sv-space-1) var(--sv-space-3);
|
|
31
|
+
font-size: var(--sv-font-size-sm);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.md {
|
|
35
|
+
padding: 13px var(--sv-space-4);
|
|
36
|
+
font-size: var(--sv-font-size-sm);
|
|
37
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Variants */
|
|
41
|
+
.primary {
|
|
42
|
+
background-color: var(--sv-color-accent);
|
|
43
|
+
color: var(--sv-color-text-on-accent);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.primary:hover:not(:disabled) {
|
|
47
|
+
background-color: var(--sv-color-accent-hover);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.secondary {
|
|
51
|
+
background-color: var(--sv-color-surface);
|
|
52
|
+
color: var(--sv-color-text-primary);
|
|
53
|
+
border-color: var(--sv-color-border-strong);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.secondary:hover:not(:disabled) {
|
|
57
|
+
background-color: var(--sv-color-surface-sunken);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.ghost {
|
|
61
|
+
background-color: transparent;
|
|
62
|
+
color: var(--sv-color-text-primary);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.ghost:hover:not(:disabled) {
|
|
66
|
+
background-color: var(--sv-color-surface-sunken);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.destructive {
|
|
70
|
+
background-color: transparent;
|
|
71
|
+
color: var(--sv-color-error-text);
|
|
72
|
+
border-color: var(--sv-color-error-border);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.destructive:hover:not(:disabled) {
|
|
76
|
+
background-color: var(--sv-color-error-surface);
|
|
77
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
.card {
|
|
2
|
+
background: var(--sv-color-surface-raised);
|
|
3
|
+
border: 1px solid var(--sv-color-border);
|
|
4
|
+
border-radius: var(--sv-radius-lg);
|
|
5
|
+
box-shadow: var(--sv-shadow-card);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.paddingSm {
|
|
9
|
+
padding: var(--sv-space-3);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.paddingMd {
|
|
13
|
+
padding: var(--sv-space-5);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.paddingLg {
|
|
17
|
+
padding: var(--sv-space-8);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.interactive {
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
display: block;
|
|
24
|
+
transition: border-color 0.15s ease;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.interactive:hover {
|
|
28
|
+
border-color: var(--sv-color-border-strong);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.interactive:focus-visible {
|
|
32
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
33
|
+
outline-offset: 2px;
|
|
34
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/* Dialog — scrim + centered panel. Tokens only (z-index is structural, not a
|
|
2
|
+
* theming value, so it has no token).
|
|
3
|
+
*
|
|
4
|
+
* Each size is a FIXED box (width AND height) — the panel never grows or
|
|
5
|
+
* shrinks with its content, so switching views inside it (e.g. overlay-plugin
|
|
6
|
+
* tabs) keeps the dialog the exact same size. Overflow scrolls inside `.content`
|
|
7
|
+
* while the panel and its close button stay put. The scrim's padding is the
|
|
8
|
+
* fixed margin `lg` leaves around the viewport; `sm`/`md` are centered and cap
|
|
9
|
+
* to that available space on short screens. On mobile every size becomes a
|
|
10
|
+
* full-screen sheet.
|
|
11
|
+
*
|
|
12
|
+
* `--sv-dialog-inset-left` lets a host inset the scrim past a fixed left nav
|
|
13
|
+
* rail (e.g. the platform sidebar) so the overlay's left margin is measured
|
|
14
|
+
* from the rail, not the viewport edge, and the rail stays visible/usable.
|
|
15
|
+
* `--sv-dialog-inset-top` (RFC 0013) mirrors this on the vertical axis: the
|
|
16
|
+
* shell sets it to the mobile header height so the header stays visible and
|
|
17
|
+
* interactive above the dialog sheet. Defaults to 0 for standalone use. */
|
|
18
|
+
|
|
19
|
+
.scrim {
|
|
20
|
+
position: fixed;
|
|
21
|
+
top: var(--sv-dialog-inset-top, 0);
|
|
22
|
+
right: 0;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
left: 0;
|
|
25
|
+
z-index: 100;
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
/* left edge always 0 so the backdrop covers the full viewport incl. sidebar.
|
|
30
|
+
padding-left offsets the panel's available area to start at the rail edge. */
|
|
31
|
+
padding: var(--sv-space-8);
|
|
32
|
+
padding-left: calc(var(--sv-dialog-inset-left, 0px) + var(--sv-space-8));
|
|
33
|
+
background: var(--sv-color-scrim);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.panel {
|
|
37
|
+
position: relative;
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
background: var(--sv-color-surface-raised);
|
|
42
|
+
color: var(--sv-color-text-primary);
|
|
43
|
+
border: 1px solid var(--sv-color-border);
|
|
44
|
+
border-radius: var(--sv-radius-lg);
|
|
45
|
+
box-shadow: var(--sv-shadow-overlay);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.content {
|
|
49
|
+
flex: 1 1 auto;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
padding: var(--sv-space-6);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Fixed sizes. `max-*: 100%` caps to the scrim's content box (viewport minus
|
|
55
|
+
* margin) so a size never overflows a small viewport. */
|
|
56
|
+
.sm {
|
|
57
|
+
width: 24rem;
|
|
58
|
+
height: 28rem;
|
|
59
|
+
max-width: 100%;
|
|
60
|
+
max-height: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.md {
|
|
64
|
+
width: 36rem;
|
|
65
|
+
height: 42rem;
|
|
66
|
+
max-width: 100%;
|
|
67
|
+
max-height: 100%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.lg,
|
|
71
|
+
.full {
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.close {
|
|
77
|
+
position: absolute;
|
|
78
|
+
top: var(--sv-space-3);
|
|
79
|
+
right: var(--sv-space-3);
|
|
80
|
+
z-index: 1;
|
|
81
|
+
display: inline-flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: center;
|
|
84
|
+
width: var(--sv-space-8);
|
|
85
|
+
height: var(--sv-space-8);
|
|
86
|
+
border: none;
|
|
87
|
+
border-radius: var(--sv-radius-md);
|
|
88
|
+
background: transparent;
|
|
89
|
+
color: var(--sv-color-text-muted);
|
|
90
|
+
font-size: var(--sv-font-size-xl);
|
|
91
|
+
line-height: 1;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.close:hover {
|
|
96
|
+
background: var(--sv-color-surface-sunken);
|
|
97
|
+
color: var(--sv-color-text-primary);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.close:focus-visible {
|
|
101
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
102
|
+
outline-offset: 2px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Hidden on desktop; shown only on mobile where it replaces the close button. */
|
|
106
|
+
.mobileBar {
|
|
107
|
+
display: none;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Mobile: full-screen sheet (RFC 0001 §3, breakpoint unified to 768px per
|
|
111
|
+
* RFC 0013). Every size fills the scrim's available area (which is already
|
|
112
|
+
* inset from the top by --sv-dialog-inset-top when a fixed header is shown).
|
|
113
|
+
* The panel therefore fills height: 100% of the remaining space, not 100dvh. */
|
|
114
|
+
@media (max-width: 768px) {
|
|
115
|
+
/* On mobile the overlay feels like a full-page push, not a floating modal.
|
|
116
|
+
Remove the dim scrim and panel chrome so it's indistinguishable from a
|
|
117
|
+
regular page render. router.back() still closes it correctly. */
|
|
118
|
+
.scrim {
|
|
119
|
+
padding: 0;
|
|
120
|
+
background: transparent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.panel,
|
|
124
|
+
.sm,
|
|
125
|
+
.md,
|
|
126
|
+
.lg,
|
|
127
|
+
.full {
|
|
128
|
+
width: 100%;
|
|
129
|
+
height: 100%;
|
|
130
|
+
max-width: none;
|
|
131
|
+
max-height: none;
|
|
132
|
+
border: none;
|
|
133
|
+
border-radius: 0;
|
|
134
|
+
box-shadow: none;
|
|
135
|
+
background: var(--sv-color-surface);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Desktop close button is replaced by mobileBar on mobile. */
|
|
139
|
+
.close {
|
|
140
|
+
display: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Title + close button in one solid row. Being a flex sibling before
|
|
144
|
+
.content means it never scrolls — the content area scrolls below it. */
|
|
145
|
+
.mobileBar {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
flex-shrink: 0;
|
|
149
|
+
padding: var(--sv-space-3) var(--sv-space-4);
|
|
150
|
+
background: var(--sv-color-surface);
|
|
151
|
+
border-bottom: 1px solid var(--sv-color-border);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.mobileBarTitle {
|
|
155
|
+
flex: 1;
|
|
156
|
+
font-size: var(--sv-font-size-xl);
|
|
157
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
158
|
+
color: var(--sv-color-text-primary);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.mobileBarClose {
|
|
162
|
+
display: inline-flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
justify-content: center;
|
|
165
|
+
width: var(--sv-space-8);
|
|
166
|
+
height: var(--sv-space-8);
|
|
167
|
+
flex-shrink: 0;
|
|
168
|
+
border: none;
|
|
169
|
+
border-radius: var(--sv-radius-md);
|
|
170
|
+
background: transparent;
|
|
171
|
+
color: var(--sv-color-text-muted);
|
|
172
|
+
font-size: var(--sv-font-size-xl);
|
|
173
|
+
line-height: 1;
|
|
174
|
+
cursor: pointer;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.mobileBarClose:hover {
|
|
178
|
+
background: var(--sv-color-surface-sunken);
|
|
179
|
+
color: var(--sv-color-text-primary);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Remove top padding so the sticky plugin header sits flush against the
|
|
183
|
+
mobileBar — no gap for scrolling content to bleed through. */
|
|
184
|
+
.content {
|
|
185
|
+
padding-top: 0;
|
|
186
|
+
padding-bottom: calc(var(--sv-shell-footer-height, 60px) + var(--sv-space-6, 24px));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* Drawer — bottom-sheet surface (RFC 0013). Shares scrim/shadow tokens with
|
|
2
|
+
* Dialog but slides up from the bottom instead of centering. The panel has no
|
|
3
|
+
* fixed height — it sizes to content, capped at 80dvh so some page context
|
|
4
|
+
* remains visible above. Safe-area-aware: bottom padding clears the home
|
|
5
|
+
* indicator in standalone/fullscreen mode. */
|
|
6
|
+
|
|
7
|
+
.scrim {
|
|
8
|
+
position: fixed;
|
|
9
|
+
inset: 0;
|
|
10
|
+
/* When the shell declares --sv-shell-footer-height (mobile nav bar), stop the
|
|
11
|
+
scrim above the footer so the panel never hides behind it. */
|
|
12
|
+
bottom: var(--sv-shell-footer-height, 0);
|
|
13
|
+
z-index: 100;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: flex-end;
|
|
16
|
+
background: var(--sv-color-scrim);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.panel {
|
|
20
|
+
width: 100%;
|
|
21
|
+
max-height: 80dvh;
|
|
22
|
+
overflow-y: auto;
|
|
23
|
+
background: var(--sv-color-surface-raised);
|
|
24
|
+
border-top: 1px solid var(--sv-color-border);
|
|
25
|
+
border-radius: var(--sv-radius-3xl) var(--sv-radius-3xl) 0 0;
|
|
26
|
+
box-shadow: var(--sv-shadow-overlay);
|
|
27
|
+
/* Pull content above the home indicator / bottom bar in standalone mode. */
|
|
28
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
29
|
+
outline: none;
|
|
30
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
gap: var(--sv-space-3);
|
|
7
|
+
padding: var(--sv-space-12) var(--sv-space-6);
|
|
8
|
+
text-align: center;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.icon {
|
|
12
|
+
color: var(--sv-color-text-subtle);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.heading {
|
|
16
|
+
margin: 0;
|
|
17
|
+
font-size: var(--sv-font-size-md);
|
|
18
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
19
|
+
color: var(--sv-color-text-primary);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.description {
|
|
23
|
+
margin: 0;
|
|
24
|
+
font-size: var(--sv-font-size-sm);
|
|
25
|
+
color: var(--sv-color-text-muted);
|
|
26
|
+
max-width: 36ch;
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.field {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--sv-space-1);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.label {
|
|
8
|
+
font-size: var(--sv-font-size-sm);
|
|
9
|
+
font-weight: var(--sv-font-weight-medium);
|
|
10
|
+
color: var(--sv-color-text-primary);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.required {
|
|
14
|
+
color: var(--sv-color-error-text);
|
|
15
|
+
margin-left: var(--sv-space-1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.hint {
|
|
19
|
+
margin: 0;
|
|
20
|
+
font-size: var(--sv-font-size-xs);
|
|
21
|
+
color: var(--sv-color-text-muted);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.error {
|
|
25
|
+
margin: 0;
|
|
26
|
+
font-size: var(--sv-font-size-xs);
|
|
27
|
+
color: var(--sv-color-error-text);
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
flex-shrink: 0;
|
|
4
|
+
/* Prevent the inline-block from adding line-height whitespace below the SVG. */
|
|
5
|
+
line-height: 0;
|
|
6
|
+
/* Color follows the surrounding text via currentColor — no token needed. */
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.sm {
|
|
10
|
+
width: var(--sv-icon-size-sm);
|
|
11
|
+
height: var(--sv-icon-size-sm);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.md {
|
|
15
|
+
width: var(--sv-icon-size-md);
|
|
16
|
+
height: var(--sv-icon-size-md);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.lg {
|
|
20
|
+
width: var(--sv-icon-size-lg);
|
|
21
|
+
height: var(--sv-icon-size-lg);
|
|
22
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
.input {
|
|
2
|
+
display: block;
|
|
3
|
+
width: 100%;
|
|
4
|
+
padding: var(--sv-space-2) var(--sv-space-3);
|
|
5
|
+
font-family: var(--sv-font-family);
|
|
6
|
+
font-size: var(--sv-font-size-sm);
|
|
7
|
+
line-height: 1.5;
|
|
8
|
+
color: var(--sv-color-text-primary);
|
|
9
|
+
background-color: var(--sv-color-surface);
|
|
10
|
+
border: 1px solid var(--sv-color-border-strong);
|
|
11
|
+
border-radius: var(--sv-radius-md);
|
|
12
|
+
transition:
|
|
13
|
+
border-color 0.15s ease,
|
|
14
|
+
box-shadow 0.15s ease;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.input::placeholder {
|
|
18
|
+
color: var(--sv-color-text-muted);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.input:focus-visible {
|
|
22
|
+
outline: none;
|
|
23
|
+
border-color: var(--sv-color-accent);
|
|
24
|
+
box-shadow: 0 0 0 2px var(--sv-color-focus-ring);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.input:read-only {
|
|
28
|
+
background-color: var(--sv-color-surface-sunken);
|
|
29
|
+
color: var(--sv-color-text-muted);
|
|
30
|
+
border-color: var(--sv-color-border);
|
|
31
|
+
cursor: default;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.input:disabled {
|
|
35
|
+
opacity: 0.5;
|
|
36
|
+
cursor: not-allowed;
|
|
37
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.nav {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
gap: 0;
|
|
5
|
+
border-bottom: 1px solid var(--sv-color-border);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.link {
|
|
9
|
+
padding: var(--sv-space-2) var(--sv-space-3);
|
|
10
|
+
padding-bottom: calc(var(--sv-space-2) + 2px);
|
|
11
|
+
border-bottom: 2px solid transparent;
|
|
12
|
+
font-size: var(--sv-font-size-sm);
|
|
13
|
+
font-weight: var(--sv-font-weight-medium);
|
|
14
|
+
color: var(--sv-color-text-muted);
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
white-space: nowrap;
|
|
17
|
+
transition: color 0.1s ease;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.link:hover {
|
|
21
|
+
color: var(--sv-color-text-primary);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.link:focus-visible {
|
|
25
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
26
|
+
outline-offset: -2px;
|
|
27
|
+
border-radius: var(--sv-radius-sm);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.active {
|
|
31
|
+
color: var(--sv-color-text-primary);
|
|
32
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
33
|
+
border-bottom-color: var(--sv-color-text-primary);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@media (max-width: 640px) {
|
|
37
|
+
.nav {
|
|
38
|
+
flex-wrap: nowrap;
|
|
39
|
+
overflow-x: auto;
|
|
40
|
+
scrollbar-width: none;
|
|
41
|
+
-webkit-overflow-scrolling: touch;
|
|
42
|
+
mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.nav::-webkit-scrollbar {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.header {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: flex-start;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
gap: var(--sv-space-4);
|
|
6
|
+
margin-bottom: var(--sv-space-6);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.text {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
gap: var(--sv-space-1);
|
|
13
|
+
min-width: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.title {
|
|
17
|
+
margin: 0;
|
|
18
|
+
font-size: var(--sv-font-size-2xl);
|
|
19
|
+
font-weight: var(--sv-font-weight-semibold);
|
|
20
|
+
color: var(--sv-color-text-primary);
|
|
21
|
+
line-height: 1.2;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.description {
|
|
25
|
+
margin: 0;
|
|
26
|
+
font-size: var(--sv-font-size-sm);
|
|
27
|
+
color: var(--sv-color-text-muted);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.action {
|
|
31
|
+
flex-shrink: 0;
|
|
32
|
+
}
|