vuetiwatch 0.1.0 → 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/README.md +200 -17
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +77 -7
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +104 -15
- package/dist/plugin.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +6 -1
- package/dist/registry.js.map +1 -1
- package/dist/styles/atlas.css +99 -0
- package/dist/styles/atlas.min.css +1 -0
- package/dist/styles/atlasDark.css +99 -0
- package/dist/styles/atlasDark.min.css +1 -0
- package/dist/styles/atlasSepia.css +99 -0
- package/dist/styles/atlasSepia.min.css +1 -0
- package/dist/styles/aurora.css +97 -4
- package/dist/styles/aurora.min.css +1 -1
- package/dist/styles/brutalist.css +5 -0
- package/dist/styles/brutalist.min.css +1 -1
- package/dist/styles/calm.css +0 -4
- package/dist/styles/calm.min.css +1 -1
- package/dist/styles/candy.css +71 -0
- package/dist/styles/candy.min.css +1 -0
- package/dist/styles/clay.css +13 -0
- package/dist/styles/clay.min.css +1 -1
- package/dist/styles/core.css +239 -36
- package/dist/styles/core.min.css +1 -1
- package/dist/styles/graphite.css +29 -0
- package/dist/styles/graphite.min.css +1 -0
- package/dist/styles/morph.css +12 -0
- package/dist/styles/morph.min.css +1 -1
- package/dist/styles/neon.css +8 -0
- package/dist/styles/neon.min.css +1 -1
- package/dist/styles/sketchy.css +4 -0
- package/dist/styles/sketchy.min.css +1 -1
- package/dist/styles/soft.css +1 -12
- package/dist/styles/soft.min.css +1 -1
- package/dist/styles.css +577 -52
- package/dist/styles.min.css +1 -1
- package/dist/themes/atlas.d.ts +38 -0
- package/dist/themes/atlas.d.ts.map +1 -0
- package/dist/themes/atlas.js +203 -0
- package/dist/themes/atlas.js.map +1 -0
- package/dist/themes/atlasDark.d.ts +8 -0
- package/dist/themes/atlasDark.d.ts.map +1 -0
- package/dist/themes/atlasDark.js +64 -0
- package/dist/themes/atlasDark.js.map +1 -0
- package/dist/themes/atlasSepia.d.ts +11 -0
- package/dist/themes/atlasSepia.d.ts.map +1 -0
- package/dist/themes/atlasSepia.js +60 -0
- package/dist/themes/atlasSepia.js.map +1 -0
- package/dist/themes/aurora.d.ts.map +1 -1
- package/dist/themes/aurora.js +27 -2
- package/dist/themes/aurora.js.map +1 -1
- package/dist/themes/brutalist.d.ts.map +1 -1
- package/dist/themes/brutalist.js +26 -0
- package/dist/themes/brutalist.js.map +1 -1
- package/dist/themes/calm.d.ts.map +1 -1
- package/dist/themes/calm.js +22 -2
- package/dist/themes/calm.js.map +1 -1
- package/dist/themes/candy.d.ts +20 -0
- package/dist/themes/candy.d.ts.map +1 -0
- package/dist/themes/candy.js +142 -0
- package/dist/themes/candy.js.map +1 -0
- package/dist/themes/classic.d.ts.map +1 -1
- package/dist/themes/classic.js +2 -0
- package/dist/themes/classic.js.map +1 -1
- package/dist/themes/clay.d.ts.map +1 -1
- package/dist/themes/clay.js +22 -0
- package/dist/themes/clay.js.map +1 -1
- package/dist/themes/darkGlass.d.ts.map +1 -1
- package/dist/themes/darkGlass.js +21 -0
- package/dist/themes/darkGlass.js.map +1 -1
- package/dist/themes/graphite.d.ts +13 -0
- package/dist/themes/graphite.d.ts.map +1 -0
- package/dist/themes/graphite.js +147 -0
- package/dist/themes/graphite.js.map +1 -0
- package/dist/themes/index.d.ts +5 -0
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +5 -0
- package/dist/themes/index.js.map +1 -1
- package/dist/themes/liquidGlass.d.ts.map +1 -1
- package/dist/themes/liquidGlass.js +27 -3
- package/dist/themes/liquidGlass.js.map +1 -1
- package/dist/themes/lux.d.ts.map +1 -1
- package/dist/themes/lux.js +21 -2
- package/dist/themes/lux.js.map +1 -1
- package/dist/themes/morph.d.ts.map +1 -1
- package/dist/themes/morph.js +23 -3
- package/dist/themes/morph.js.map +1 -1
- package/dist/themes/neon.d.ts.map +1 -1
- package/dist/themes/neon.js +22 -0
- package/dist/themes/neon.js.map +1 -1
- package/dist/themes/paper.d.ts.map +1 -1
- package/dist/themes/paper.js +16 -0
- package/dist/themes/paper.js.map +1 -1
- package/dist/themes/sketchy.d.ts.map +1 -1
- package/dist/themes/sketchy.js +17 -0
- package/dist/themes/sketchy.js.map +1 -1
- package/dist/themes/slate.d.ts.map +1 -1
- package/dist/themes/slate.js +22 -1
- package/dist/themes/slate.js.map +1 -1
- package/dist/themes/soft.d.ts.map +1 -1
- package/dist/themes/soft.js +21 -2
- package/dist/themes/soft.js.map +1 -1
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util/defaults.d.ts.map +1 -1
- package/dist/util/defaults.js +11 -1
- package/dist/util/defaults.js.map +1 -1
- package/dist/util/defineTheme.d.ts.map +1 -1
- package/dist/util/defineTheme.js +11 -5
- package/dist/util/defineTheme.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +8 -2
- package/src/plugin.ts +214 -21
- package/src/registry.ts +10 -0
- package/src/styles/core.css +563 -35
- package/src/styles/index.css +4 -0
- package/src/styles/themes/_atlas.css +194 -0
- package/src/styles/themes/atlas.css +2 -0
- package/src/styles/themes/atlasDark.css +2 -0
- package/src/styles/themes/atlasSepia.css +2 -0
- package/src/styles/themes/aurora.css +151 -7
- package/src/styles/themes/brutalist.css +5 -3
- package/src/styles/themes/calm.css +0 -7
- package/src/styles/themes/candy.css +113 -0
- package/src/styles/themes/clay.css +24 -0
- package/src/styles/themes/graphite.css +63 -0
- package/src/styles/themes/liquidGlass.css +0 -2
- package/src/styles/themes/lux.css +0 -4
- package/src/styles/themes/morph.css +22 -0
- package/src/styles/themes/neon.css +8 -3
- package/src/styles/themes/paper.css +0 -2
- package/src/styles/themes/sketchy.css +9 -0
- package/src/styles/themes/slate.css +0 -4
- package/src/styles/themes/soft.css +1 -12
- package/src/themes/atlas.ts +211 -0
- package/src/themes/atlasDark.ts +64 -0
- package/src/themes/atlasSepia.ts +60 -0
- package/src/themes/aurora.ts +30 -2
- package/src/themes/brutalist.ts +29 -0
- package/src/themes/calm.ts +25 -2
- package/src/themes/candy.ts +144 -0
- package/src/themes/classic.ts +3 -0
- package/src/themes/clay.ts +24 -0
- package/src/themes/darkGlass.ts +24 -0
- package/src/themes/graphite.ts +150 -0
- package/src/themes/index.ts +5 -0
- package/src/themes/liquidGlass.ts +30 -3
- package/src/themes/lux.ts +24 -2
- package/src/themes/morph.ts +25 -3
- package/src/themes/neon.ts +25 -0
- package/src/themes/paper.ts +19 -0
- package/src/themes/sketchy.ts +20 -0
- package/src/themes/slate.ts +25 -1
- package/src/themes/soft.ts +24 -2
- package/src/types.ts +41 -0
- package/src/util/defaults.ts +12 -1
- package/src/util/defineTheme.ts +11 -5
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
box-shadow: none;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
& :is(.v-toolbar-title, .v-card-title, .v-list-subheader) {
|
|
12
11
|
letter-spacing: 0.16em;
|
|
13
12
|
text-transform: uppercase;
|
|
@@ -25,7 +24,4 @@
|
|
|
25
24
|
border: var(--v-vw-border-width) solid rgba(var(--v-border-color), 0.14);
|
|
26
25
|
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.08);
|
|
27
26
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
27
|
}
|
|
@@ -26,6 +26,19 @@
|
|
|
26
26
|
-3px -3px 6px rgba(255, 255, 255, 0.6);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* The relief is composed against this theme's own ground: a white
|
|
31
|
+
* highlight top-left, a dark shadow bottom-right. Inside a surface that
|
|
32
|
+
* paints its own colour — `color=` on a card, a coloured bar, a filled
|
|
33
|
+
* alert — the highlight has nothing to blend into and reads as a halo
|
|
34
|
+
* around the control, so the relief is dropped there and the control
|
|
35
|
+
* keeps its flat fill. Vuetify only emits `bg-*` when an author asked
|
|
36
|
+
* for a colour, so untouched surfaces are unaffected.
|
|
37
|
+
*/
|
|
38
|
+
& [class*='bg-'] :is(.v-btn.v-btn, .v-chip.v-chip) {
|
|
39
|
+
box-shadow: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
29
42
|
/* Inputs are recesses, not tiles. */
|
|
30
43
|
& :is(.v-field--variant-solo, .v-switch__track, .v-slider-track) {
|
|
31
44
|
background: rgb(var(--v-theme-background));
|
|
@@ -50,4 +63,13 @@
|
|
|
50
63
|
border-radius: 4px;
|
|
51
64
|
box-shadow: var(--vw-morph-raised);
|
|
52
65
|
}
|
|
66
|
+
|
|
67
|
+
/* The timeline is the same groove as the inputs, stood on end. */
|
|
68
|
+
& :is(.v-timeline-divider__before, .v-timeline-divider__after) {
|
|
69
|
+
box-shadow: var(--vw-morph-pressed);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
& .v-timeline-divider__dot {
|
|
73
|
+
box-shadow: var(--vw-morph-raised);
|
|
74
|
+
}
|
|
53
75
|
}
|
|
@@ -46,11 +46,16 @@
|
|
|
46
46
|
box-shadow: 0 0 14px rgba(var(--v-theme-primary), 0.55);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
49
|
& .v-expansion-panels {
|
|
53
50
|
box-shadow: 0 0 0 1px rgba(var(--v-theme-primary), 0.12);
|
|
54
51
|
}
|
|
55
52
|
|
|
53
|
+
/* The line is lit filament, and the dot is the lamp. */
|
|
54
|
+
& :is(.v-timeline-divider__before, .v-timeline-divider__after) {
|
|
55
|
+
box-shadow: 0 0 8px rgb(var(--v-theme-secondary));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
& .v-timeline-divider__dot {
|
|
59
|
+
box-shadow: 0 0 12px rgba(var(--v-theme-primary), 0.9);
|
|
60
|
+
}
|
|
56
61
|
}
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
box-shadow: none;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
19
|
/* A printed rule under the active tab, not a Material underline. */
|
|
21
20
|
|
|
22
21
|
/* The switch gets an outline for the same reason cards do. */
|
|
@@ -28,5 +27,4 @@
|
|
|
28
27
|
& :is(.v-table thead th, .v-data-table__th) {
|
|
29
28
|
border-bottom: 3px double rgba(var(--v-border-color), 0.45);
|
|
30
29
|
}
|
|
31
|
-
|
|
32
30
|
}
|
|
@@ -25,6 +25,15 @@
|
|
|
25
25
|
& .v-tab__slider {
|
|
26
26
|
border-radius: 8px 3px 8px 3px / 3px 8px 3px 8px;
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The one thing the panel token cannot carry: ink is never even, so
|
|
31
|
+
* the bottom of the stroke sits heavier. A shorthand sets all four
|
|
32
|
+
* sides, and this is a single longhand on top of it.
|
|
33
|
+
*/
|
|
34
|
+
& :is(.v-list, .v-sheet, .v-banner, .v-table):not(:is(.v-card, .v-overlay__content, .v-navigation-drawer, .v-expansion-panels, .v-list) *) {
|
|
35
|
+
border-bottom-width: calc(var(--v-vw-border-width) + 1px);
|
|
36
|
+
}
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
@media (prefers-reduced-motion: no-preference) {
|
|
@@ -7,14 +7,13 @@
|
|
|
7
7
|
box-shadow:
|
|
8
8
|
0 2px 4px rgba(var(--v-theme-primary), 0.06),
|
|
9
9
|
0 12px 28px rgba(var(--v-theme-primary), 0.1);
|
|
10
|
-
transition: box-shadow
|
|
10
|
+
transition: box-shadow var(--v-vw-motion-duration) var(--v-vw-motion-ease);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
& .v-card.v-card--variant-elevated.v-card--link:hover {
|
|
14
14
|
box-shadow:
|
|
15
15
|
0 4px 8px rgba(var(--v-theme-primary), 0.08),
|
|
16
16
|
0 20px 40px rgba(var(--v-theme-primary), 0.14);
|
|
17
|
-
transform: translateY(-2px);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
& .v-btn.v-btn--variant-flat:not(.v-btn--disabled) {
|
|
@@ -51,13 +50,3 @@
|
|
|
51
50
|
box-shadow: 0 2px 10px rgba(var(--v-theme-primary), 0.2);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
@media (prefers-reduced-motion: reduce) {
|
|
56
|
-
.v-theme--soft .v-card.v-card--variant-elevated {
|
|
57
|
-
transition: none;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.v-theme--soft .v-card.v-card--variant-elevated.v-card--link:hover {
|
|
61
|
-
transform: none;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { VuetiwatchAccent, VuetiwatchDefaults } from '../types.js'
|
|
2
|
+
import { bars, controls, fields, icons, tables } from '../util/defaults.js'
|
|
3
|
+
import { defineTheme } from '../util/defineTheme.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The admin theme, and the first one here that comes as a family: `atlas`,
|
|
7
|
+
* `atlasDark` and `atlasSepia` share every measurement and differ only in
|
|
8
|
+
* ground, so an app can offer all three and change nothing but the name.
|
|
9
|
+
*
|
|
10
|
+
* It is built for the screen a person keeps open all day. Where `slate`
|
|
11
|
+
* packs a dashboard tight and `graphite` states a product's opinion, this
|
|
12
|
+
* one gets out of the way: comfortable density rather than compact, one
|
|
13
|
+
* low-chroma accent, hairlines instead of shadows, and no capitals, glow or
|
|
14
|
+
* texture anywhere. Nothing on the screen competes with the data on it.
|
|
15
|
+
*
|
|
16
|
+
* Exported alongside the theme are the parts the other two variants reuse —
|
|
17
|
+
* they are the family, not three lookalikes maintained in parallel.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The accents the family offers, one row per preset and one column per
|
|
22
|
+
* ground. A light ground needs a deep accent to carry a white label; a dark
|
|
23
|
+
* one needs a light accent and a dark label — the Material 3 pairing — so
|
|
24
|
+
* the same preset is a different hex in each variant, and the id is what
|
|
25
|
+
* ties them together when someone switches.
|
|
26
|
+
*
|
|
27
|
+
* Every value here is measured: filled controls clear 4.5:1 in all three.
|
|
28
|
+
*/
|
|
29
|
+
const ACCENTS = [
|
|
30
|
+
{ id: 'cobalt', title: 'Cobalt', light: ['#0059FF', '#0047CC'], dark: ['#3382FF', '#2A6BD6'], sepia: ['#1150E0', '#0E41B4'] },
|
|
31
|
+
{ id: 'indigo', title: 'Indigo', light: ['#3F4E8C', '#323E70'], dark: ['#93A4E8', '#7688D1'], sepia: ['#46508A', '#37406E'] },
|
|
32
|
+
{ id: 'eucalyptus', title: 'Eucalyptus', light: ['#2F6B5B', '#245448'], dark: ['#6FB39B', '#57957F'], sepia: ['#3F6B57', '#325544'] },
|
|
33
|
+
{ id: 'plum', title: 'Plum', light: ['#6B3F63', '#55324F'], dark: ['#C596BC', '#A87A9F'], sepia: ['#6B4560', '#56374D'] },
|
|
34
|
+
{ id: 'clay', title: 'Clay', light: ['#8A5B2B', '#6E4822'], dark: ['#D9A272', '#BC855A'], sepia: ['#8A5B34', '#6E4829'] },
|
|
35
|
+
] as const
|
|
36
|
+
|
|
37
|
+
/** The accent list for one ground, in the shape `meta.accents` expects. */
|
|
38
|
+
export const atlasAccents = (tone: 'light' | 'dark' | 'sepia'): VuetiwatchAccent[] =>
|
|
39
|
+
ACCENTS.map(accent => {
|
|
40
|
+
const [primary, darken] = accent[tone]
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
id: accent.id,
|
|
44
|
+
title: accent.title,
|
|
45
|
+
colors: {
|
|
46
|
+
primary,
|
|
47
|
+
'primary-darken-1': darken,
|
|
48
|
+
// On a dark ground the accent is the light thing on screen, so its
|
|
49
|
+
// label is the ground itself rather than white.
|
|
50
|
+
...(tone === 'dark' ? { 'on-primary': '#15191B' } : {}),
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
/** Geometry, type and motion. Identical across the family. */
|
|
56
|
+
export const atlasVariables = {
|
|
57
|
+
'high-emphasis-opacity': 0.88,
|
|
58
|
+
'medium-emphasis-opacity': 0.6,
|
|
59
|
+
'hover-opacity': 0.04,
|
|
60
|
+
'font-body': "'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif",
|
|
61
|
+
// Eight and ten, which is where the admin frameworks people actually
|
|
62
|
+
// like have settled: tight enough to read as a tool, round enough not to
|
|
63
|
+
// look like a spreadsheet.
|
|
64
|
+
'vw-radius': '8px',
|
|
65
|
+
'vw-radius-lg': '10px',
|
|
66
|
+
'vw-radius-chip': '6px',
|
|
67
|
+
'vw-radius-thumb': '50%',
|
|
68
|
+
'vw-border-width': '1px',
|
|
69
|
+
// A field's outline is how you find the field: 0.5 puts it just past 3:1
|
|
70
|
+
// on all three grounds, where Vuetify's 0.38 leaves it at about 2.3.
|
|
71
|
+
'vw-field-border-opacity': '0.5',
|
|
72
|
+
'vw-btn-transform': 'none',
|
|
73
|
+
'vw-btn-tracking': '0',
|
|
74
|
+
'vw-btn-weight': '500',
|
|
75
|
+
'vw-heading-weight': '600',
|
|
76
|
+
'vw-heading-tracking': '-0.025em',
|
|
77
|
+
// Column headers are labels, not announcements: weight and a little
|
|
78
|
+
// tracking, no capitals. Three themes here already shout in their tables.
|
|
79
|
+
'vw-th-weight': '500',
|
|
80
|
+
'vw-th-tracking': '0.03em',
|
|
81
|
+
// An admin screen is mostly figures, and figures only line up in a column
|
|
82
|
+
// when every digit is the same width.
|
|
83
|
+
'vw-numeric': 'tabular-nums',
|
|
84
|
+
'vw-tab-slider-height': '2px',
|
|
85
|
+
'vw-list-bar': '2px',
|
|
86
|
+
'vw-list-bar-color': 'rgb(var(--v-theme-primary))',
|
|
87
|
+
// Quiet, quick, and no overshoot — the motion of something you look at
|
|
88
|
+
// for eight hours rather than something you show off.
|
|
89
|
+
'vw-motion-duration': '160ms',
|
|
90
|
+
'vw-motion-ease': 'cubic-bezier(0.2, 0, 0.2, 1)',
|
|
91
|
+
'vw-press-scale': '0.99',
|
|
92
|
+
'vw-hover-lift': '1px',
|
|
93
|
+
'vw-pop-scale': '1.08',
|
|
94
|
+
'vw-pop-duration': '180ms',
|
|
95
|
+
'vw-theme-transition': '320ms',
|
|
96
|
+
} as const
|
|
97
|
+
|
|
98
|
+
/** Component defaults. Identical across the family. */
|
|
99
|
+
export const atlasDefaults: VuetiwatchDefaults[] = [
|
|
100
|
+
{
|
|
101
|
+
VBtn: { variant: 'flat' },
|
|
102
|
+
VCard: { variant: 'outlined' },
|
|
103
|
+
VAlert: { variant: 'tonal', density: 'compact' },
|
|
104
|
+
VChip: { variant: 'tonal', size: 'small' },
|
|
105
|
+
VNavigationDrawer: { border: 'e' },
|
|
106
|
+
// A row that lights under the cursor is the cheapest way to keep a
|
|
107
|
+
// place in a table of a hundred lines.
|
|
108
|
+
VDataTable: { hover: true },
|
|
109
|
+
/**
|
|
110
|
+
* The picker's 70px header repeats the date it is already showing —
|
|
111
|
+
* it exists for the full-screen dialog on a phone. In a form beside a
|
|
112
|
+
* labelled field it is a third of the control's height saying nothing.
|
|
113
|
+
*/
|
|
114
|
+
VDatePicker: { hideHeader: true },
|
|
115
|
+
VTimePicker: { hideHeader: true },
|
|
116
|
+
// Vuetify draws the empty-state glyph at 96px, which is a poster on a
|
|
117
|
+
// panel this size. Enough to read as an illustration, not as a banner.
|
|
118
|
+
VEmptyState: { size: 56 },
|
|
119
|
+
/**
|
|
120
|
+
* A segmented control is one object, not a row of raised buttons: a
|
|
121
|
+
* hairline box with the chosen segment filled. Vuetify's default leaves
|
|
122
|
+
* each button floating on its own elevation.
|
|
123
|
+
*/
|
|
124
|
+
VBtnToggle: { variant: 'outlined', divided: true, density: 'compact' },
|
|
125
|
+
},
|
|
126
|
+
// Compact throughout: an admin screen is a working surface, and a field
|
|
127
|
+
// at Vuetify's default height is a third taller than the row it sits in.
|
|
128
|
+
fields({ variant: 'outlined', density: 'compact' }),
|
|
129
|
+
controls({ density: 'compact' }),
|
|
130
|
+
tables('compact'),
|
|
131
|
+
bars({ flat: true, border: 'b', height: 56 }),
|
|
132
|
+
{
|
|
133
|
+
// Not inset: the pill is 52×32 where the plain switch is 36×14, and on
|
|
134
|
+
// a row of settings that difference is the whole line height.
|
|
135
|
+
VSwitch: { inset: false },
|
|
136
|
+
VSlider: { thumbSize: 14, trackSize: 3 },
|
|
137
|
+
},
|
|
138
|
+
icons({
|
|
139
|
+
dropdown: 'mdi-chevron-down',
|
|
140
|
+
collapse: 'mdi-chevron-up',
|
|
141
|
+
checkboxOn: 'mdi-checkbox-marked-outline',
|
|
142
|
+
checkboxOff: 'mdi-checkbox-blank-outline',
|
|
143
|
+
sortAsc: 'mdi-arrow-up',
|
|
144
|
+
sortDesc: 'mdi-arrow-down',
|
|
145
|
+
next: 'mdi-chevron-right',
|
|
146
|
+
prev: 'mdi-chevron-left',
|
|
147
|
+
first: 'mdi-page-first',
|
|
148
|
+
last: 'mdi-page-last',
|
|
149
|
+
clear: 'mdi-close',
|
|
150
|
+
close: 'mdi-close',
|
|
151
|
+
}),
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
export const atlas = defineTheme({
|
|
155
|
+
name: 'atlas',
|
|
156
|
+
meta: {
|
|
157
|
+
title: 'Atlas',
|
|
158
|
+
description: 'Console light — a white page, hairline panels and one blue that means "do it".',
|
|
159
|
+
dark: false,
|
|
160
|
+
iconStyle: 'outline',
|
|
161
|
+
family: 'atlas',
|
|
162
|
+
variant: 'Light',
|
|
163
|
+
accents: atlasAccents('light'),
|
|
164
|
+
swatch: ['#FDFDFF', '#FFFFFF', '#0059FF', '#57647B'],
|
|
165
|
+
fonts: ['Inter'],
|
|
166
|
+
},
|
|
167
|
+
theme: {
|
|
168
|
+
dark: false,
|
|
169
|
+
colors: {
|
|
170
|
+
/**
|
|
171
|
+
* The ground is white, not grey. Consoles built this decade separate
|
|
172
|
+
* a panel from the page with a line, not with a tint — the tint is
|
|
173
|
+
* saved for the bands inside a panel, which is what `surface-light`
|
|
174
|
+
* is here: table headers, filled rows, the sidebar.
|
|
175
|
+
*/
|
|
176
|
+
background: '#FDFDFF',
|
|
177
|
+
surface: '#FFFFFF',
|
|
178
|
+
'surface-bright': '#FFFFFF',
|
|
179
|
+
// The reference uses this tint at a third of its strength — `bg-muted/30`
|
|
180
|
+
// — so the bands read as a change of paper, not as a coloured stripe.
|
|
181
|
+
'surface-light': '#F5F8FD',
|
|
182
|
+
'surface-variant': '#0B101C',
|
|
183
|
+
'on-surface-variant': '#FDFDFF',
|
|
184
|
+
primary: '#0059FF',
|
|
185
|
+
'primary-darken-1': '#0047CC',
|
|
186
|
+
secondary: '#57647B',
|
|
187
|
+
'secondary-darken-1': '#45505F',
|
|
188
|
+
error: '#D91326',
|
|
189
|
+
info: '#0369A1',
|
|
190
|
+
success: '#15803D',
|
|
191
|
+
warning: '#B45309',
|
|
192
|
+
'on-surface': '#0B101C',
|
|
193
|
+
'on-background': '#0B101C',
|
|
194
|
+
},
|
|
195
|
+
variables: {
|
|
196
|
+
/**
|
|
197
|
+
* A cool grey line rather than ink at low alpha: ink fades to a
|
|
198
|
+
* neutral grey, and every line here should carry the same blue cast
|
|
199
|
+
* as the surfaces it separates. At 0.22 it lands on #DFE3EB, a shade
|
|
200
|
+
* off the panel it edges.
|
|
201
|
+
*/
|
|
202
|
+
'border-color': '#6E82A6',
|
|
203
|
+
'border-opacity': 0.22,
|
|
204
|
+
'shadow-color': '#0B101C',
|
|
205
|
+
'vw-overlay-border': '1px solid rgba(var(--v-border-color), 0.1)',
|
|
206
|
+
'vw-overlay-shadow': '0 8px 28px rgba(var(--v-shadow-color), 0.1)',
|
|
207
|
+
...atlasVariables,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
defaults: atlasDefaults,
|
|
211
|
+
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { atlasAccents, atlasDefaults, atlasVariables } from './atlas.js'
|
|
2
|
+
import { defineTheme } from '../util/defineTheme.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `atlas` after dark: the same measurements, the same accent hue lifted to
|
|
6
|
+
* where it reads on a dark ground, and a background that is grey rather
|
|
7
|
+
* than black — a panel someone stares at all evening should not be a hole
|
|
8
|
+
* with text floating in it.
|
|
9
|
+
*/
|
|
10
|
+
export const atlasDark = defineTheme({
|
|
11
|
+
name: 'atlasDark',
|
|
12
|
+
meta: {
|
|
13
|
+
title: 'Atlas Dark',
|
|
14
|
+
description: 'The same console after dark — deep navy, a lit blue, lines you can find.',
|
|
15
|
+
dark: true,
|
|
16
|
+
iconStyle: 'outline',
|
|
17
|
+
family: 'atlas',
|
|
18
|
+
variant: 'Dark',
|
|
19
|
+
accents: atlasAccents('dark'),
|
|
20
|
+
swatch: ['#040817', '#070E21', '#3382FF', '#838FA8'],
|
|
21
|
+
fonts: ['Inter'],
|
|
22
|
+
},
|
|
23
|
+
theme: {
|
|
24
|
+
dark: true,
|
|
25
|
+
colors: {
|
|
26
|
+
background: '#040817',
|
|
27
|
+
surface: '#070E21',
|
|
28
|
+
'surface-bright': '#101830',
|
|
29
|
+
'surface-light': '#151E35',
|
|
30
|
+
'surface-variant': '#CBD5E1',
|
|
31
|
+
'on-surface-variant': '#040817',
|
|
32
|
+
primary: '#3382FF',
|
|
33
|
+
'primary-darken-1': '#2A6BD6',
|
|
34
|
+
secondary: '#838FA8',
|
|
35
|
+
'secondary-darken-1': '#6B778F',
|
|
36
|
+
error: '#F94144',
|
|
37
|
+
info: '#7DD3FC',
|
|
38
|
+
success: '#4ADE80',
|
|
39
|
+
warning: '#FBBF24',
|
|
40
|
+
'on-surface': '#EEF2F9',
|
|
41
|
+
'on-background': '#EEF2F9',
|
|
42
|
+
/**
|
|
43
|
+
* A dark theme's accents are the light thing on the screen, so their
|
|
44
|
+
* labels are the ground colour rather than white — the Material 3
|
|
45
|
+
* convention, and the only option that clears 4.5:1 here. Vuetify's
|
|
46
|
+
* automatic pick lands on white at about 2.5:1.
|
|
47
|
+
*/
|
|
48
|
+
'on-primary': '#040817',
|
|
49
|
+
'on-secondary': '#040817',
|
|
50
|
+
'on-error': '#040817',
|
|
51
|
+
},
|
|
52
|
+
variables: {
|
|
53
|
+
// Lands on #1F283E over the panel — the line is visible without
|
|
54
|
+
// becoming a grid.
|
|
55
|
+
'border-color': '#8FA0C4',
|
|
56
|
+
'border-opacity': 0.18,
|
|
57
|
+
'shadow-color': '#000000',
|
|
58
|
+
'vw-overlay-border': '1px solid rgba(var(--v-border-color), 0.16)',
|
|
59
|
+
'vw-overlay-shadow': '0 12px 32px rgba(0, 0, 0, 0.5)',
|
|
60
|
+
...atlasVariables,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
defaults: atlasDefaults,
|
|
64
|
+
})
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { atlasAccents, atlasDefaults, atlasVariables } from './atlas.js'
|
|
2
|
+
import { defineTheme } from '../util/defineTheme.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The third ground: warm paper rather than white or grey.
|
|
6
|
+
*
|
|
7
|
+
* Neither light nor dark mode helps the person who finds a white panel too
|
|
8
|
+
* bright and a dark one too flat. Dropping the blue out of the ground and
|
|
9
|
+
* the ink lowers the glare without lowering the contrast — the text still
|
|
10
|
+
* carries better than 12:1 — and the accent turns a shade warmer to sit on
|
|
11
|
+
* it. It is the same panel, lit by a lamp instead of a window.
|
|
12
|
+
*/
|
|
13
|
+
export const atlasSepia = defineTheme({
|
|
14
|
+
name: 'atlasSepia',
|
|
15
|
+
meta: {
|
|
16
|
+
title: 'Atlas Sepia',
|
|
17
|
+
description: 'Warm paper and brown ink — the same panel, easier on tired eyes.',
|
|
18
|
+
dark: false,
|
|
19
|
+
iconStyle: 'outline',
|
|
20
|
+
family: 'atlas',
|
|
21
|
+
variant: 'Sepia',
|
|
22
|
+
accents: atlasAccents('sepia'),
|
|
23
|
+
swatch: ['#F7F3EC', '#FFFDF9', '#1150E0', '#7A6A52'],
|
|
24
|
+
fonts: ['Inter'],
|
|
25
|
+
},
|
|
26
|
+
theme: {
|
|
27
|
+
dark: false,
|
|
28
|
+
colors: {
|
|
29
|
+
background: '#F7F3EC',
|
|
30
|
+
surface: '#FFFDF9',
|
|
31
|
+
'surface-bright': '#FFFFFC',
|
|
32
|
+
'surface-light': '#F4EEE3',
|
|
33
|
+
'surface-variant': '#241E16',
|
|
34
|
+
'on-surface-variant': '#F7F3EC',
|
|
35
|
+
// Ink-blue on warm paper: the family's accent, in the register the
|
|
36
|
+
// ground is written in.
|
|
37
|
+
primary: '#1150E0',
|
|
38
|
+
'primary-darken-1': '#0E41B4',
|
|
39
|
+
secondary: '#7A6A52',
|
|
40
|
+
'secondary-darken-1': '#615341',
|
|
41
|
+
error: '#A83A2C',
|
|
42
|
+
info: '#356B86',
|
|
43
|
+
success: '#3B6B4A',
|
|
44
|
+
warning: '#8A6118',
|
|
45
|
+
'on-surface': '#241E16',
|
|
46
|
+
'on-background': '#241E16',
|
|
47
|
+
},
|
|
48
|
+
variables: {
|
|
49
|
+
// The same idea as the light variant, in the warm register: the line
|
|
50
|
+
// lands on #E0D7C8 rather than on a grey.
|
|
51
|
+
'border-color': '#8A7A63',
|
|
52
|
+
'border-opacity': 0.28,
|
|
53
|
+
'shadow-color': '#3B332A',
|
|
54
|
+
'vw-overlay-border': '1px solid rgba(var(--v-border-color), 0.12)',
|
|
55
|
+
'vw-overlay-shadow': '0 8px 28px rgba(var(--v-shadow-color), 0.14)',
|
|
56
|
+
...atlasVariables,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaults: atlasDefaults,
|
|
60
|
+
})
|
package/src/themes/aurora.ts
CHANGED
|
@@ -16,7 +16,7 @@ export const aurora = defineTheme({
|
|
|
16
16
|
description: 'Iridescent gradients on near-black. Built to be looked at — the showcase theme.',
|
|
17
17
|
dark: true,
|
|
18
18
|
iconStyle: 'filled',
|
|
19
|
-
swatch: ['#08080C', '#101018', '#
|
|
19
|
+
swatch: ['#08080C', '#101018', '#7857FF', '#00D4FF'],
|
|
20
20
|
fonts: ['Inter'],
|
|
21
21
|
},
|
|
22
22
|
theme: {
|
|
@@ -28,7 +28,7 @@ export const aurora = defineTheme({
|
|
|
28
28
|
'surface-light': '#16161F',
|
|
29
29
|
'surface-variant': '#C9C6E0',
|
|
30
30
|
'on-surface-variant': '#08080C',
|
|
31
|
-
primary: '#
|
|
31
|
+
primary: '#7857FF',
|
|
32
32
|
'primary-darken-1': '#5F3FE0',
|
|
33
33
|
secondary: '#00D4FF',
|
|
34
34
|
'secondary-darken-1': '#00A8CC',
|
|
@@ -38,11 +38,20 @@ export const aurora = defineTheme({
|
|
|
38
38
|
warning: '#FFB86B',
|
|
39
39
|
'on-surface': '#E8E6F5',
|
|
40
40
|
'on-background': '#F0EEFA',
|
|
41
|
+
// Vuetify picks the label colour by luminance and settles for
|
|
42
|
+
// about 3:1, which is the bar for large text rather than for a
|
|
43
|
+
// button label. Measured on the filled buttons: error 3:1 → 7.1:1.
|
|
44
|
+
'on-error': '#000000',
|
|
41
45
|
'on-secondary': '#04121A',
|
|
42
46
|
'on-success': '#04140D',
|
|
43
47
|
'on-warning': '#1A1004',
|
|
44
48
|
},
|
|
45
49
|
variables: {
|
|
50
|
+
/* A panel standing on its own — a bare list, sheet, banner or table.
|
|
51
|
+
Core owns the selector; this is what it draws with. */
|
|
52
|
+
'vw-panel-image':
|
|
53
|
+
'radial-gradient(36rem 18rem at 0% 0%, rgba(124, 92, 255, 0.14), transparent 70%)',
|
|
54
|
+
'vw-panel-shadow': '0 12px 40px rgba(0, 0, 0, 0.55)',
|
|
46
55
|
'border-color': '#9B8CFF',
|
|
47
56
|
'border-opacity': 0.14,
|
|
48
57
|
'shadow-color': '#000000',
|
|
@@ -61,6 +70,25 @@ export const aurora = defineTheme({
|
|
|
61
70
|
// Shared by every gradient below, so a derived theme restyles the
|
|
62
71
|
// whole surface language by overriding one value.
|
|
63
72
|
'vw-gradient': 'linear-gradient(135deg, #7C5CFF 0%, #00D4FF 55%, #FF5CAA 100%)',
|
|
73
|
+
/**
|
|
74
|
+
* The same three hues at a depth that carries a white label: the
|
|
75
|
+
* showcase gradient runs through a cyan where white text reads at
|
|
76
|
+
* 1.8:1, which is fine behind a tab slider and unusable behind a
|
|
77
|
+
* word. Anything with text on it takes this one instead.
|
|
78
|
+
*/
|
|
79
|
+
'vw-gradient-btn': 'linear-gradient(135deg, #6F4CFF 0%, #007891 55%, #DA0069 100%)',
|
|
80
|
+
|
|
81
|
+
// The showcase theme, so the motion shows off too.
|
|
82
|
+
'vw-motion-duration': '300ms',
|
|
83
|
+
'vw-press-scale': '0.97',
|
|
84
|
+
'vw-hover-lift': '3px',
|
|
85
|
+
'vw-pop-scale': '1.28',
|
|
86
|
+
'vw-pop-duration': '300ms',
|
|
87
|
+
'vw-theme-transition': '560ms',
|
|
88
|
+
|
|
89
|
+
// The line is the theme's own gradient, top to bottom.
|
|
90
|
+
'vw-timeline-line': 'var(--v-vw-gradient)',
|
|
91
|
+
'vw-timeline-line-width': '2px',
|
|
64
92
|
},
|
|
65
93
|
},
|
|
66
94
|
defaults: [
|
package/src/themes/brutalist.ts
CHANGED
|
@@ -38,11 +38,21 @@ export const brutalist = defineTheme({
|
|
|
38
38
|
warning: '#FFB300',
|
|
39
39
|
'on-surface': '#0A0A0A',
|
|
40
40
|
'on-background': '#0A0A0A',
|
|
41
|
+
// Vuetify picks the label colour by luminance and settles for
|
|
42
|
+
// about 3:1, which is the bar for large text rather than for a
|
|
43
|
+
// button label. Measured on the filled buttons: info 3.8:1 → 5.2:1, error 3.3:1 → 6:1.
|
|
44
|
+
'on-info': '#0A0A0A',
|
|
45
|
+
'on-error': '#0A0A0A',
|
|
41
46
|
'on-secondary': '#0A0A0A',
|
|
42
47
|
'on-warning': '#0A0A0A',
|
|
43
48
|
'on-success': '#0A0A0A',
|
|
44
49
|
},
|
|
45
50
|
variables: {
|
|
51
|
+
/* A panel standing on its own — a bare list, sheet, banner or table.
|
|
52
|
+
Core owns the selector; this is what it draws with. */
|
|
53
|
+
'vw-panel-border': 'var(--v-vw-border-width) solid rgb(var(--v-shadow-color))',
|
|
54
|
+
'vw-panel-shadow':
|
|
55
|
+
'var(--vw-brut-offset) var(--vw-brut-offset) 0 rgb(var(--v-shadow-color))',
|
|
46
56
|
'border-color': '#0A0A0A',
|
|
47
57
|
'border-opacity': 1,
|
|
48
58
|
'shadow-color': '#0A0A0A',
|
|
@@ -54,6 +64,8 @@ export const brutalist = defineTheme({
|
|
|
54
64
|
'vw-radius-lg': '0px',
|
|
55
65
|
'vw-radius-thumb': '0px',
|
|
56
66
|
'vw-radius-chip': '0px',
|
|
67
|
+
// Nothing here is round, the icon buttons included.
|
|
68
|
+
'vw-radius-icon-btn': '0px',
|
|
57
69
|
'vw-border-width': '3px',
|
|
58
70
|
'vw-btn-transform': 'uppercase',
|
|
59
71
|
'vw-btn-tracking': '0.04em',
|
|
@@ -65,6 +77,23 @@ export const brutalist = defineTheme({
|
|
|
65
77
|
'vw-heading-weight': '700',
|
|
66
78
|
'vw-heading-tracking': '-0.02em',
|
|
67
79
|
'vw-tab-slider-height': '4px',
|
|
80
|
+
|
|
81
|
+
// Two frames, no curve. The press is the theme's own slide into its
|
|
82
|
+
// shadow, so the shared squash stays out of its way.
|
|
83
|
+
'vw-motion-duration': '80ms',
|
|
84
|
+
'vw-motion-ease': 'steps(2, end)',
|
|
85
|
+
'vw-press-scale': '1',
|
|
86
|
+
'vw-pop-scale': '1.3',
|
|
87
|
+
'vw-pop-duration': '100ms',
|
|
88
|
+
'vw-focus-ring': '3px solid rgb(var(--v-shadow-color))',
|
|
89
|
+
'vw-focus-offset': '3px',
|
|
90
|
+
'vw-theme-transition': '200ms',
|
|
91
|
+
|
|
92
|
+
// A structural beam, and the dot is a square like everything else.
|
|
93
|
+
'vw-timeline-line': 'rgb(var(--v-shadow-color))',
|
|
94
|
+
'vw-timeline-line-width': '4px',
|
|
95
|
+
'vw-radius-dot': '0px',
|
|
96
|
+
'vw-radius-avatar': '0px',
|
|
68
97
|
},
|
|
69
98
|
},
|
|
70
99
|
defaults: [
|
package/src/themes/calm.ts
CHANGED
|
@@ -17,7 +17,7 @@ export const calm = defineTheme({
|
|
|
17
17
|
description: 'Low contrast, desaturated naturals and a lot of air. Nothing competes for attention.',
|
|
18
18
|
dark: false,
|
|
19
19
|
iconStyle: 'outline',
|
|
20
|
-
swatch: ['#FAFAF7', '#FFFFFF', '#6B7A6B', '#
|
|
20
|
+
swatch: ['#FAFAF7', '#FFFFFF', '#6B7A6B', '#86725F'],
|
|
21
21
|
fonts: ['Inter'],
|
|
22
22
|
},
|
|
23
23
|
theme: {
|
|
@@ -31,7 +31,7 @@ export const calm = defineTheme({
|
|
|
31
31
|
'on-surface-variant': '#FAFAF7',
|
|
32
32
|
primary: '#6B7A6B',
|
|
33
33
|
'primary-darken-1': '#556355',
|
|
34
|
-
secondary: '#
|
|
34
|
+
secondary: '#86725F',
|
|
35
35
|
'secondary-darken-1': '#8B7A69',
|
|
36
36
|
error: '#A86B63',
|
|
37
37
|
info: '#6B7A8A',
|
|
@@ -39,8 +39,19 @@ export const calm = defineTheme({
|
|
|
39
39
|
warning: '#A89464',
|
|
40
40
|
'on-surface': '#3A3A36',
|
|
41
41
|
'on-background': '#3A3A36',
|
|
42
|
+
// Vuetify picks the label colour by luminance and settles for
|
|
43
|
+
// about 3:1, which is the bar for large text rather than for a
|
|
44
|
+
// button label. Measured on the filled buttons: success 3.8:1 → 5.5:1, info 4.4:1 → 4.8:1, warning 3:1 → 7.1:1, error 4.2:1 → 4.9:1.
|
|
45
|
+
'on-success': '#000000',
|
|
46
|
+
'on-info': '#000000',
|
|
47
|
+
'on-warning': '#000000',
|
|
48
|
+
'on-error': '#000000',
|
|
42
49
|
},
|
|
43
50
|
variables: {
|
|
51
|
+
/* A panel standing on its own — a bare list, sheet, banner or table.
|
|
52
|
+
Core owns the selector; this is what it draws with. */
|
|
53
|
+
'vw-panel-border':
|
|
54
|
+
'var(--v-vw-border-width) solid rgba(var(--v-border-color), var(--v-border-opacity))',
|
|
44
55
|
'border-color': '#3A3A36',
|
|
45
56
|
'border-opacity': 0.09,
|
|
46
57
|
'high-emphasis-opacity': 0.78,
|
|
@@ -57,6 +68,18 @@ export const calm = defineTheme({
|
|
|
57
68
|
'vw-heading-weight': '500',
|
|
58
69
|
'vw-heading-tracking': '-0.01em',
|
|
59
70
|
'vw-tab-slider-height': '2px',
|
|
71
|
+
|
|
72
|
+
// Slow enough that nothing ever catches the eye.
|
|
73
|
+
'vw-motion-duration': '320ms',
|
|
74
|
+
'vw-press-scale': '0.99',
|
|
75
|
+
'vw-hover-lift': '2px',
|
|
76
|
+
'vw-pop-scale': '1.08',
|
|
77
|
+
'vw-pop-duration': '280ms',
|
|
78
|
+
'vw-theme-transition': '560ms',
|
|
79
|
+
|
|
80
|
+
// Barely there, like everything else in this theme.
|
|
81
|
+
'vw-timeline-line': 'rgba(var(--v-border-color), 0.5)',
|
|
82
|
+
'vw-timeline-line-width': '1px',
|
|
60
83
|
},
|
|
61
84
|
},
|
|
62
85
|
defaults: [
|