diff --git a/ui/src/css/_root-css-vars.scss b/ui/src/css/_root-css-vars.scss index c0ecfe2..e775e21 100644 --- a/ui/src/css/_root-css-vars.scss +++ b/ui/src/css/_root-css-vars.scss @@ -7,14 +7,14 @@ CSS custom properties (e.g. from "design tokens") for dynamic theming. // Colors. Values are specified as a space-separated list of HSL values so they can be used in the CSS 'hsl()' function. // e.g. color: hsl(var(--color-brand) / 50%); --color-brand: 270 50% 40%; // rebeccapurple - --color-text: 0 0% 20%; - --color-background: 0 0% 100%; + --color-neutral-100: 0 0% 100%; + --color-neutral-200: 0 0% 95%; + --color-neutral-700: 0 0% 20%; --color-neutral-900: 0 0% 0%; - --color-neutral-100: 0 0% 95%; --color-accent-positive: 116 44% 60%; --color-accent-negative: 358 75% 39%; --color-accent-neutral: 51 100% 45%; - --color-focus: 193 100% 45%; + --color-focused: 193 100% 45%; // Typography. --type-font-fallback: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, @@ -49,9 +49,9 @@ CSS custom properties (e.g. from "design tokens") for dynamic theming. @media (prefers-color-scheme: dark) { :root { --color-brand: 270 50% 50%; - --color-text: 0 0% 95%; - --color-background: 0 0% 13%; + --color-neutral-100: 0 0% 13%; + --color-neutral-200: 0 0% 95%; + --color-neutral-700: 0 0% 95%; --color-neutral-900: 0 0% 13%; - --color-neutral-100: 0 0% 95%; } } diff --git a/ui/src/css/base/_colors.scss b/ui/src/css/base/_colors.scss index 7600e58..cc9d031 100644 --- a/ui/src/css/base/_colors.scss +++ b/ui/src/css/base/_colors.scss @@ -2,31 +2,33 @@ ---------------------------------------------------------------------------- Color settings. -1. Copy the CSS Custom properties below, along with their JSDoc comments, into 'base/colors-to-json.scss'. -2. The 'sass-export' Node package then correctly exports all the colors as JSON for consumption by Storybook. +1. Copy the CSS custom properties inside the ':root {}' ruleset, along with their JSDoc comments, into 'base/colors-to-json.scss'. +2. Replace '--' with '$'. +3. The 'sass-export' Node package then correctly exports all the colors as JSON for consumption by Storybook. TODO: - Write custom Node script to convert these values into JSON without the manual copy/paste step into a Sass file. ---------------------------------------------------------------------------- */ +:root { + /** + * @sass-export-section="main theme colours" + */ + --color-primary: hsl(var(--color-brand)); -/** - * @sass-export-section="main theme colours" - */ -$color-brand: hsl(var(--color-brand)); -$color-text: hsl(var(--color-text)); -$color-background: hsl(var(--color-background)); + /** + * @sass-export-section="neutral colours" + */ + --color-background: hsl(var(--color-neutral-100)); + --color-text: hsl(var(--color-neutral-700)); + --color-neutral-light: hsl(var(--color-neutral-200)); + --color-neutral-dark: hsl(var(--color-neutral-900)); -/** - * @sass-export-section="neutral colours" - */ -$color-neutral-900: hsl(var(--color-neutral-900)); -$color-neutral-100: hsl(var(--color-neutral-100)); - -/** - * @sass-export-section="other accent colours" - */ -$color-success: hsl(var(--color-accent-positive)); -$color-error: hsl(var(--color-accent-negative)); -$color-notify: hsl(var(--color-accent-neutral)); -$color-focus: hsl(var(--color-focus)); + /** + * @sass-export-section="other accent colours" + */ + --color-success: hsl(var(--color-accent-positive)); + --color-error: hsl(var(--color-accent-negative)); + --color-notify: hsl(var(--color-accent-neutral)); + --color-focus: hsl(var(--color-focused)); +} diff --git a/ui/src/css/base/_config.scss b/ui/src/css/base/_config.scss index 126a6b4..e876392 100644 --- a/ui/src/css/base/_config.scss +++ b/ui/src/css/base/_config.scss @@ -19,7 +19,7 @@ Config settings. - Uses transparent outline so high contrast mode works. - See https://css-tricks.com/the-focus-visible-trick/. */ - --focus-shadow: 0 0 0 var(--border-width-l) #{$color-focus}; + --focus-shadow: 0 0 0 var(--border-width-l) var(--color-focus); --focus-outline: var(--border-width-l) solid transparent; /* :hover and :active */ diff --git a/ui/src/css/base/_type.scss b/ui/src/css/base/_type.scss index bc6345a..04f727f 100644 --- a/ui/src/css/base/_type.scss +++ b/ui/src/css/base/_type.scss @@ -56,6 +56,3 @@ Font-face rules. /* Max line-length (aka measure) to improve readability of editorial content */ --type-max-line-length: 65ch; } - -/* TODO - Base font settings. */ -$base-color: $color-text !default; diff --git a/ui/src/css/base/colors-to-json.scss b/ui/src/css/base/colors-to-json.scss index 6c740b7..84dd41e 100644 --- a/ui/src/css/base/colors-to-json.scss +++ b/ui/src/css/base/colors-to-json.scss @@ -2,32 +2,31 @@ ---------------------------------------------------------------------------- Color settings. -1. Copied from the CSS Custom properties in 'base/colors.css', ans converted to Sass variables. +1. Copied from the CSS Custom properties in 'base/colors.css', and converted to Sass variables. 2. The 'sass-export' Node package then correctly exports all the colors as JSON for consumption by Storybook. -3. This file is NOT imported so is NOT part of the Parcel build. +3. This file is NOT imported and is NOT part of the Parcel build. TODO: - Write custom Node script to convert CSS into JSON without the manual copy/paste step into this Sass file. ---------------------------------------------------------------------------- */ - /** - * @sass-export-section="main theme colours" - */ -$color-brand: hsl(var(--color-brand)); -$color-text: hsl(var(--color-text)); -$color-background: hsl(var(--color-background)); +* @sass-export-section="main theme colours" +*/ +$color-primary: hsl(var(--color-brand)); /** - * @sass-export-section="neutral colours" - */ -$color-neutral-900: hsl(var(--color-neutral-900)); -$color-neutral-100: hsl(var(--color-neutral-100)); +* @sass-export-section="neutral colours" +*/ +$color-background: hsl(var(--color-neutral-100)); +$color-text: hsl(var(--color-neutral-700)); +$color-neutral-light: hsl(var(--color-neutral-200)); +$color-neutral-dark: hsl(var(--color-neutral-900)); /** - * @sass-export-section="other accent colours" - */ +* @sass-export-section="other accent colours" +*/ $color-success: hsl(var(--color-accent-positive)); $color-error: hsl(var(--color-accent-negative)); $color-notify: hsl(var(--color-accent-neutral)); -$color-focus: hsl(var(--color-focus)); +$color-focus: hsl(var(--color-focused)); diff --git a/ui/src/css/components/_ajax.scss b/ui/src/css/components/_ajax.scss index 453268d..0683462 100644 --- a/ui/src/css/components/_ajax.scss +++ b/ui/src/css/components/_ajax.scss @@ -7,6 +7,6 @@ Dependencies. .ajax { &__error { - color: $color-error; + color: var(--color-error); } } diff --git a/ui/src/css/components/_banner.scss b/ui/src/css/components/_banner.scss index 827d60b..af1d139 100644 --- a/ui/src/css/components/_banner.scss +++ b/ui/src/css/components/_banner.scss @@ -22,7 +22,7 @@ Dependencies. } &__content { - color: $color-text; + color: var(--color-text); } &--fullwidth { @@ -44,7 +44,7 @@ Dependencies. .banner__content { /* stylelint-disable-next-line max-nesting-depth */ @media (prefers-color-scheme: dark) { - --color-text: 0 0% 20%; + --color-neutral-700: 0 0% 20%; } // Example, so text is legible above image. @@ -74,7 +74,7 @@ Dependencies. @media (width > 48em) { /* stylelint-disable-next-line max-nesting-depth */ @media (prefers-color-scheme: dark) { - --color-text: 0 0% 20%; + --color-neutral-700: 0 0% 20%; } background: none; diff --git a/ui/src/css/components/_button.scss b/ui/src/css/components/_button.scss index d7ff750..0df6479 100644 --- a/ui/src/css/components/_button.scss +++ b/ui/src/css/components/_button.scss @@ -47,19 +47,19 @@ Dependencies. // Apply colours to button variants. &--primary { - background-color: $color-brand; - color: $color-neutral-100; + background-color: var(--color-primary); + color: var(--color-neutral-light); &[class*='text'] { - border-color: $color-brand; + border-color: var(--color-primary); } } &--secondary { - color: $color-brand; + color: var(--color-primary); &[class*='text'] { - border-color: $color-brand; + border-color: var(--color-primary); } /* stylelint-disable-next-line order/order */ @@ -69,24 +69,24 @@ Dependencies. } &--positive { - background-color: $color-success; + background-color: var(--color-success); &[class*='text'] { - border-color: $color-success; + border-color: var(--color-success); } /* stylelint-disable-next-line order/order */ @media (prefers-color-scheme: dark) { - color: $color-neutral-900; + color: var(--color-neutral-dark); } } &--negative { - background-color: $color-error; - color: $color-neutral-100; + background-color: var(--color-error); + color: var(--color-neutral-light); &[class*='text'] { - border-color: $color-error; + border-color: var(--color-error); } } diff --git a/ui/src/css/components/_nav.scss b/ui/src/css/components/_nav.scss index 4b6ceac..27229da 100644 --- a/ui/src/css/components/_nav.scss +++ b/ui/src/css/components/_nav.scss @@ -22,7 +22,7 @@ Dependencies. } [aria-current] { - color: $color-brand; + color: var(--color-primary); font-weight: bold; } @@ -38,7 +38,7 @@ Dependencies. } .nav__list--dropdown { - background-color: $color-background; + background-color: var(--color-background); border: var(--border-width-s) solid; flex-direction: column; inset-block-start: 100%; @@ -86,7 +86,7 @@ Dependencies. // Using custom element. webui-disclosure:defined { .nav__list { - background-color: $color-background; + background-color: var(--color-background); border: var(--border-width-s) solid; inset-block-start: 100%; padding: var(--gutter-m); diff --git a/ui/src/css/components/_skin.scss b/ui/src/css/components/_skin.scss index 308e875..2dadf81 100644 --- a/ui/src/css/components/_skin.scss +++ b/ui/src/css/components/_skin.scss @@ -26,8 +26,8 @@ Dependencies. } &-2 { - background-color: $color-brand; - color: $color-neutral-100; + background-color: var(--color-primary); + color: var(--color-neutral-light); padding: var(--gutter-m); } diff --git a/ui/src/css/components/_skiplinks.scss b/ui/src/css/components/_skiplinks.scss index a8b67c5..cc3255d 100644 --- a/ui/src/css/components/_skiplinks.scss +++ b/ui/src/css/components/_skiplinks.scss @@ -9,8 +9,8 @@ Dependencies. position: absolute; &__link { - background-color: $color-brand; - color: $color-neutral-100; + background-color: var(--color-primary); + color: var(--color-neutral-light); display: inline-block; left: var(--gutter-m); min-inline-size: 10vw; diff --git a/ui/src/css/form/_checkbox.scss b/ui/src/css/form/_checkbox.scss index a1dbed5..27a3a87 100644 --- a/ui/src/css/form/_checkbox.scss +++ b/ui/src/css/form/_checkbox.scss @@ -15,7 +15,7 @@ Dependencies. inline-size: 1.5em; &:invalid:required:focus { - box-shadow: 0 0 0 var(--border-width-m) $color-error; + box-shadow: 0 0 0 var(--border-width-m) --color-error; } } } diff --git a/ui/src/css/form/_form.scss b/ui/src/css/form/_form.scss index f369c8a..bbe1141 100644 --- a/ui/src/css/form/_form.scss +++ b/ui/src/css/form/_form.scss @@ -25,7 +25,7 @@ Dependencies. /* stylelint-disable-next-line max-nesting-depth, no-descending-specificity */ &::after { - color: $color-error; + color: var(--color-error); content: '!'; display: block; font-size: 1em; @@ -41,7 +41,7 @@ Dependencies. :is(.label, .checkbox__label, .radio__label) { /* stylelint-disable-next-line max-nesting-depth */ &::after { - color: $color-success; + color: var(--color-success); content: '✓'; } } @@ -50,7 +50,7 @@ Dependencies. // Errors rendered directly in HTML, or via JavaScript. &__error { - color: $color-error; + color: var(--color-error); } &__field--has-error { @@ -83,20 +83,20 @@ Dependencies. // Native HTML5 validation. &:valid:required { background-color: hsl(var(--color-accent-positive) / 10%); - border-color: $color-success; + border-color: var(--color-success); border-width: var(--border-width-m); } &:user-invalid:required { background-color: hsl(var(--color-accent-negative) / 10%); - border-color: $color-error; + border-color: var(--color-error); border-width: var(--border-width-m); } // ARIA. &[aria-invalid='true'] { background-color: hsl(var(--color-accent-negative) / 10%); - border-color: $color-error; + border-color: var(--color-error); border-width: var(--border-width-m); } } diff --git a/ui/src/css/form/_radio.scss b/ui/src/css/form/_radio.scss index 8377dd7..4e2836d 100644 --- a/ui/src/css/form/_radio.scss +++ b/ui/src/css/form/_radio.scss @@ -15,7 +15,7 @@ Dependencies. inline-size: 1.5em; &:invalid:required:focus { - box-shadow: 0 0 0 var(--border-width-m) $color-error; + box-shadow: 0 0 0 var(--border-width-m) --color-error; } } } diff --git a/ui/src/css/form/_select.scss b/ui/src/css/form/_select.scss index 867d00b..adaa042 100644 --- a/ui/src/css/form/_select.scss +++ b/ui/src/css/form/_select.scss @@ -8,7 +8,7 @@ Basic component styles are in "form.css". .select { @media (prefers-color-scheme: dark) { option { - color: $color-neutral-900; + color: var(--color-neutral-dark); } } } diff --git a/ui/src/css/global/_reset.scss b/ui/src/css/global/_reset.scss index 6fd3bd4..81dd853 100644 --- a/ui/src/css/global/_reset.scss +++ b/ui/src/css/global/_reset.scss @@ -18,7 +18,7 @@ Dependencies. @use '../base' as *; html { - accent-color: $color-brand; + accent-color: var(--color-primary); color-scheme: light dark; /* stylelint-disable-next-line property-no-unknown */ interpolate-size: allow-keywords; @@ -43,8 +43,8 @@ html { @media (prefers-reduced-motion: no-preference) { scroll-behavior: smooth; } - background-color: $color-background; - color: $base-color; + background-color: var(--color-background); + color: var(--color-text); min-block-size: 100vh; // 100dvb might have performance implications. } diff --git a/ui/src/css/global/_typography.scss b/ui/src/css/global/_typography.scss index 6523937..4dc09a5 100644 --- a/ui/src/css/global/_typography.scss +++ b/ui/src/css/global/_typography.scss @@ -91,11 +91,11 @@ Validation styles. ---------------------------------------------------------------------------- */ .error { - color: $color-error; + color: var(--color-error); } .success { - color: $color-success; + color: var(--color-success); } /* diff --git a/ui/src/css/web-components/_webui-carousel.scss b/ui/src/css/web-components/_webui-carousel.scss index 1f5b876..694045d 100644 --- a/ui/src/css/web-components/_webui-carousel.scss +++ b/ui/src/css/web-components/_webui-carousel.scss @@ -27,7 +27,7 @@ webui-carousel { // Identify current slide (when using PREV|NEXT buttons). .is-current:not(:focus-visible) { - box-shadow: inset 0 0 0 var(--border-width-l) $color-brand; // For demo purposes. + box-shadow: inset 0 0 0 var(--border-width-l) var(--color-primary); // For demo purposes. } .carousel__controls { @@ -49,8 +49,8 @@ webui-carousel { padding: var(--gutter-s); &.is-current { - background-color: $color-brand; - color: $color-brand; + background-color: var(--color-primary); + color: var(--color-primary); } } } diff --git a/ui/src/css/web-components/_webui-image-gallery.scss b/ui/src/css/web-components/_webui-image-gallery.scss index 06beff2..d4f26a0 100644 --- a/ui/src/css/web-components/_webui-image-gallery.scss +++ b/ui/src/css/web-components/_webui-image-gallery.scss @@ -49,7 +49,7 @@ webui-image-gallery { } .modal__close { - background: $color-neutral-100; + background: var(--color-neutral-light); margin: var(--gutter-s); } } diff --git a/ui/src/css/web-components/_webui-make-clickable.scss b/ui/src/css/web-components/_webui-make-clickable.scss index 7121e48..76ebe01 100644 --- a/ui/src/css/web-components/_webui-make-clickable.scss +++ b/ui/src/css/web-components/_webui-make-clickable.scss @@ -25,7 +25,7 @@ webui-make-clickable { // Visible focus state only if 'data-url' link receives keyboard focus. &:focus-within { &:has([data-url]:focus-visible) { - box-shadow: 0 0 0 var(--border-width-l) $color-focus; + box-shadow: 0 0 0 var(--border-width-l) --color-focus; outline: var(--border-width-l) solid transparent; // So high contrast mode works. } } diff --git a/ui/src/css/web-components/_webui-modal.scss b/ui/src/css/web-components/_webui-modal.scss index 7571a3b..227436d 100644 --- a/ui/src/css/web-components/_webui-modal.scss +++ b/ui/src/css/web-components/_webui-modal.scss @@ -19,13 +19,13 @@ webui-modal { // Browser already applies "position: fixed" and "width: fit-content". .modal__dialog { - background: $color-neutral-100; + background: var(--color-neutral-light); margin: auto; padding: 0 var(--gutter-m) var(--gutter-m); /* stylelint-disable-next-line order/order */ @media (prefers-color-scheme: dark) { - background: $color-neutral-900; + background: var(--color-neutral-dark); } &::backdrop { @@ -35,14 +35,14 @@ webui-modal { } .modal__header { - background: $color-neutral-100; + background: var(--color-neutral-light); display: flex; justify-content: flex-end; padding-block-start: var(--gutter-m); /* stylelint-disable-next-line order/order */ @media (prefers-color-scheme: dark) { - background: $color-neutral-900; + background: var(--color-neutral-dark); } } diff --git a/ui/src/css/web-components/_webui-notify.scss b/ui/src/css/web-components/_webui-notify.scss index a5603f2..83632a8 100644 --- a/ui/src/css/web-components/_webui-notify.scss +++ b/ui/src/css/web-components/_webui-notify.scss @@ -18,17 +18,17 @@ webui-notify { &[data-success] { background: hsl(var(--color-accent-positive) / 15%); - border-color: $color-success; + border-color: var(--color-success); } &[data-warning] { background: hsl(var(--color-accent-neutral) / 15%); - border-color: $color-notify; + border-color: var(--color-notify); } &[data-error] { background: hsl(var(--color-accent-negative) / 15%); - border-color: $color-error; + border-color: var(--color-error); } [data-close] { diff --git a/ui/src/css/web-components/_webui-range-input.scss b/ui/src/css/web-components/_webui-range-input.scss index a8f93e9..ae63057 100644 --- a/ui/src/css/web-components/_webui-range-input.scss +++ b/ui/src/css/web-components/_webui-range-input.scss @@ -26,7 +26,7 @@ webui-range-input { &::-webkit-slider-thumb, &::-moz-range-thumb { - background-color: $color-brand; + background-color: var(--color-primary); block-size: var(--icon-size-l); border: 0; border-radius: 50%; @@ -36,7 +36,7 @@ webui-range-input { &::-webkit-slider-runnable-track, &::-moz-range-track { - background-color: hsl(var(--color-text) / 20%); + background-color: hsl(var(--color-neutral-700) / 20%); block-size: var(--slider-height); } } diff --git a/ui/src/css/web-components/_webui-tabs.scss b/ui/src/css/web-components/_webui-tabs.scss index e86a11b..adab1a1 100644 --- a/ui/src/css/web-components/_webui-tabs.scss +++ b/ui/src/css/web-components/_webui-tabs.scss @@ -51,7 +51,7 @@ webui-tabs { } [role='tab'] { - background-color: $color-neutral-100; + background-color: var(--color-neutral-light); padding: var(--gutter-s); text-decoration: none; transition: background-color var(--animation-fast); @@ -61,13 +61,13 @@ webui-tabs { } &[aria-selected='true'] { - background-color: $color-brand; - color: $color-neutral-100; + background-color: var(--color-primary); + color: var(--color-neutral-light); } /* stylelint-disable-next-line order/order */ @media (prefers-color-scheme: dark) { - background-color: hsl(var(--color-neutral-100) / 30%); + background-color: hsl(var(--color-neutral-200) / 30%); /* stylelint-disable max-nesting-depth */ &[aria-selected='true'] { diff --git a/ui/src/css/web-components/_webui-toggle.scss b/ui/src/css/web-components/_webui-toggle.scss index 2ee8001..ce97d03 100644 --- a/ui/src/css/web-components/_webui-toggle.scss +++ b/ui/src/css/web-components/_webui-toggle.scss @@ -23,14 +23,14 @@ webui-toggle { [aria-checked='false'] { .toggle__off { - background-color: hsl(var(--color-text) / 30%); + background-color: hsl(var(--color-neutral-700) / 30%); } } [aria-checked='true'] { .toggle__on { - background-color: $color-brand; - color: $color-neutral-100; + background-color: var(--color-primary); + color: var(--color-neutral-light); } }