@greendrake/theme 0.6.0 → 0.8.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/README.md +1 -1
- package/_index.scss +2 -43
- package/_mixins.scss +15 -13
- package/dashboard.scss +12 -1
- package/editor-rows.scss +26 -2
- package/form-controls.scss +1 -2
- package/package.json +10 -5
- package/spinner.scss +49 -0
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ An app not on the dashboard palette defines the palette group itself: this packa
|
|
|
76
76
|
|
|
77
77
|
## Global spinner
|
|
78
78
|
|
|
79
|
-
This package defines the `spinner` keyframes and the `.spinner` / `body.spinner`
|
|
79
|
+
This package defines the `spinner` keyframes, `--spinner-size` (40px) and the `.spinner` / `body.spinner` rules, for components that show progress by toggling a `spinner` class and for `@greendrake/scss-kit`'s `img-spinner` mixin: a ring at the centre of the element, or of the viewport for `body`. They consume `--spinner-color` (palette) and `--spinner-side-color` (app). They are the `spinner` entry, which the root entry includes; an app not on this theme can `@use '@greendrake/theme/spinner'` alone, defining the two colours itself.
|
|
80
80
|
|
|
81
81
|
## Not included
|
|
82
82
|
|
package/_index.scss
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// This entry EMITS global CSS (the reset, base element styles, the :root
|
|
2
|
-
// design tokens). It is the app-level base — `@use` it ONCE from the app's
|
|
2
|
+
// design tokens, the spinner). It is the app-level base — `@use` it ONCE from the app's
|
|
3
3
|
// main.scss. A component that needs only a mixin must `@use
|
|
4
4
|
// '@greendrake/theme/mixins'` (side-effect-free); importing this module from a
|
|
5
5
|
// per-component <style> re-emits the reset into a late stylesheet that
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
@use '@greendrake/css-reset';
|
|
8
8
|
@use '@greendrake/scss-kit' as kit;
|
|
9
9
|
@use 'mixins';
|
|
10
|
+
@use 'spinner';
|
|
10
11
|
@forward 'mixins';
|
|
11
12
|
|
|
12
13
|
:root {
|
|
@@ -49,11 +50,6 @@
|
|
|
49
50
|
--error-color: #ff4800;
|
|
50
51
|
--warning-color: #890095;
|
|
51
52
|
--accent-color: #0aa13e;
|
|
52
|
-
|
|
53
|
-
// Single source of truth for spinner ring size — the default centred
|
|
54
|
-
// spinner shown at the middle of a loading UI. The small in-control variant
|
|
55
|
-
// overrides this (see button.spinner in form-controls).
|
|
56
|
-
--spinner-size: 40px;
|
|
57
53
|
}
|
|
58
54
|
|
|
59
55
|
body {
|
|
@@ -135,40 +131,3 @@ blockquote {
|
|
|
135
131
|
[inert] {
|
|
136
132
|
@include kit.disabled;
|
|
137
133
|
}
|
|
138
|
-
|
|
139
|
-
@keyframes spinner {
|
|
140
|
-
to {
|
|
141
|
-
transform: rotate(360deg);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.spinner:not(.splash) {
|
|
146
|
-
position: relative;
|
|
147
|
-
&::before {
|
|
148
|
-
content: '';
|
|
149
|
-
box-sizing: border-box;
|
|
150
|
-
position: absolute;
|
|
151
|
-
border-radius: 50%;
|
|
152
|
-
z-index: kit.z('spinner');
|
|
153
|
-
border: 2px solid var(--spinner-color);
|
|
154
|
-
border-top-color: var(--spinner-side-color);
|
|
155
|
-
animation: spinner 0.6s linear infinite;
|
|
156
|
-
top: 50%;
|
|
157
|
-
left: 50%;
|
|
158
|
-
// Size from the single-source token, centred via negative
|
|
159
|
-
// half-margins. Applies to any host element — div, section, aside,
|
|
160
|
-
// ul — rather than a fixed list of them.
|
|
161
|
-
width: var(--spinner-size);
|
|
162
|
-
height: var(--spinner-size);
|
|
163
|
-
margin-top: calc(var(--spinner-size) / -2);
|
|
164
|
-
margin-left: calc(var(--spinner-size) / -2);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Full-page spinner: pin to the viewport centre rather than the host element.
|
|
169
|
-
// Size and centring come from the base rule above. body::before belongs to
|
|
170
|
-
// this spinner alone — the page vignette hangs off html::before precisely so
|
|
171
|
-
// the two can never share one pseudo-element (page-vignette in _mixins.scss).
|
|
172
|
-
body:not(.splash).spinner::before {
|
|
173
|
-
position: fixed;
|
|
174
|
-
}
|
package/_mixins.scss
CHANGED
|
@@ -35,7 +35,7 @@ $max-content-width: 850px;
|
|
|
35
35
|
//
|
|
36
36
|
// It hangs off <html>, not <body>: an element has exactly one ::before, and
|
|
37
37
|
// body's belongs to the full-page loading spinner (`body.spinner::before`, see
|
|
38
|
-
//
|
|
38
|
+
// spinner.scss). Sharing it made the two fight — the spinner ring inherited the
|
|
39
39
|
// vignette's page-sized inset shadow, and the vignette vanished for the
|
|
40
40
|
// duration of every page load. The canvas is html's job anyway; it already
|
|
41
41
|
// carries the page background above.
|
|
@@ -78,8 +78,15 @@ $max-content-width: 850px;
|
|
|
78
78
|
// colour of its own but a second copy of the page canvas on its own
|
|
79
79
|
// viewport-anchored box, masked down to the strip the bar occupies: where it is
|
|
80
80
|
// opaque it is indistinguishable from the page behind it, vignette falloff
|
|
81
|
-
// included.
|
|
82
|
-
//
|
|
81
|
+
// included.
|
|
82
|
+
//
|
|
83
|
+
// Included on an element of its own: the bar's preceding sibling, at the bar's
|
|
84
|
+
// z-index, so tree order paints it directly under the bar. Never the bar's own
|
|
85
|
+
// ::before — a sticky bar is a stacking context, and a fixed layer inside it
|
|
86
|
+
// lies beneath everything the bar holds. WebKit then composites any transformed
|
|
87
|
+
// child overlapping that layer onto a layer of its own, rasterised at the
|
|
88
|
+
// child's untransformed size, so a child scaled up (the header's parked brand
|
|
89
|
+
// mark) is drawn as an upscaled bitmap.
|
|
83
90
|
//
|
|
84
91
|
// $edge is the viewport edge the bar is stuck to. The mask holds full opacity
|
|
85
92
|
// for $solid from that edge — the band the bar's content occupies — then takes
|
|
@@ -95,15 +102,11 @@ $max-content-width: 850px;
|
|
|
95
102
|
@if $edge == top {
|
|
96
103
|
$away: bottom;
|
|
97
104
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
pointer-events: none;
|
|
104
|
-
@include page-canvas;
|
|
105
|
-
mask-image: linear-gradient(to #{$away}, #000 #{$solid}, transparent calc(#{$solid} + #{$ramp}));
|
|
106
|
-
}
|
|
105
|
+
position: fixed;
|
|
106
|
+
inset: 0;
|
|
107
|
+
pointer-events: none;
|
|
108
|
+
@include page-canvas;
|
|
109
|
+
mask-image: linear-gradient(to #{$away}, #000 #{$solid}, transparent calc(#{$solid} + #{$ramp}));
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
@mixin button-colors {
|
|
@@ -129,7 +132,6 @@ $max-content-width: 850px;
|
|
|
129
132
|
color: #fff;
|
|
130
133
|
border: 0;
|
|
131
134
|
padding: 0;
|
|
132
|
-
cursor: pointer;
|
|
133
135
|
line-height: $size;
|
|
134
136
|
font-size: calc($size * 0.55);
|
|
135
137
|
&:hover {
|
package/dashboard.scss
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
:root {
|
|
13
13
|
--border-radius: 4px;
|
|
14
|
+
--border-radius-pill: 999px;
|
|
14
15
|
--icon-size: 18px;
|
|
15
16
|
// Denser base than the document default: dashboards are dense,
|
|
16
17
|
// information-first surfaces.
|
|
@@ -34,12 +35,22 @@ a:hover {
|
|
|
34
35
|
color: var(--link-color-hover);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
label
|
|
38
|
+
// Captions: a bare <label>, and a Field's caption, which is in its <label> or, for a
|
|
39
|
+
// control a label cannot name, stands alone. A Field's <label> also wraps the control
|
|
40
|
+
// itself, which keeps its own look.
|
|
41
|
+
label,
|
|
42
|
+
.Field__caption {
|
|
38
43
|
font-size: var(--font-xs);
|
|
39
44
|
font-weight: 500;
|
|
40
45
|
opacity: 0.7;
|
|
41
46
|
}
|
|
42
47
|
|
|
48
|
+
.Field > label {
|
|
49
|
+
font-size: inherit;
|
|
50
|
+
font-weight: inherit;
|
|
51
|
+
opacity: 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
// Headings read as panel/section dividers rather than page titles — every
|
|
44
55
|
// dashboard panel opens with one, and detail views nest h2/h3 under it.
|
|
45
56
|
h1,
|
package/editor-rows.scss
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Opt-in record-editor/detail-pane layout: `@use '@greendrake/theme/editor-rows';`
|
|
2
2
|
// (the dashboard preset pulls it in). `.EditorRows` is the padded scrolling
|
|
3
|
-
// pane, `.EditorRows__row` a label/value line
|
|
4
|
-
// a
|
|
3
|
+
// pane, `.EditorRows__row` a label/value line; `.EditorRows--dense` packs the
|
|
4
|
+
// rows of a read-only pane tighter than an editor's. The classes are
|
|
5
|
+
// independent: a component whose root layout diverges may adopt the rows alone.
|
|
5
6
|
|
|
6
7
|
.EditorRows {
|
|
7
8
|
padding: var(--space-4);
|
|
@@ -23,5 +24,28 @@
|
|
|
23
24
|
}
|
|
24
25
|
> div {
|
|
25
26
|
flex-grow: 1;
|
|
27
|
+
min-width: 0;
|
|
28
|
+
word-break: break-word;
|
|
26
29
|
}
|
|
27
30
|
}
|
|
31
|
+
|
|
32
|
+
.EditorRows--dense .EditorRows__row {
|
|
33
|
+
padding: var(--space-1) 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A value too long or too literal for a line — an error trace, a raw body,
|
|
37
|
+
// template data: monospace, wrapped, and scrolling within a bounded box.
|
|
38
|
+
.EditorRows__pre {
|
|
39
|
+
flex: 1;
|
|
40
|
+
min-width: 0;
|
|
41
|
+
margin: 0;
|
|
42
|
+
padding: var(--space-2);
|
|
43
|
+
background: var(--form-background);
|
|
44
|
+
border: 1px solid var(--border-color);
|
|
45
|
+
border-radius: var(--border-radius);
|
|
46
|
+
white-space: pre-wrap;
|
|
47
|
+
font-family: ui-monospace, monospace;
|
|
48
|
+
font-size: var(--font-xs);
|
|
49
|
+
max-height: 50vh;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
}
|
package/form-controls.scss
CHANGED
|
@@ -13,8 +13,8 @@ textarea {
|
|
|
13
13
|
border: 1px solid var(--border-color);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// A button keeps the default cursor: the hand is a hyperlink's.
|
|
16
17
|
button {
|
|
17
|
-
cursor: pointer;
|
|
18
18
|
padding: var(--space-1) var(--space-4);
|
|
19
19
|
&:hover:not(:disabled) {
|
|
20
20
|
border-color: var(--border-color-hover);
|
|
@@ -22,7 +22,6 @@ button {
|
|
|
22
22
|
}
|
|
23
23
|
&:disabled {
|
|
24
24
|
opacity: 0.5;
|
|
25
|
-
cursor: default;
|
|
26
25
|
}
|
|
27
26
|
}
|
|
28
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@greendrake/theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Design tokens, document-level element styling, a light/dark theming mixin and an opt-in dashboard palette",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eugene Greendrake <eugene@greendrake.nz>",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"./dashboard": {
|
|
40
40
|
"sass": "./dashboard.scss",
|
|
41
41
|
"default": "./dashboard.scss"
|
|
42
|
+
},
|
|
43
|
+
"./spinner": {
|
|
44
|
+
"sass": "./spinner.scss",
|
|
45
|
+
"default": "./spinner.scss"
|
|
42
46
|
}
|
|
43
47
|
},
|
|
44
48
|
"files": [
|
|
@@ -47,17 +51,18 @@
|
|
|
47
51
|
"dashboard-palette.scss",
|
|
48
52
|
"form-controls.scss",
|
|
49
53
|
"editor-rows.scss",
|
|
50
|
-
"dashboard.scss"
|
|
54
|
+
"dashboard.scss",
|
|
55
|
+
"spinner.scss"
|
|
51
56
|
],
|
|
52
57
|
"publishConfig": {
|
|
53
58
|
"access": "public"
|
|
54
59
|
},
|
|
55
60
|
"prettier": "@greendrake/dev-config/prettier",
|
|
56
61
|
"dependencies": {
|
|
57
|
-
"@greendrake/css-reset": "0.
|
|
58
|
-
"@greendrake/scss-kit": "0.
|
|
62
|
+
"@greendrake/css-reset": "^0.7.0",
|
|
63
|
+
"@greendrake/scss-kit": "^0.8.0"
|
|
59
64
|
},
|
|
60
65
|
"devDependencies": {
|
|
61
|
-
"@greendrake/dev-config": "0.
|
|
66
|
+
"@greendrake/dev-config": "0.7.0"
|
|
62
67
|
}
|
|
63
68
|
}
|
package/spinner.scss
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The spinner: a ring at the centre of whatever element has the `spinner` class while
|
|
2
|
+
// what it shows is on its way, or of the viewport for <body>. This entry EMITS global
|
|
3
|
+
// CSS. The root entry has it; an app not on this theme can `@use` it alone, defining
|
|
4
|
+
// --spinner-color and --spinner-side-color itself.
|
|
5
|
+
@use '@greendrake/scss-kit' as kit;
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
// Single source of truth for spinner ring size — the default centred
|
|
9
|
+
// spinner shown at the middle of a loading UI. The small in-control variant
|
|
10
|
+
// overrides this (see button.spinner in form-controls).
|
|
11
|
+
--spinner-size: 40px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@keyframes spinner {
|
|
15
|
+
to {
|
|
16
|
+
transform: rotate(360deg);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.spinner:not(.splash) {
|
|
21
|
+
position: relative;
|
|
22
|
+
&::before {
|
|
23
|
+
content: '';
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
position: absolute;
|
|
26
|
+
border-radius: 50%;
|
|
27
|
+
z-index: kit.z('spinner');
|
|
28
|
+
border: 2px solid var(--spinner-color);
|
|
29
|
+
border-top-color: var(--spinner-side-color);
|
|
30
|
+
animation: spinner 0.6s linear infinite;
|
|
31
|
+
top: 50%;
|
|
32
|
+
left: 50%;
|
|
33
|
+
// Size from the single-source token, centred via negative
|
|
34
|
+
// half-margins. Applies to any host element — div, section, aside,
|
|
35
|
+
// ul — rather than a fixed list of them.
|
|
36
|
+
width: var(--spinner-size);
|
|
37
|
+
height: var(--spinner-size);
|
|
38
|
+
margin-top: calc(var(--spinner-size) / -2);
|
|
39
|
+
margin-left: calc(var(--spinner-size) / -2);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Full-page spinner: pin to the viewport centre rather than the host element.
|
|
44
|
+
// Size and centring come from the base rule above. body::before belongs to
|
|
45
|
+
// this spinner alone — the page vignette hangs off html::before precisely so
|
|
46
|
+
// the two can never share one pseudo-element (page-vignette in _mixins.scss).
|
|
47
|
+
body:not(.splash).spinner::before {
|
|
48
|
+
position: fixed;
|
|
49
|
+
}
|