@junoput01/junoui 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 +199 -0
- package/README.md +117 -0
- package/dist/android/colors.xml +94 -0
- package/dist/android/dimens.xml +49 -0
- package/dist/css/juno-fonts.css +45 -0
- package/dist/css/juno-tokens.css +345 -0
- package/dist/css/juno.css +4481 -0
- package/dist/flutter/juno_tokens.dart +143 -0
- package/dist/fonts/b612-400.woff2 +0 -0
- package/dist/fonts/b612-700.woff2 +0 -0
- package/dist/fonts/b612-mono-400.woff2 +0 -0
- package/dist/fonts/b612-mono-700.woff2 +0 -0
- package/dist/icons/juno-icons.svg +69 -0
- package/dist/ios/JunoTokens.swift +149 -0
- package/dist/js/tokens.d.ts +11 -0
- package/dist/js/tokens.js +244 -0
- package/dist/json/tokens.json +921 -0
- package/dist/scss/_juno-tokens.scss +176 -0
- package/package.json +92 -0
- package/src/css/base.css +120 -0
- package/src/css/components/accordion.css +83 -0
- package/src/css/components/alert.css +90 -0
- package/src/css/components/avatar.css +82 -0
- package/src/css/components/badge.css +55 -0
- package/src/css/components/breadcrumb.css +64 -0
- package/src/css/components/button.css +59 -0
- package/src/css/components/card.css +68 -0
- package/src/css/components/checkbox.css +89 -0
- package/src/css/components/chip.css +89 -0
- package/src/css/components/divider.css +50 -0
- package/src/css/components/dock.css +74 -0
- package/src/css/components/dot.css +35 -0
- package/src/css/components/drawer.css +80 -0
- package/src/css/components/field.css +37 -0
- package/src/css/components/gauge.css +78 -0
- package/src/css/components/icon.css +35 -0
- package/src/css/components/input.css +60 -0
- package/src/css/components/list.css +135 -0
- package/src/css/components/loader.css +159 -0
- package/src/css/components/menu.css +114 -0
- package/src/css/components/modal.css +161 -0
- package/src/css/components/navbar.css +103 -0
- package/src/css/components/pagination.css +72 -0
- package/src/css/components/pillbar.css +111 -0
- package/src/css/components/popover.css +73 -0
- package/src/css/components/rail.css +96 -0
- package/src/css/components/readout.css +45 -0
- package/src/css/components/segmented.css +99 -0
- package/src/css/components/select.css +38 -0
- package/src/css/components/skeleton.css +62 -0
- package/src/css/components/slider.css +117 -0
- package/src/css/components/spark.css +26 -0
- package/src/css/components/stepper.css +121 -0
- package/src/css/components/switch.css +131 -0
- package/src/css/components/table.css +443 -0
- package/src/css/components/tabs.css +66 -0
- package/src/css/components/thumb.css +69 -0
- package/src/css/components/toast.css +109 -0
- package/src/css/components/toggle-button.css +91 -0
- package/src/css/components/tooltip.css +155 -0
- package/src/css/density.css +40 -0
- package/src/css/fonts.css +45 -0
- package/src/css/layout.css +99 -0
- package/src/css/typescale.css +27 -0
- package/src/css/utilities.css +76 -0
- package/src/fonts/LICENSE +93 -0
- package/src/fonts/b612-400.woff2 +0 -0
- package/src/fonts/b612-700.woff2 +0 -0
- package/src/fonts/b612-mono-400.woff2 +0 -0
- package/src/fonts/b612-mono-700.woff2 +0 -0
- package/src/icons/LICENSE +21 -0
- package/src/icons/arrow-clockwise.svg +1 -0
- package/src/icons/arrow-down.svg +1 -0
- package/src/icons/arrow-left.svg +1 -0
- package/src/icons/arrow-right.svg +1 -0
- package/src/icons/arrow-up.svg +1 -0
- package/src/icons/arrows-clockwise.svg +1 -0
- package/src/icons/arrows-out.svg +1 -0
- package/src/icons/bell.svg +1 -0
- package/src/icons/calendar-blank.svg +1 -0
- package/src/icons/caret-down.svg +1 -0
- package/src/icons/caret-left.svg +1 -0
- package/src/icons/caret-right.svg +1 -0
- package/src/icons/caret-up.svg +1 -0
- package/src/icons/chat-circle.svg +1 -0
- package/src/icons/check-circle.svg +1 -0
- package/src/icons/check.svg +1 -0
- package/src/icons/clock.svg +1 -0
- package/src/icons/cloud-arrow-down.svg +1 -0
- package/src/icons/cloud.svg +1 -0
- package/src/icons/copy.svg +1 -0
- package/src/icons/cpu.svg +1 -0
- package/src/icons/dots-three-vertical.svg +1 -0
- package/src/icons/dots-three.svg +1 -0
- package/src/icons/download.svg +1 -0
- package/src/icons/envelope.svg +1 -0
- package/src/icons/eye-slash.svg +1 -0
- package/src/icons/eye.svg +1 -0
- package/src/icons/file.svg +1 -0
- package/src/icons/film-strip.svg +1 -0
- package/src/icons/floppy-disk.svg +1 -0
- package/src/icons/folder.svg +1 -0
- package/src/icons/funnel.svg +1 -0
- package/src/icons/gear.svg +1 -0
- package/src/icons/hard-drives.svg +1 -0
- package/src/icons/heart.svg +1 -0
- package/src/icons/hexagon.svg +1 -0
- package/src/icons/house.svg +1 -0
- package/src/icons/images.svg +1 -0
- package/src/icons/info.svg +1 -0
- package/src/icons/link.svg +1 -0
- package/src/icons/list.svg +1 -0
- package/src/icons/lock-open.svg +1 -0
- package/src/icons/lock.svg +1 -0
- package/src/icons/magnifying-glass.svg +1 -0
- package/src/icons/minus.svg +1 -0
- package/src/icons/moon.svg +1 -0
- package/src/icons/pencil-simple.svg +1 -0
- package/src/icons/play.svg +1 -0
- package/src/icons/plus.svg +1 -0
- package/src/icons/puzzle-piece.svg +1 -0
- package/src/icons/question.svg +1 -0
- package/src/icons/sliders-horizontal.svg +1 -0
- package/src/icons/sliders.svg +1 -0
- package/src/icons/squares-four.svg +1 -0
- package/src/icons/star.svg +1 -0
- package/src/icons/sun.svg +1 -0
- package/src/icons/trash.svg +1 -0
- package/src/icons/upload-simple.svg +1 -0
- package/src/icons/upload.svg +1 -0
- package/src/icons/user.svg +1 -0
- package/src/icons/users.svg +1 -0
- package/src/icons/warning-circle.svg +1 -0
- package/src/icons/warning.svg +1 -0
- package/src/icons/x-circle.svg +1 -0
- package/src/icons/x.svg +1 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Badge / status indicator
|
|
3
|
+
* Usage: <span class="juno-badge juno--nominal">NOMINAL</span>
|
|
4
|
+
* <span class="juno-badge juno-badge--outline juno--caution">…</span>
|
|
5
|
+
* Color comes from --juno-role (set by an .juno--<role> class).
|
|
6
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
7
|
+
|
|
8
|
+
.juno-badge {
|
|
9
|
+
--juno-role: var(--juno-muted);
|
|
10
|
+
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
font-family: var(--juno-font-family-sans);
|
|
14
|
+
font-size: var(--juno-font-size-11);
|
|
15
|
+
font-weight: var(--juno-font-weight-bold);
|
|
16
|
+
letter-spacing: var(--juno-font-tracking-caps);
|
|
17
|
+
text-transform: uppercase;
|
|
18
|
+
padding: var(--juno-space-4) var(--juno-space-10);
|
|
19
|
+
border-radius: var(--juno-radius-3);
|
|
20
|
+
border: var(--juno-border-width-1) solid transparent;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
|
|
23
|
+
/* filled (default) */
|
|
24
|
+
background: var(--juno-role);
|
|
25
|
+
color: var(--juno-s0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.juno-badge--outline {
|
|
29
|
+
background: transparent;
|
|
30
|
+
color: var(--juno-role);
|
|
31
|
+
border-color: var(--juno-role);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* micro — data-UI atom below the badge scale: provenance/kind tags, model
|
|
35
|
+
names, threshold values. Mono, outline-only, 10px floor (the type scale
|
|
36
|
+
stops there on purpose). Role via juno--* as usual. */
|
|
37
|
+
.juno-badge--micro {
|
|
38
|
+
font-family: var(--juno-font-family-mono);
|
|
39
|
+
font-size: var(--juno-font-size-10);
|
|
40
|
+
font-weight: var(--juno-font-weight-semibold);
|
|
41
|
+
letter-spacing: var(--juno-font-tracking-normal);
|
|
42
|
+
padding: var(--juno-space-2) var(--juno-space-4);
|
|
43
|
+
border-radius: var(--juno-radius-2);
|
|
44
|
+
background: transparent;
|
|
45
|
+
color: var(--juno-role);
|
|
46
|
+
border-color: color-mix(in srgb, var(--juno-role) 55%, transparent);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* soft — low-fill chip: role text on a tinted wash + faint role border.
|
|
50
|
+
Quieter than filled; ideal for in-table status (a phase/state per row). */
|
|
51
|
+
.juno-badge--soft {
|
|
52
|
+
background: color-mix(in srgb, var(--juno-role) 13%, transparent);
|
|
53
|
+
color: var(--juno-role);
|
|
54
|
+
border-color: color-mix(in srgb, var(--juno-role) 30%, transparent);
|
|
55
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Breadcrumb · hierarchy trail
|
|
3
|
+
* A horizontal path of links to ancestor pages, ending at the current
|
|
4
|
+
* page. Built on a real <nav><ol>; the separator is a CSS chevron (no
|
|
5
|
+
* glyph font). Mark the last crumb aria-current="page". Zero JS.
|
|
6
|
+
* Usage:
|
|
7
|
+
* <nav class="juno-breadcrumb" aria-label="Breadcrumb">
|
|
8
|
+
* <ol>
|
|
9
|
+
* <li><a href="/">Home</a></li>
|
|
10
|
+
* <li><a href="/fleet">Fleet</a></li>
|
|
11
|
+
* <li><a aria-current="page">api-gateway</a></li>
|
|
12
|
+
* </ol>
|
|
13
|
+
* </nav>
|
|
14
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
15
|
+
|
|
16
|
+
.juno-breadcrumb ol {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-wrap: wrap;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: var(--juno-space-8);
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
list-style: none;
|
|
24
|
+
font-family: var(--juno-font-family-sans);
|
|
25
|
+
font-size: var(--juno-font-size-13);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.juno-breadcrumb li {
|
|
29
|
+
display: inline-flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
gap: var(--juno-space-8);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.juno-breadcrumb a {
|
|
35
|
+
color: var(--juno-label);
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
border-radius: var(--juno-radius-2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.juno-breadcrumb a[href]:hover {
|
|
41
|
+
color: var(--juno-data);
|
|
42
|
+
text-decoration: underline;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.juno-breadcrumb a:focus-visible {
|
|
46
|
+
outline: var(--juno-border-width-2) solid var(--juno-active);
|
|
47
|
+
outline-offset: var(--juno-space-2);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* current page — not a link; brightest */
|
|
51
|
+
.juno-breadcrumb [aria-current='page'] {
|
|
52
|
+
color: var(--juno-data);
|
|
53
|
+
font-weight: var(--juno-font-weight-semibold);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* separator — a CSS chevron between items (no glyph font) */
|
|
57
|
+
.juno-breadcrumb li + li::before {
|
|
58
|
+
content: '';
|
|
59
|
+
inline-size: var(--juno-space-4);
|
|
60
|
+
block-size: var(--juno-space-4);
|
|
61
|
+
border-block-start: var(--juno-border-width-1) solid var(--juno-muted);
|
|
62
|
+
border-inline-end: var(--juno-border-width-1) solid var(--juno-muted);
|
|
63
|
+
transform: rotate(45deg); /* points to the inline-end (flips under RTL via dir) */
|
|
64
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Button
|
|
3
|
+
* Usage: <button class="juno-btn juno--nominal">CONFIRM</button>
|
|
4
|
+
* <button class="juno-btn juno-btn--ghost">CANCEL</button>
|
|
5
|
+
* <button class="juno-btn juno-btn--sm">EDIT</button>
|
|
6
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
7
|
+
|
|
8
|
+
.juno-btn {
|
|
9
|
+
--juno-role: var(--juno-active);
|
|
10
|
+
|
|
11
|
+
display: inline-flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
gap: var(--juno-gap-control);
|
|
15
|
+
min-height: var(--juno-size-tap-min);
|
|
16
|
+
font-family: var(--juno-font-family-sans);
|
|
17
|
+
font-size: var(--juno-font-size-13);
|
|
18
|
+
font-weight: var(--juno-font-weight-bold);
|
|
19
|
+
letter-spacing: var(--juno-font-tracking-caps);
|
|
20
|
+
text-transform: uppercase;
|
|
21
|
+
padding: var(--juno-pad-control-block) var(--juno-pad-control-inline);
|
|
22
|
+
border: var(--juno-border-width-1) solid transparent;
|
|
23
|
+
border-radius: var(--juno-radius-4);
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
|
|
26
|
+
/* primary (filled) */
|
|
27
|
+
background: var(--juno-role);
|
|
28
|
+
color: var(--juno-s0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.juno-btn:hover { filter: brightness(1.08); }
|
|
32
|
+
.juno-btn:active { filter: brightness(0.94); }
|
|
33
|
+
|
|
34
|
+
.juno-btn--ghost {
|
|
35
|
+
background: transparent;
|
|
36
|
+
color: var(--juno-data);
|
|
37
|
+
border-color: var(--juno-border);
|
|
38
|
+
font-weight: var(--juno-font-weight-semibold);
|
|
39
|
+
}
|
|
40
|
+
.juno-btn--ghost:hover { background: var(--juno-s2); filter: none; }
|
|
41
|
+
|
|
42
|
+
/* Small — for dense desktop toolbars (40–46px bars) where the default
|
|
43
|
+
control would not fit. Deliberately under the WCAG tap-min target:
|
|
44
|
+
keep the default size for touch surfaces. Combines with --ghost + roles. */
|
|
45
|
+
.juno-btn--sm {
|
|
46
|
+
min-height: var(--juno-space-24);
|
|
47
|
+
font-size: var(--juno-font-size-11);
|
|
48
|
+
letter-spacing: var(--juno-font-tracking-wide);
|
|
49
|
+
padding: var(--juno-space-4) var(--juno-space-10);
|
|
50
|
+
border-radius: var(--juno-radius-3);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.juno-btn:disabled {
|
|
54
|
+
background: var(--juno-muted);
|
|
55
|
+
color: var(--juno-label);
|
|
56
|
+
border-color: transparent;
|
|
57
|
+
cursor: not-allowed;
|
|
58
|
+
filter: none;
|
|
59
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Card / panel
|
|
3
|
+
* Usage:
|
|
4
|
+
* <article class="juno-card">
|
|
5
|
+
* <header class="juno-card__head">…<span class="juno-badge …">…</span></header>
|
|
6
|
+
* <div class="juno-card__body">…</div>
|
|
7
|
+
* </article>
|
|
8
|
+
* Add a status accent edge: <article class="juno-card juno-card--accent juno--caution">
|
|
9
|
+
* Critical full-border: <article class="juno-card juno-card--alert juno--warning">
|
|
10
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
11
|
+
|
|
12
|
+
.juno-card {
|
|
13
|
+
--juno-role: var(--juno-active);
|
|
14
|
+
|
|
15
|
+
background: var(--juno-s1);
|
|
16
|
+
border: var(--juno-border-width-1) solid var(--juno-border);
|
|
17
|
+
border-radius: var(--juno-radius-8);
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
container-type: inline-size; /* rows below adapt to the card's own width */
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* When the card itself is narrow, stack label/value rows. Driven by the
|
|
23
|
+
card's container width, not the viewport — works in any layout. */
|
|
24
|
+
@container (max-width: 320px) {
|
|
25
|
+
.juno-card__row {
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
gap: var(--juno-space-2);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.juno-card--accent { border-top: var(--juno-border-width-2) solid var(--juno-role); }
|
|
33
|
+
|
|
34
|
+
.juno-card--alert { border-color: var(--juno-role); border-top-width: var(--juno-border-width-2); }
|
|
35
|
+
|
|
36
|
+
.juno-card__head {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: space-between;
|
|
40
|
+
gap: var(--juno-space-8);
|
|
41
|
+
padding: var(--juno-space-12) var(--juno-space-16);
|
|
42
|
+
border-bottom: var(--juno-border-width-1) solid var(--juno-border);
|
|
43
|
+
font-size: var(--juno-font-size-12);
|
|
44
|
+
font-weight: var(--juno-font-weight-semibold);
|
|
45
|
+
letter-spacing: var(--juno-font-tracking-wide);
|
|
46
|
+
text-transform: uppercase;
|
|
47
|
+
color: var(--juno-data);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.juno-card--alert .juno-card__head {
|
|
51
|
+
background: var(--juno-s2);
|
|
52
|
+
border-bottom-color: var(--juno-role);
|
|
53
|
+
color: var(--juno-role);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.juno-card__body {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
gap: var(--juno-space-12);
|
|
60
|
+
padding: var(--juno-pad-surface-block) var(--juno-pad-surface-inline);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Label / value row inside a card body */
|
|
64
|
+
.juno-card__row {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: baseline;
|
|
67
|
+
justify-content: space-between;
|
|
68
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Checkbox & Radio
|
|
3
|
+
* Custom-styled native inputs (appearance:none) — keyboard + screen-reader
|
|
4
|
+
* native, zero JS. Checkbox is a targeting-reticle square whose solid core
|
|
5
|
+
* drops in on check; radio is a ring with a center dot. Default tint ACTIVE.
|
|
6
|
+
* Wrap with .juno-choice for an inline label row.
|
|
7
|
+
* Usage:
|
|
8
|
+
* <label class="juno-choice">
|
|
9
|
+
* <input class="juno-checkbox" type="checkbox" checked /> TCAS
|
|
10
|
+
* </label>
|
|
11
|
+
* <label class="juno-choice">
|
|
12
|
+
* <input class="juno-radio" type="radio" name="mode" /> MANAGED
|
|
13
|
+
* </label>
|
|
14
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
15
|
+
|
|
16
|
+
.juno-choice {
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: var(--juno-gap-control);
|
|
20
|
+
font-family: var(--juno-font-family-sans);
|
|
21
|
+
font-size: var(--juno-font-size-13);
|
|
22
|
+
color: var(--juno-data);
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.juno-checkbox,
|
|
27
|
+
.juno-radio {
|
|
28
|
+
--juno-role: var(--juno-active);
|
|
29
|
+
|
|
30
|
+
appearance: none;
|
|
31
|
+
margin: 0;
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
inline-size: var(--juno-space-16);
|
|
34
|
+
block-size: var(--juno-space-16);
|
|
35
|
+
display: inline-grid;
|
|
36
|
+
place-content: center;
|
|
37
|
+
background: var(--juno-control-surface);
|
|
38
|
+
border: var(--juno-border-width-1) solid var(--juno-control-edge-strong);
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
transition:
|
|
41
|
+
border-color var(--juno-motion-duration-quick) var(--juno-motion-ease-standard),
|
|
42
|
+
box-shadow var(--juno-motion-duration-quick) var(--juno-motion-ease-standard);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.juno-checkbox { border-radius: var(--juno-radius-2); }
|
|
46
|
+
.juno-radio { border-radius: 50%; }
|
|
47
|
+
|
|
48
|
+
/* the core / dot — drops in on check with a slight overshoot */
|
|
49
|
+
.juno-checkbox::before,
|
|
50
|
+
.juno-radio::before {
|
|
51
|
+
content: '';
|
|
52
|
+
inline-size: var(--juno-space-8);
|
|
53
|
+
block-size: var(--juno-space-8);
|
|
54
|
+
background: var(--juno-role);
|
|
55
|
+
transform: scale(0);
|
|
56
|
+
transition: transform var(--juno-motion-duration-quick) var(--juno-motion-ease-spring);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.juno-checkbox::before { border-radius: 1px; }
|
|
60
|
+
.juno-radio::before { border-radius: 50%; }
|
|
61
|
+
|
|
62
|
+
.juno-checkbox:checked,
|
|
63
|
+
.juno-radio:checked {
|
|
64
|
+
border-color: var(--juno-role);
|
|
65
|
+
box-shadow: 0 0 0 var(--juno-border-width-3) color-mix(in srgb, var(--juno-role) 22%, transparent);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.juno-checkbox:checked::before,
|
|
69
|
+
.juno-radio:checked::before { transform: scale(1); }
|
|
70
|
+
|
|
71
|
+
/* indeterminate (e.g. a "select all" with a partial set) — a dash, not a core */
|
|
72
|
+
.juno-checkbox:indeterminate {
|
|
73
|
+
border-color: var(--juno-role);
|
|
74
|
+
box-shadow: 0 0 0 var(--juno-border-width-3) color-mix(in srgb, var(--juno-role) 22%, transparent);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.juno-checkbox:indeterminate::before {
|
|
78
|
+
transform: scale(1);
|
|
79
|
+
block-size: 2px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.juno-checkbox:disabled,
|
|
83
|
+
.juno-radio:disabled {
|
|
84
|
+
background: var(--juno-s1);
|
|
85
|
+
opacity: var(--juno-opacity-disabled);
|
|
86
|
+
cursor: not-allowed;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.juno-choice:has(:disabled) { color: var(--juno-muted); cursor: not-allowed; }
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Chip / Tag · compact interactive token
|
|
3
|
+
* A pill that represents a discrete entity: a filter, a selected value,
|
|
4
|
+
* a removable tag. Unlike a badge (a static status label), a chip is
|
|
5
|
+
* interactive — selectable and/or dismissible. Reads --juno-role for its
|
|
6
|
+
* accent. Use a <button> for a toggle chip; add a remove button for a
|
|
7
|
+
* dismissible one. Zero JS — the app owns selection / removal.
|
|
8
|
+
* Usage:
|
|
9
|
+
* <span class="juno-chip">us-east-1</span>
|
|
10
|
+
* <button class="juno-chip juno-chip--toggle" aria-pressed="true">Active</button>
|
|
11
|
+
* <span class="juno-chip juno--active">
|
|
12
|
+
* filter:prod
|
|
13
|
+
* <button class="juno-chip__remove" aria-label="Remove">
|
|
14
|
+
* <svg class="juno-icon juno-icon--sm"><use href="…#juno-i-x" /></svg>
|
|
15
|
+
* </button>
|
|
16
|
+
* </span>
|
|
17
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
18
|
+
|
|
19
|
+
.juno-chip {
|
|
20
|
+
--juno-role: var(--juno-label);
|
|
21
|
+
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: var(--juno-space-8);
|
|
25
|
+
block-size: var(--juno-space-24);
|
|
26
|
+
padding-inline: var(--juno-space-12);
|
|
27
|
+
border: var(--juno-border-width-1) solid var(--juno-control-edge-strong);
|
|
28
|
+
border-radius: 999px;
|
|
29
|
+
background: var(--juno-control-surface);
|
|
30
|
+
color: var(--juno-data);
|
|
31
|
+
font-family: var(--juno-font-family-sans);
|
|
32
|
+
font-size: var(--juno-font-size-12);
|
|
33
|
+
letter-spacing: var(--juno-font-tracking-tight);
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* leading accent dot — reads the role; appears when a role class is set */
|
|
38
|
+
.juno-chip.juno--nominal,
|
|
39
|
+
.juno-chip.juno--active,
|
|
40
|
+
.juno-chip.juno--target,
|
|
41
|
+
.juno-chip.juno--caution,
|
|
42
|
+
.juno-chip.juno--warning {
|
|
43
|
+
border-color: var(--juno-role);
|
|
44
|
+
color: var(--juno-role);
|
|
45
|
+
background: color-mix(in srgb, var(--juno-role) 12%, var(--juno-control-surface));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* toggle chip — a real <button>; pressed = filled accent */
|
|
49
|
+
button.juno-chip {
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
transition:
|
|
52
|
+
border-color var(--juno-motion-duration-quick) var(--juno-motion-ease-standard),
|
|
53
|
+
background-color var(--juno-motion-duration-quick) var(--juno-motion-ease-standard);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.juno-chip--toggle[aria-pressed='true'] {
|
|
57
|
+
border-color: var(--juno-role);
|
|
58
|
+
background: color-mix(in srgb, var(--juno-role) 18%, var(--juno-control-surface));
|
|
59
|
+
color: var(--juno-role);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.juno-chip:focus-visible {
|
|
63
|
+
outline: var(--juno-border-width-2) solid var(--juno-active);
|
|
64
|
+
outline-offset: var(--juno-space-2);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* remove affordance — a tiny inset button at the trailing edge */
|
|
68
|
+
.juno-chip__remove {
|
|
69
|
+
display: inline-grid;
|
|
70
|
+
place-content: center;
|
|
71
|
+
margin-inline-end: calc(var(--juno-space-4) * -1);
|
|
72
|
+
padding: 0;
|
|
73
|
+
border: 0;
|
|
74
|
+
background: none;
|
|
75
|
+
color: inherit;
|
|
76
|
+
opacity: var(--juno-opacity-muted);
|
|
77
|
+
cursor: pointer;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.juno-chip__remove:hover,
|
|
81
|
+
.juno-chip__remove:focus-visible {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.juno-chip:disabled,
|
|
86
|
+
.juno-chip[aria-disabled='true'] {
|
|
87
|
+
opacity: var(--juno-opacity-disabled);
|
|
88
|
+
cursor: not-allowed;
|
|
89
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Divider · visual / semantic separation
|
|
3
|
+
* A hairline rule. Horizontal by default; add --vertical for a column
|
|
4
|
+
* separator (stretches to the row's cross size). An optional centered
|
|
5
|
+
* label breaks the rule in two ("OR", "MORE"). Use a real <hr> for a
|
|
6
|
+
* semantic break, or a styled element when it's purely visual.
|
|
7
|
+
* Usage:
|
|
8
|
+
* <hr class="juno-divider" />
|
|
9
|
+
* <div class="juno-divider juno-divider--label">OR</div>
|
|
10
|
+
* <span class="juno-divider juno-divider--vertical"></span>
|
|
11
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
12
|
+
|
|
13
|
+
.juno-divider {
|
|
14
|
+
border: 0;
|
|
15
|
+
margin: 0;
|
|
16
|
+
block-size: var(--juno-border-width-1);
|
|
17
|
+
inline-size: 100%;
|
|
18
|
+
background: var(--juno-border);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* vertical rule — sits inline; relies on the parent giving it block size */
|
|
22
|
+
.juno-divider--vertical {
|
|
23
|
+
inline-size: var(--juno-border-width-1);
|
|
24
|
+
block-size: auto;
|
|
25
|
+
align-self: stretch;
|
|
26
|
+
min-block-size: var(--juno-space-16);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* labeled rule — a centered caption with a line on each side */
|
|
30
|
+
.juno-divider--label {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: center;
|
|
33
|
+
gap: var(--juno-space-12);
|
|
34
|
+
border: 0;
|
|
35
|
+
background: none;
|
|
36
|
+
block-size: auto;
|
|
37
|
+
color: var(--juno-label);
|
|
38
|
+
font-family: var(--juno-font-family-sans);
|
|
39
|
+
font-size: var(--juno-font-size-11);
|
|
40
|
+
letter-spacing: var(--juno-font-tracking-label);
|
|
41
|
+
text-transform: uppercase;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.juno-divider--label::before,
|
|
45
|
+
.juno-divider--label::after {
|
|
46
|
+
content: '';
|
|
47
|
+
flex: 1;
|
|
48
|
+
block-size: var(--juno-border-width-1);
|
|
49
|
+
background: var(--juno-border);
|
|
50
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Dock (app-shell bottom navigation)
|
|
3
|
+
* The narrow-viewport counterpart of the rail: 3–5 primary destinations
|
|
4
|
+
* as icon-over-label tap targets pinned to the bottom edge. Zero JS —
|
|
5
|
+
* the app sets aria-current="page"; the active item styles off the
|
|
6
|
+
* attribute, exactly like the rail.
|
|
7
|
+
*
|
|
8
|
+
* Sticky (not fixed) so it stays in flow: put it last inside the
|
|
9
|
+
* scrolling column and it pins itself without overlapping content.
|
|
10
|
+
* Pads for the home-indicator via safe-area-inset. Pair with the rail
|
|
11
|
+
* using the viewport helpers (see docs/layout.md#app-shell):
|
|
12
|
+
* <nav class="juno-rail juno-hide-below-md" …>
|
|
13
|
+
* <nav class="juno-dock juno-hide-from-md" aria-label="Primary">
|
|
14
|
+
* <a class="juno-dock__item" href="…" aria-current="page">
|
|
15
|
+
* <svg class="juno-icon" aria-hidden="true"><use href="…#juno-i-squares-four" /></svg>
|
|
16
|
+
* <span class="juno-dock__label">Library</span>
|
|
17
|
+
* </a>
|
|
18
|
+
* </nav>
|
|
19
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
20
|
+
|
|
21
|
+
.juno-dock {
|
|
22
|
+
--juno-role: var(--juno-active);
|
|
23
|
+
|
|
24
|
+
position: sticky;
|
|
25
|
+
inset-block-end: 0;
|
|
26
|
+
z-index: var(--juno-z-raised);
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: stretch;
|
|
29
|
+
background: var(--juno-s1);
|
|
30
|
+
border-block-start: var(--juno-border-width-1) solid var(--juno-border);
|
|
31
|
+
padding-block-end: env(safe-area-inset-bottom, 0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.juno-dock__item {
|
|
35
|
+
flex: 1 1 0;
|
|
36
|
+
min-inline-size: 0;
|
|
37
|
+
min-block-size: var(--juno-size-tap-comfortable);
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
gap: var(--juno-space-2);
|
|
43
|
+
padding-block: var(--juno-space-4);
|
|
44
|
+
border-block-start: var(--juno-border-width-2) solid transparent;
|
|
45
|
+
font-family: var(--juno-font-family-sans);
|
|
46
|
+
font-size: var(--juno-font-size-10);
|
|
47
|
+
font-weight: var(--juno-font-weight-semibold);
|
|
48
|
+
letter-spacing: var(--juno-font-tracking-label);
|
|
49
|
+
text-transform: uppercase;
|
|
50
|
+
text-decoration: none;
|
|
51
|
+
color: var(--juno-label);
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.juno-dock__label {
|
|
56
|
+
max-inline-size: 100%;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
text-overflow: ellipsis;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.juno-dock__item:hover { color: var(--juno-data); }
|
|
63
|
+
|
|
64
|
+
/* active = attribute, not class: <a aria-current="page"> */
|
|
65
|
+
.juno-dock__item[aria-current] {
|
|
66
|
+
border-block-start-color: var(--juno-role);
|
|
67
|
+
background: var(--juno-s2);
|
|
68
|
+
color: var(--juno-data);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.juno-dock__item:focus-visible {
|
|
72
|
+
outline: var(--juno-border-width-2) solid var(--juno-active);
|
|
73
|
+
outline-offset: calc(-1 * var(--juno-space-2));
|
|
74
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Status dot + label
|
|
3
|
+
* Usage:
|
|
4
|
+
* <span class="juno-status juno--nominal">
|
|
5
|
+
* <span class="juno-status__dot"></span>NOMINAL
|
|
6
|
+
* </span>
|
|
7
|
+
* Pair color with the text label — color is never the sole signal.
|
|
8
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
9
|
+
|
|
10
|
+
.juno-status {
|
|
11
|
+
--juno-role: var(--juno-nominal);
|
|
12
|
+
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: var(--juno-space-8);
|
|
16
|
+
font-size: var(--juno-font-size-12);
|
|
17
|
+
letter-spacing: var(--juno-font-tracking-label);
|
|
18
|
+
color: var(--juno-role);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.juno-status__dot {
|
|
22
|
+
width: var(--juno-size-dot-sm);
|
|
23
|
+
height: var(--juno-size-dot-sm);
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
background: var(--juno-role);
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.juno-status--lg .juno-status__dot {
|
|
30
|
+
width: var(--juno-size-dot-md);
|
|
31
|
+
height: var(--juno-size-dot-md);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Live/armed pulse — respects prefers-reduced-motion via base layer. */
|
|
35
|
+
.juno-status--live .juno-status__dot { animation: juno-blink 1.4s ease-in-out infinite; }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* ════════════════════════════════════════════════════════════════════
|
|
2
|
+
* Component — Drawer
|
|
3
|
+
* Edge-anchored <dialog> for secondary tasks and settings. Same scrim and
|
|
4
|
+
* layer as the modal, but slides along one axis. App owns showModal()/close().
|
|
5
|
+
* Default anchors to the inline-end edge; modifiers move it.
|
|
6
|
+
* Usage:
|
|
7
|
+
* <dialog class="juno-modal juno-drawer">…</dialog> (inline-end)
|
|
8
|
+
* <dialog class="juno-modal juno-drawer juno-drawer--start">…</dialog>
|
|
9
|
+
* <dialog class="juno-modal juno-drawer juno-drawer--bottom">…</dialog>
|
|
10
|
+
* Reuses .juno-modal for the surface + scrim; this file re-pins + re-slides.
|
|
11
|
+
* Selectors are compound (.juno-modal.juno-drawer) so they override the
|
|
12
|
+
* modal's centered transform regardless of bundle order.
|
|
13
|
+
* ════════════════════════════════════════════════════════════════════ */
|
|
14
|
+
|
|
15
|
+
.juno-modal.juno-drawer {
|
|
16
|
+
inline-size: 380px;
|
|
17
|
+
max-inline-size: 100%;
|
|
18
|
+
block-size: 100dvh;
|
|
19
|
+
max-block-size: 100dvh;
|
|
20
|
+
border-radius: 0;
|
|
21
|
+
border: none;
|
|
22
|
+
|
|
23
|
+
/* pin to the inline-end edge (mirrors under RTL) */
|
|
24
|
+
margin-block: 0;
|
|
25
|
+
margin-inline: auto 0;
|
|
26
|
+
border-inline-start: var(--juno-border-width-1) solid var(--juno-border);
|
|
27
|
+
|
|
28
|
+
/* slide in from the edge; base speed (lighter than a modal) */
|
|
29
|
+
transform: translateX(100%);
|
|
30
|
+
transition:
|
|
31
|
+
transform var(--juno-motion-duration-base) var(--juno-motion-ease-decel),
|
|
32
|
+
overlay var(--juno-motion-duration-base) allow-discrete,
|
|
33
|
+
display var(--juno-motion-duration-base) allow-discrete;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.juno-modal.juno-drawer[open] { transform: translateX(0); }
|
|
37
|
+
|
|
38
|
+
@starting-style {
|
|
39
|
+
.juno-modal.juno-drawer[open] { transform: translateX(100%); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.juno-modal.juno-drawer--start {
|
|
43
|
+
margin-inline: 0 auto;
|
|
44
|
+
border-inline: none;
|
|
45
|
+
border-inline-end: var(--juno-border-width-1) solid var(--juno-border);
|
|
46
|
+
transform: translateX(-100%);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.juno-modal.juno-drawer--start[open] { transform: translateX(0); }
|
|
50
|
+
|
|
51
|
+
@starting-style {
|
|
52
|
+
.juno-modal.juno-drawer--start[open] { transform: translateX(-100%); }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.juno-modal.juno-drawer--bottom {
|
|
56
|
+
inline-size: 100%;
|
|
57
|
+
max-inline-size: 100%;
|
|
58
|
+
block-size: 60dvh;
|
|
59
|
+
margin-block: auto 0;
|
|
60
|
+
margin-inline: 0;
|
|
61
|
+
border: none;
|
|
62
|
+
border-block-start: var(--juno-border-width-1) solid var(--juno-border);
|
|
63
|
+
transform: translateY(100%);
|
|
64
|
+
|
|
65
|
+
/* keep content above the home indicator */
|
|
66
|
+
padding-block-end: env(safe-area-inset-bottom, 0);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.juno-modal.juno-drawer--bottom[open] { transform: translateY(0); }
|
|
70
|
+
|
|
71
|
+
@starting-style {
|
|
72
|
+
.juno-modal.juno-drawer--bottom[open] { transform: translateY(100%); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* ── narrow viewports ────────────────────────────────────────────────────
|
|
76
|
+
Side drawers cap below the full width so a sliver of scrim survives —
|
|
77
|
+
the visual cue (and tap target) that "outside" closes the panel. */
|
|
78
|
+
@media (width <= 639.98px) {
|
|
79
|
+
.juno-modal.juno-drawer:not(.juno-drawer--bottom) { inline-size: min(380px, 85vw); }
|
|
80
|
+
}
|