From 50a9e638ce1794a9e4fcd22f2f0f64d56978bb4b Mon Sep 17 00:00:00 2001 From: dvdherron Date: Mon, 3 Nov 2025 18:16:28 +0100 Subject: [PATCH 01/21] add color theme demo files --- src/color-theme/index.html | 152 +++++++ src/color-theme/script.js | 35 ++ src/color-theme/style.css | 862 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1049 insertions(+) create mode 100644 src/color-theme/index.html create mode 100644 src/color-theme/script.js create mode 100644 src/color-theme/style.css diff --git a/src/color-theme/index.html b/src/color-theme/index.html new file mode 100644 index 0000000..7e2c22c --- /dev/null +++ b/src/color-theme/index.html @@ -0,0 +1,152 @@ + + + + + + + Baseline Color Theme Demo + + + + + +
+
+

Baseline Radio

+

the color theme color-mix playlist

+
+ + +
+ +
+ +
+

Baseline Radio footer information

+
+
+ + + diff --git a/src/color-theme/script.js b/src/color-theme/script.js new file mode 100644 index 0000000..b89b573 --- /dev/null +++ b/src/color-theme/script.js @@ -0,0 +1,35 @@ +const pressedButton = '[data-scheme][aria-pressed="true"]'; + +const setScheme = (scheme) => { + const target = document.querySelector(`[data-scheme="${scheme}"]`); + document.documentElement.setAttribute('data-scheme', scheme); + document.querySelector(pressedButton).setAttribute('aria-pressed', 'false'); + target.setAttribute('aria-pressed', 'true'); +}; + +const handleSchemeSelection = (event) => { + const target = event.target; + const isPressed = target.getAttribute('aria-pressed'); + const scheme = target.getAttribute('data-scheme'); + + if (isPressed !== 'true') { + setScheme(scheme); + localStorage.setItem('data-scheme', scheme); + } +}; + +const setInitialScheme = () => { + const savedScheme = localStorage.getItem('data-scheme'); + if (savedScheme) { + setScheme(savedScheme); + } +}; + +setInitialScheme(); + +const themePicker = document.querySelector(`[data-options="theme"]`); +const schemeButtons = themePicker.querySelectorAll(`[data-scheme]`); + +schemeButtons.forEach((button) => { + button.addEventListener('click', handleSchemeSelection); +}); diff --git a/src/color-theme/style.css b/src/color-theme/style.css new file mode 100644 index 0000000..4e439fd --- /dev/null +++ b/src/color-theme/style.css @@ -0,0 +1,862 @@ +@layer reset, base, theme, layout; + +[data-button] { + align-items: center; + background: var(--btn-bg, var(--action-color)); + border: 1px solid var(--btn-border, transparent); + color: var(--btn-text, var(--background-color)); + cursor: pointer; + display: inline-flex; + font-size: inherit; + font-weight: 600; + justify-content: center; + padding: 0.25em var(--gap); + + &:hover, + &:focus { + --btn-bg: var(--active-color); + --btn-border: var(--border-color); + } + + &[aria-pressed="true"] { + --btn-bg: var(--background-color); + --btn-border: var(--active-color); + --btn-text: var(--text-color); + } +} + +[data-playlist-item] { + align-items: center; + border-inline-start: max(2cqi, 2ch) solid color-mix(in oklab, var(--song-color) 80%, canvas); + color: canvasText; + column-gap: calc(var(--gap) / 4); + display: grid; + grid-template: + "song" auto + "artist" auto + "rating" auto/ 100%; + font-size: var(--text-small); + justify-items: start; + padding: calc(var(--gap) / 2); + + @container (min-width: 30em) { + grid-template: + "song rating" auto + "artist artist" auto / minmax(0, max-content) max-content; + } + + p { + margin: 0; + } + + [data-song] { + font-family: var(--sans-serif-font); + font-weight: bold; + grid-area: song; + } + + .top-pick { + background: var(--surface-feature); + border: 2px solid var(--border-color); + border-radius: 4px; + font-family: var(--sans-serif-font); + font-size: var(--text-xsmall); + font-weight: bold; + color: canvas; + padding: 0.25cqi 0.5cqi; + grid-area: rating; + } + + .artist { + font-size: var(--text-small); + grid-area: artist; + } +} + +[data-playlist-item~="red"] { + --song-color: oklch(0.5466 0.2208 26.67); +} + +[data-playlist-item~="yellow"] { + --song-color: oklch(0.9815 0.0884 107.23); +} + +[data-playlist-item~="orange"] { + --song-color: oklch(0.7927 0.141 70.67); +} + +[data-playlist-item~="indigo"] { + --song-color: oklch(0.4738 0.3005 273.86); +} + +[data-playlist-item~="blue"] { + --song-color: oklch(0.335 0.10866 259.73); +} + +[data-playlist-item~="purple"] { + --song-color: oklch(0.5045 0.1487 277.84); +} + +[data-playlist-item~="green"] { + --song-color: oklch(0.561 0.1813 141.97); +} + +[data-playlist-item~="pink"] { + --song-color: color-mix(in oklab, oklch(54.66% 0.225 340), white); +} + +[data-playlist-item~="black"] { + --song-color: oklch(0.7% 0.007 333); +} + +[data-playlist-item~="white"] { + --song-color: oklch(99.5% 0 333); +} + +@layer layout { + body { + container: body / inline-size; + display: grid; + grid-template: + "header" auto + "main" 1fr + "footer" auto; + } + + .page-header { + display: flex; + flex-wrap: wrap; + gap: var(--gap); + grid-area: header; + align-content: center; + container: header / inline-size; + padding: var(--gap); + + @container (min-width: 20em) { + justify-content: end; + } + } + + nav { + display: flex; + align-items: center; + } + + .nav-list { + align-items: center; + display: flex; + flex-wrap: wrap; + font-family: var(--sans-serif-font); + gap: var(--gap); + margin-block-end: 0; + + @container header (min-width: 20em) { + justify-content: end; + } + + a { + padding: calc(var(--gap) / 2); + } + } + + details { + font-family: var(--sans-serif-font); + position: relative; + + .dropdown { + background: var(--surface-light); + border: thin solid var(--border-color); + padding: var(--gap); + position: absolute; + + @container header (min-width: 20em) { + inset-inline-end: 0; + } + + fieldset { + border-color: var(--border-color); + } + } + + [data-options~="theme"] { + display: grid; + font-size: var(--text-small); + gap: calc(var(--gap) / 2); + } + } + + main { + container: main-content / inline-size; + display: grid; + gap: var(--gap); + grid-area: main; + grid-template: + "header" auto + "playlist" auto/ 100%; + margin: var(--gap); + + @container body (min-width: 25em) { + --summary-text: end; + grid-template: + "header playlist" auto + / 50vw 1fr; + + .content-header { + align-content: start; + display: grid; + font-family: var(--sans-serif-font); + grid-area: header; + margin: 3lh 0; + justify-items: end; + } + + .main-heading { + margin-block-end: 0; + } + } + + .summary { + text-align: var(--summary-text, start); + margin-block: 0; + text-wrap: balance; + } + } + + .playlist { + @container body (max-width: 25em) { + --list-padding: calc(var(--gap) * 2); + } + } + + [data-layout="footer"] { + display: grid; + font-family: var(--sans-serif-font); + font-size: var(--text-small); + grid-area: footer; + grid-template: + "contact" 1fr + "footer" auto / 100%; + padding: calc(var(--gap) * 2); + + @container (min-width: 30em) { + grid-template: + "contact ." 1fr + "footer footer" auto / 1fr 1fr; + } + } + + [data-layout="contact-form"] { + background: var(--surface-light); + padding: var(--gap); + } + + [data-form] { + display: grid; + gap: var(--gap); + + .field-group { + display: grid; + gap: var(--gap); + grid-template-columns: repeat(auto-fit, minmax(12em, 1fr)); + } + + [data-input*="text"] { + --focus-ring: transparent; + border: 2px solid var(--input-border, var(--border-color)); + padding: calc(var(--gap) / 4); + + &:focus { + --input-border: transparent; + --outline-offset: 0; + --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h); + } + + &:user-invalid:not(:active, :focus) { + --input-border: var(--error-color); + } + } + + [data-field] { + display: grid; + grid-template: + "label" auto + "input" auto / 100%; + } + } + + footer { + grid-area: footer; + } +} + +@layer theme { + html { + color-scheme: light dark; + + &[data-scheme="light"] { + color-scheme: light; + } + + &[data-scheme="dark"] { + color-scheme: dark; + } + + accent-color: var(--accent-color); + + --text-xsmall: clamp(0.748rem, 0.624rem + 0.254cqi, 1.25rem); + --text-small: clamp(0.938rem, 0.824rem + 0.568cqi, 1.25rem); + --text-normal: clamp(1.25rem, 1.023rem + 1.136cqi, 1.875rem); + --text-large: clamp(1.35rem, 0.818rem + 2.659cqi, 2.813rem); + --text-xlarge: clamp(1.7rem, 0.784rem + 4.58cqi, 4.219rem); + --gap: clamp(2cqi, 0.5lh, 5cqi); + + --base-color: light-dark(oklch(33.5% 0.10866 259.73), + oklch(90.5% 0.045 259.73)); + + --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), + oklch(from var(--base-color) 80% 0.202 h)); + --surface-light: color-mix(in oklab, + var(--background-color) 80%, + var(--base-color)); + --error-color: oklch(from var(--base-color) l 0.395 24); + + --text-color: canvasText; + --background-color: light-dark(oklch(95.5% 0 162), + oklch(22.635% 0.01351 291.83)); + --border-color: color-mix(in oklab, var(--base-color), grey); + --accent-color: oklch(from var(--base-color) l 0.185 calc(h - 120)); + --action-color: var(--base-color); + --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) calc(c + 0.08) h), + oklch(from var(--base-color) calc(l * 0.9) calc(c + 0.05) h)); + --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); + + --serif-font: "Nimbus Mono PS", + "Courier New", + monospace; + --sans-serif-font: Bahnschrift, + "DIN Alternate", + "Franklin Gothic Medium", + "Nimbus Sans Narrow", + sans-serif-condensed, + sans-serif; + } + + body { + background-color: var(--background-color); + color: var(--text-color); + font-family: var(--serif-font); + transition: + background 200ms linear, + color 200ms linear; + } + + h1 { + font-family: var(--sans-serif-font); + font-size: var(--text-xlarge); + text-wrap: balance; + } + + :focus-visible { + outline: 3px solid var(--focus-ring, canvasText); + outline-offset: var(--outline-offset, 0.15em); + } + + :any-link { + color: var(--link-color, var(--action-color)); + text-decoration: underline; + text-decoration-color: var(--underline-color, var(--accent-color)); + text-decoration-thickness: var(--underline-thickness, 0.1em); + text-underline-offset: var(--underline-offset, 0.15em); + transition: + color 150ms, + text-decoration-color 150ms, + text-decoration-thickness 150ms ease-out; + + &:hover, + &:focus { + --link-color: var(--accent-color); + --underline-thickness: 0.25em; + } + } +} + +@layer base { + body { + font-size: var(--text-normal); + line-height: 1.2; + overflow-wrap: break-word; + } +} + +@layer reset { + * { + box-sizing: border-box; + } + + html { + block-size: 100%; + } + + body { + margin: unset; + min-block-size: 100%; + } + + picture { + display: contents; + } + + img { + display: block; + } + + img, + svg { + max-inline-size: 100%; + } + + input, + button, + textarea, + select { + font: inherit; + } + + ul, + ol { + list-style: none; + margin-block-start: 0; + padding-inline-start: var(--list-padding, 0); + } +} + +@layer reset, base, theme, layout; + +[data-button] { + align-items: center; + background: var(--btn-bg, var(--action-color)); + border: 1px solid var(--btn-border, transparent); + color: var(--btn-text, var(--background-color)); + cursor: pointer; + display: inline-flex; + font-size: inherit; + font-weight: 600; + justify-content: center; + padding: 0.25em var(--gap); + + &:hover, + &:focus { + --btn-bg: var(--active-color); + --btn-border: var(--border-color); + } + + &[aria-pressed="true"] { + --btn-bg: var(--background-color); + --btn-border: var(--active-color); + --btn-text: var(--text-color); + } +} + +[data-playlist-item] { + align-items: center; + border-inline-start: max(2cqi, 2ch) solid color-mix(in oklab, var(--song-color) 80%, canvas); + color: canvasText; + column-gap: calc(var(--gap) / 4); + display: grid; + grid-template: + "song" auto + "artist" auto + "rating" auto/ 100%; + font-size: var(--text-small); + justify-items: start; + padding: calc(var(--gap) / 2); + + @container (min-width: 30em) { + grid-template: + "song rating" auto + "artist artist" auto / minmax(0, max-content) max-content; + } + + p { + margin: 0; + } + + [data-song] { + font-family: var(--sans-serif-font); + font-weight: bold; + grid-area: song; + } + + .top-pick { + background: var(--surface-feature); + border: 2px solid var(--border-color); + border-radius: 4px; + font-family: var(--sans-serif-font); + font-size: var(--text-xsmall); + font-weight: bold; + color: canvas; + padding: 0.25cqi 0.5cqi; + grid-area: rating; + } + + .artist { + font-size: var(--text-small); + grid-area: artist; + } +} + +[data-playlist-item~="red"] { + --song-color: oklch(0.5466 0.2208 26.67); +} + +[data-playlist-item~="yellow"] { + --song-color: oklch(0.9815 0.0884 107.23); +} + +[data-playlist-item~="orange"] { + --song-color: oklch(0.7927 0.141 70.67); +} + +[data-playlist-item~="indigo"] { + --song-color: oklch(0.4738 0.3005 273.86); +} + +[data-playlist-item~="blue"] { + --song-color: var(--base-color); +} + +[data-playlist-item~="purple"] { + --song-color: oklch(0.5045 0.1487 277.84); +} + +[data-playlist-item~="green"] { + --song-color: oklch(0.561 0.1813 141.97); +} + +[data-playlist-item~="pink"] { + --song-color: color-mix(in oklab, oklch(54.66% 0.225 340), white); +} + +[data-playlist-item~="black"] { + --song-color: oklch(0.7% 0.007 333); +} + +[data-playlist-item~="white"] { + --song-color: oklch(99.5% 0 333); +} + +@layer layout { + body { + container: body / inline-size; + display: grid; + grid-template: + "header" auto + "main" 1fr + "footer" auto; + } + + .page-header { + display: flex; + flex-wrap: wrap; + gap: var(--gap); + grid-area: header; + align-content: center; + container: header / inline-size; + padding: var(--gap); + + @container (min-width: 20em) { + justify-content: end; + } + } + + nav { + display: flex; + align-items: center; + } + + .nav-list { + align-items: center; + display: flex; + flex-wrap: wrap; + font-family: var(--sans-serif-font); + gap: var(--gap); + margin-block-end: 0; + + @container header (min-width: 20em) { + justify-content: end; + } + + a { + padding: calc(var(--gap) / 2); + } + } + + details { + font-family: var(--sans-serif-font); + position: relative; + + .dropdown { + background: var(--surface-light); + border: thin solid var(--border-color); + padding: var(--gap); + position: absolute; + + @container header (min-width: 20em) { + inset-inline-end: 0; + } + + fieldset { + border-color: var(--border-color); + } + } + + [data-options~="theme"] { + display: grid; + font-size: var(--text-small); + gap: calc(var(--gap) / 2); + } + } + + main { + container: main-content / inline-size; + display: grid; + gap: var(--gap); + grid-area: main; + grid-template: + "header" auto + "playlist" auto/ 100%; + margin: var(--gap); + + @container body (min-width: 25em) { + --summary-text: end; + grid-template: + "header playlist" auto + / 50vw 1fr; + + .content-header { + align-content: start; + display: grid; + font-family: var(--sans-serif-font); + grid-area: header; + margin: 3lh 0; + justify-items: end; + } + + .main-heading { + margin-block-end: 0; + } + } + + .summary { + text-align: var(--summary-text, start); + margin-block: 0; + text-wrap: balance; + } + } + + .playlist { + @container body (max-width: 25em) { + --list-padding: calc(var(--gap) * 2); + } + } + + [data-layout="footer"] { + display: grid; + font-family: var(--sans-serif-font); + font-size: var(--text-small); + grid-area: footer; + grid-template: + "contact" 1fr + "footer" auto / 100%; + padding: calc(var(--gap) * 2); + + @container (min-width: 30em) { + grid-template: + "contact ." 1fr + "footer footer" auto / 1fr 1fr; + } + } + + [data-layout="contact-form"] { + background: var(--surface-light); + padding: var(--gap); + } + + [data-form] { + display: grid; + gap: var(--gap); + + .field-group { + display: grid; + gap: var(--gap); + grid-template-columns: repeat(auto-fit, minmax(12em, 1fr)); + } + + [data-input*="text"] { + --focus-ring: transparent; + border: 2px solid var(--input-border, var(--border-color)); + padding: calc(var(--gap) / 4); + + &:focus { + --input-border: transparent; + --outline-offset: 0; + --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h); + } + + &:user-invalid { + --input-border: 2px solid red; + } + } + + [data-field] { + display: grid; + grid-template: + "label" auto + "input" auto / 100%; + } + } + + footer { + grid-area: footer; + } +} + +@layer theme { + html { + color-scheme: light dark; + + &[data-scheme="light"] { + color-scheme: light; + } + + &[data-scheme="dark"] { + color-scheme: dark; + } + + accent-color: var(--accent-color); + + --text-xsmall: clamp(0.748rem, 0.624rem + 0.254cqi, 1.25rem); + --text-small: clamp(0.938rem, 0.824rem + 0.568cqi, 1.25rem); + --text-normal: clamp(1.25rem, 1.023rem + 1.136cqi, 1.875rem); + --text-large: clamp(1.35rem, 0.818rem + 2.659cqi, 2.813rem); + --text-xlarge: clamp(1.7rem, 0.784rem + 4.58cqi, 4.219rem); + --gap: clamp(2cqi, 0.5lh, 5cqi); + + --base-color: light-dark(oklch(33.5% 0.10866 259.73), + oklch(90.5% 0.045 259.73)); + + --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), + oklch(from var(--base-color) 80% 0.202 h)); + --surface-light: color-mix(in oklab, + var(--background-color) 80%, + var(--base-color)); + + --text-color: canvasText; + --background-color: light-dark(oklch(95.5% 0 162), + oklch(22.635% 0.01351 291.83)); + --border-color: color-mix(in oklab, var(--base-color), grey); + --accent-color: oklch(from var(--base-color) l 0.185 calc(h - 120)); + --action-color: var(--base-color); + --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) calc(c + 0.08) h), + oklch(from var(--base-color) calc(l * 0.9) calc(c + 0.05) h)); + --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); + + --serif-font: "Nimbus Mono PS", + "Courier New", + monospace; + --sans-serif-font: Bahnschrift, + "DIN Alternate", + "Franklin Gothic Medium", + "Nimbus Sans Narrow", + sans-serif-condensed, + sans-serif; + } + + body { + background-color: var(--background-color); + color: var(--text-color); + font-family: var(--serif-font); + transition: + background 200ms linear, + color 200ms linear; + } + + h1 { + font-family: var(--sans-serif-font); + font-size: var(--text-xlarge); + text-wrap: balance; + } + + :focus-visible { + outline: 3px solid var(--focus-ring, canvasText); + outline-offset: var(--outline-offset, 0.15em); + } + + :any-link { + color: var(--link-color, var(--action-color)); + text-decoration: underline; + text-decoration-color: var(--underline-color, var(--accent-color)); + text-decoration-thickness: var(--underline-thickness, 0.1em); + text-underline-offset: var(--underline-offset, 0.15em); + transition: + color 150ms, + text-decoration-color 150ms, + text-decoration-thickness 150ms ease-out; + + &:hover, + &:focus { + --link-color: var(--accent-color); + --underline-thickness: 0.25em; + } + } +} + +@layer base { + body { + font-size: var(--text-normal); + line-height: 1.2; + overflow-wrap: break-word; + } +} + +@layer reset { + * { + box-sizing: border-box; + } + + html { + block-size: 100%; + } + + body { + margin: unset; + min-block-size: 100%; + } + + picture { + display: contents; + } + + img { + display: block; + } + + img, + svg { + max-inline-size: 100%; + } + + input, + button, + textarea, + select { + font: inherit; + } + + ul, + ol { + list-style: none; + margin-block-start: 0; + padding-inline-start: var(--list-padding, 0); + } +} From 19e17111b19de8801d7855461642a2f82fb3fd0a Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 4 Nov 2025 17:37:37 +0100 Subject: [PATCH 02/21] initial cleanup --- src/color-theme/style.css | 460 +------------------------------------- 1 file changed, 11 insertions(+), 449 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 4e439fd..113f5b5 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -56,439 +56,7 @@ } .top-pick { - background: var(--surface-feature); - border: 2px solid var(--border-color); - border-radius: 4px; - font-family: var(--sans-serif-font); - font-size: var(--text-xsmall); - font-weight: bold; - color: canvas; - padding: 0.25cqi 0.5cqi; - grid-area: rating; - } - - .artist { - font-size: var(--text-small); - grid-area: artist; - } -} - -[data-playlist-item~="red"] { - --song-color: oklch(0.5466 0.2208 26.67); -} - -[data-playlist-item~="yellow"] { - --song-color: oklch(0.9815 0.0884 107.23); -} - -[data-playlist-item~="orange"] { - --song-color: oklch(0.7927 0.141 70.67); -} - -[data-playlist-item~="indigo"] { - --song-color: oklch(0.4738 0.3005 273.86); -} - -[data-playlist-item~="blue"] { - --song-color: oklch(0.335 0.10866 259.73); -} - -[data-playlist-item~="purple"] { - --song-color: oklch(0.5045 0.1487 277.84); -} - -[data-playlist-item~="green"] { - --song-color: oklch(0.561 0.1813 141.97); -} - -[data-playlist-item~="pink"] { - --song-color: color-mix(in oklab, oklch(54.66% 0.225 340), white); -} - -[data-playlist-item~="black"] { - --song-color: oklch(0.7% 0.007 333); -} - -[data-playlist-item~="white"] { - --song-color: oklch(99.5% 0 333); -} - -@layer layout { - body { - container: body / inline-size; - display: grid; - grid-template: - "header" auto - "main" 1fr - "footer" auto; - } - - .page-header { - display: flex; - flex-wrap: wrap; - gap: var(--gap); - grid-area: header; - align-content: center; - container: header / inline-size; - padding: var(--gap); - - @container (min-width: 20em) { - justify-content: end; - } - } - - nav { - display: flex; - align-items: center; - } - - .nav-list { - align-items: center; - display: flex; - flex-wrap: wrap; - font-family: var(--sans-serif-font); - gap: var(--gap); - margin-block-end: 0; - - @container header (min-width: 20em) { - justify-content: end; - } - - a { - padding: calc(var(--gap) / 2); - } - } - - details { - font-family: var(--sans-serif-font); - position: relative; - - .dropdown { - background: var(--surface-light); - border: thin solid var(--border-color); - padding: var(--gap); - position: absolute; - - @container header (min-width: 20em) { - inset-inline-end: 0; - } - - fieldset { - border-color: var(--border-color); - } - } - - [data-options~="theme"] { - display: grid; - font-size: var(--text-small); - gap: calc(var(--gap) / 2); - } - } - - main { - container: main-content / inline-size; - display: grid; - gap: var(--gap); - grid-area: main; - grid-template: - "header" auto - "playlist" auto/ 100%; - margin: var(--gap); - - @container body (min-width: 25em) { - --summary-text: end; - grid-template: - "header playlist" auto - / 50vw 1fr; - - .content-header { - align-content: start; - display: grid; - font-family: var(--sans-serif-font); - grid-area: header; - margin: 3lh 0; - justify-items: end; - } - - .main-heading { - margin-block-end: 0; - } - } - - .summary { - text-align: var(--summary-text, start); - margin-block: 0; - text-wrap: balance; - } - } - - .playlist { - @container body (max-width: 25em) { - --list-padding: calc(var(--gap) * 2); - } - } - - [data-layout="footer"] { - display: grid; - font-family: var(--sans-serif-font); - font-size: var(--text-small); - grid-area: footer; - grid-template: - "contact" 1fr - "footer" auto / 100%; - padding: calc(var(--gap) * 2); - - @container (min-width: 30em) { - grid-template: - "contact ." 1fr - "footer footer" auto / 1fr 1fr; - } - } - - [data-layout="contact-form"] { - background: var(--surface-light); - padding: var(--gap); - } - - [data-form] { - display: grid; - gap: var(--gap); - - .field-group { - display: grid; - gap: var(--gap); - grid-template-columns: repeat(auto-fit, minmax(12em, 1fr)); - } - - [data-input*="text"] { - --focus-ring: transparent; - border: 2px solid var(--input-border, var(--border-color)); - padding: calc(var(--gap) / 4); - - &:focus { - --input-border: transparent; - --outline-offset: 0; - --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h); - } - - &:user-invalid:not(:active, :focus) { - --input-border: var(--error-color); - } - } - - [data-field] { - display: grid; - grid-template: - "label" auto - "input" auto / 100%; - } - } - - footer { - grid-area: footer; - } -} - -@layer theme { - html { - color-scheme: light dark; - - &[data-scheme="light"] { - color-scheme: light; - } - - &[data-scheme="dark"] { - color-scheme: dark; - } - - accent-color: var(--accent-color); - - --text-xsmall: clamp(0.748rem, 0.624rem + 0.254cqi, 1.25rem); - --text-small: clamp(0.938rem, 0.824rem + 0.568cqi, 1.25rem); - --text-normal: clamp(1.25rem, 1.023rem + 1.136cqi, 1.875rem); - --text-large: clamp(1.35rem, 0.818rem + 2.659cqi, 2.813rem); - --text-xlarge: clamp(1.7rem, 0.784rem + 4.58cqi, 4.219rem); - --gap: clamp(2cqi, 0.5lh, 5cqi); - - --base-color: light-dark(oklch(33.5% 0.10866 259.73), - oklch(90.5% 0.045 259.73)); - - --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), - oklch(from var(--base-color) 80% 0.202 h)); - --surface-light: color-mix(in oklab, - var(--background-color) 80%, - var(--base-color)); - --error-color: oklch(from var(--base-color) l 0.395 24); - - --text-color: canvasText; - --background-color: light-dark(oklch(95.5% 0 162), - oklch(22.635% 0.01351 291.83)); - --border-color: color-mix(in oklab, var(--base-color), grey); - --accent-color: oklch(from var(--base-color) l 0.185 calc(h - 120)); - --action-color: var(--base-color); - --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) calc(c + 0.08) h), - oklch(from var(--base-color) calc(l * 0.9) calc(c + 0.05) h)); - --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); - - --serif-font: "Nimbus Mono PS", - "Courier New", - monospace; - --sans-serif-font: Bahnschrift, - "DIN Alternate", - "Franklin Gothic Medium", - "Nimbus Sans Narrow", - sans-serif-condensed, - sans-serif; - } - - body { - background-color: var(--background-color); - color: var(--text-color); - font-family: var(--serif-font); - transition: - background 200ms linear, - color 200ms linear; - } - - h1 { - font-family: var(--sans-serif-font); - font-size: var(--text-xlarge); - text-wrap: balance; - } - - :focus-visible { - outline: 3px solid var(--focus-ring, canvasText); - outline-offset: var(--outline-offset, 0.15em); - } - - :any-link { - color: var(--link-color, var(--action-color)); - text-decoration: underline; - text-decoration-color: var(--underline-color, var(--accent-color)); - text-decoration-thickness: var(--underline-thickness, 0.1em); - text-underline-offset: var(--underline-offset, 0.15em); - transition: - color 150ms, - text-decoration-color 150ms, - text-decoration-thickness 150ms ease-out; - - &:hover, - &:focus { - --link-color: var(--accent-color); - --underline-thickness: 0.25em; - } - } -} - -@layer base { - body { - font-size: var(--text-normal); - line-height: 1.2; - overflow-wrap: break-word; - } -} - -@layer reset { - * { - box-sizing: border-box; - } - - html { - block-size: 100%; - } - - body { - margin: unset; - min-block-size: 100%; - } - - picture { - display: contents; - } - - img { - display: block; - } - - img, - svg { - max-inline-size: 100%; - } - - input, - button, - textarea, - select { - font: inherit; - } - - ul, - ol { - list-style: none; - margin-block-start: 0; - padding-inline-start: var(--list-padding, 0); - } -} - -@layer reset, base, theme, layout; - -[data-button] { - align-items: center; - background: var(--btn-bg, var(--action-color)); - border: 1px solid var(--btn-border, transparent); - color: var(--btn-text, var(--background-color)); - cursor: pointer; - display: inline-flex; - font-size: inherit; - font-weight: 600; - justify-content: center; - padding: 0.25em var(--gap); - - &:hover, - &:focus { - --btn-bg: var(--active-color); - --btn-border: var(--border-color); - } - - &[aria-pressed="true"] { - --btn-bg: var(--background-color); - --btn-border: var(--active-color); - --btn-text: var(--text-color); - } -} - -[data-playlist-item] { - align-items: center; - border-inline-start: max(2cqi, 2ch) solid color-mix(in oklab, var(--song-color) 80%, canvas); - color: canvasText; - column-gap: calc(var(--gap) / 4); - display: grid; - grid-template: - "song" auto - "artist" auto - "rating" auto/ 100%; - font-size: var(--text-small); - justify-items: start; - padding: calc(var(--gap) / 2); - - @container (min-width: 30em) { - grid-template: - "song rating" auto - "artist artist" auto / minmax(0, max-content) max-content; - } - - p { - margin: 0; - } - - [data-song] { - font-family: var(--sans-serif-font); - font-weight: bold; - grid-area: song; - } - - .top-pick { - background: var(--surface-feature); + background: var(--highlight-color); border: 2px solid var(--border-color); border-radius: 4px; font-family: var(--sans-serif-font); @@ -703,8 +271,8 @@ --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h); } - &:user-invalid { - --input-border: 2px solid red; + &:user-invalid:not(:active, :focus) { + --input-border: red; } } @@ -742,8 +310,8 @@ --text-xlarge: clamp(1.7rem, 0.784rem + 4.58cqi, 4.219rem); --gap: clamp(2cqi, 0.5lh, 5cqi); - --base-color: light-dark(oklch(33.5% 0.10866 259.73), - oklch(90.5% 0.045 259.73)); + --base-color: light-dark(oklch(33.5% 0.133 259.73), + oklch(90.5% 0.046 259.73)); --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), oklch(from var(--base-color) 80% 0.202 h)); @@ -755,21 +323,15 @@ --background-color: light-dark(oklch(95.5% 0 162), oklch(22.635% 0.01351 291.83)); --border-color: color-mix(in oklab, var(--base-color), grey); - --accent-color: oklch(from var(--base-color) l 0.185 calc(h - 120)); + --accent-color: oklch(from var(--base-color) l c calc(h - 120)); --action-color: var(--base-color); - --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) calc(c + 0.08) h), - oklch(from var(--base-color) calc(l * 0.9) calc(c + 0.05) h)); + --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) c h), + oklch(from var(--base-color) calc(l * 0.9) c h)); --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); - --serif-font: "Nimbus Mono PS", - "Courier New", - monospace; - --sans-serif-font: Bahnschrift, - "DIN Alternate", - "Franklin Gothic Medium", - "Nimbus Sans Narrow", - sans-serif-condensed, - sans-serif; + --serif-font: "Nimbus Mono PS", "Courier New", monospace; + --sans-serif-font: Bahnschrift, "DIN Alternate", "Franklin Gothic Medium", "Nimbus Sans Narrow", + sans-serif-condensed, sans-serif; } body { From 2b1cc450cfec60e812028272a5f37286e7e77507 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Fri, 7 Nov 2025 17:59:07 +0100 Subject: [PATCH 03/21] add registered custom property example --- src/color-theme/style.css | 60 ++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 113f5b5..f746559 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -1,5 +1,12 @@ @layer reset, base, theme, layout; +@property --header-hue { + syntax: ''; + inherits: false; + initial-value: 100; +} + + [data-button] { align-items: center; background: var(--btn-bg, var(--action-color)); @@ -196,30 +203,39 @@ margin: var(--gap); @container body (min-width: 25em) { - --summary-text: end; + --heading-margin-block-end: 0; + --summary-text-align: end; grid-template: "header playlist" auto / 50vw 1fr; + } + } - .content-header { - align-content: start; - display: grid; - font-family: var(--sans-serif-font); - grid-area: header; - margin: 3lh 0; - justify-items: end; - } + .content-header { + font-family: var(--sans-serif-font); + grid-area: header; + margin: var(--content-header-margin-block, var(--gap)) 0; - .main-heading { - margin-block-end: 0; - } + @container body (min-width: 25em) { + --content-header-margin-block: 3lh; + align-content: start; + display: grid; + justify-items: end; } + } - .summary { - text-align: var(--summary-text, start); - margin-block: 0; - text-wrap: balance; - } + .main-heading { + background: linear-gradient(in oklch 90deg, canvastext 50%, oklch(from var(--base-color) l c var(--header-hue))); + background-clip: text; + color: transparent; + margin-block-end: var(--heading-margin-block-end, 0.15lh); + animation: header-switch 5s linear infinite; + } + + .summary { + text-align: var(--summary-text-align, start); + margin-block: 0; + text-wrap: balance; } .playlist { @@ -371,6 +387,16 @@ --underline-thickness: 0.25em; } } + + @keyframes header-switch { + from { + --header-hue: 26.67; + } + + to { + --header-hue: 277; + } + } } @layer base { From 5640b09d2bf05e25c107f860e00ae3451572d163 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Fri, 7 Nov 2025 18:06:59 +0100 Subject: [PATCH 04/21] add color-theme link to index page --- src/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.html b/src/index.html index aaa5501..a07f863 100644 --- a/src/index.html +++ b/src/index.html @@ -29,6 +29,7 @@

List of Demos

From 8e7571a0edce4339d8eeaa5aa1b74f6a1b246630 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 11 Nov 2025 21:48:56 +0100 Subject: [PATCH 05/21] color variable cleanup --- src/color-theme/index.html | 1 + src/color-theme/style.css | 17 ++++++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/color-theme/index.html b/src/color-theme/index.html index 7e2c22c..8af49c3 100644 --- a/src/color-theme/index.html +++ b/src/color-theme/index.html @@ -4,6 +4,7 @@ + Baseline Color Theme Demo diff --git a/src/color-theme/style.css b/src/color-theme/style.css index f746559..4f76292 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -34,8 +34,7 @@ [data-playlist-item] { align-items: center; - border-inline-start: max(2cqi, 2ch) solid color-mix(in oklab, var(--song-color) 80%, canvas); - color: canvasText; + border-inline-start: max(2cqi, 2ch) solid color-mix(in oklab, var(--song-color) 80%, var(--background-color)); column-gap: calc(var(--gap) / 4); display: grid; grid-template: @@ -63,13 +62,12 @@ } .top-pick { - background: var(--highlight-color); - border: 2px solid var(--border-color); + background: var(--surface-light); + border: 2px solid var(--highlight-color); border-radius: 4px; font-family: var(--sans-serif-font); font-size: var(--text-xsmall); font-weight: bold; - color: canvas; padding: 0.25cqi 0.5cqi; grid-area: rating; } @@ -225,7 +223,7 @@ } .main-heading { - background: linear-gradient(in oklch 90deg, canvastext 50%, oklch(from var(--base-color) l c var(--header-hue))); + background: linear-gradient(in oklch 90deg, var(--text-color) 50%, oklch(from var(--base-color) l c var(--header-hue))); background-clip: text; color: transparent; margin-block-end: var(--heading-margin-block-end, 0.15lh); @@ -263,6 +261,7 @@ [data-layout="contact-form"] { background: var(--surface-light); + border: thin solid var(--border-color); padding: var(--gap); } @@ -340,9 +339,9 @@ oklch(22.635% 0.01351 291.83)); --border-color: color-mix(in oklab, var(--base-color), grey); --accent-color: oklch(from var(--base-color) l c calc(h - 120)); - --action-color: var(--base-color); - --active-color: light-dark(oklch(from var(--base-color) calc(l / 0.85) c h), - oklch(from var(--base-color) calc(l * 0.9) c h)); + --action-color: oklch(from var(--base-color) l c calc(h + 180)); + --active-color: light-dark(oklch(from var(--action-color) calc(l / 0.85) c h), + oklch(from var(--action-color) calc(l * 0.9) c h)); --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); --serif-font: "Nimbus Mono PS", "Courier New", monospace; From c8e5c5966f2a0d22ad01ba52e2dda280730f8306 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Mon, 17 Nov 2025 15:02:02 +0100 Subject: [PATCH 06/21] demo cleanup to match article --- src/color-theme/style.css | 41 ++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 4f76292..9d27b12 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -6,6 +6,18 @@ initial-value: 100; } +@property --base-color-light { + syntax: ''; + inherits: false; + initial-value: oklch(43.7% 0.075 224); +} + +@property --base-color-dark { + syntax: ''; + inherits: false; + initial-value: oklch(89.2% 0.069 224); +} + [data-button] { align-items: center; @@ -18,6 +30,7 @@ font-weight: 600; justify-content: center; padding: 0.25em var(--gap); + transition: background 150ms ease-in; &:hover, &:focus { @@ -227,7 +240,7 @@ background-clip: text; color: transparent; margin-block-end: var(--heading-margin-block-end, 0.15lh); - animation: header-switch 5s linear infinite; + animation: header-hue-switch 5s ease-in-out infinite; } .summary { @@ -261,7 +274,7 @@ [data-layout="contact-form"] { background: var(--surface-light); - border: thin solid var(--border-color); + border: thin solid var(--border-highlight); padding: var(--gap); } @@ -325,9 +338,17 @@ --text-xlarge: clamp(1.7rem, 0.784rem + 4.58cqi, 4.219rem); --gap: clamp(2cqi, 0.5lh, 5cqi); - --base-color: light-dark(oklch(33.5% 0.133 259.73), - oklch(90.5% 0.046 259.73)); + --base-color: light-dark(var(--base-color-light), var(--base-color-dark)); + --accent-color: oklch(from var(--base-color) l c calc(h + 120)); + --complement-color: oklch(from var(--base-color) l c calc(h + 180)); + --action-color: oklch(from var(--base-color) calc(l * 0.85) c h); + --highlight-color: oklch(from var(--base-color) l c calc(h - 120)); + --active-color: light-dark(oklch(from var(--action-color) calc(l / 0.85) c h), + oklch(from var(--action-color) calc(l * 0.9) c h)); + + --background-color: light-dark(oklch(95.5% 0 162), + oklch(22.635% 0.01351 291.83)); --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), oklch(from var(--base-color) 80% 0.202 h)); --surface-light: color-mix(in oklab, @@ -335,14 +356,8 @@ var(--base-color)); --text-color: canvasText; - --background-color: light-dark(oklch(95.5% 0 162), - oklch(22.635% 0.01351 291.83)); - --border-color: color-mix(in oklab, var(--base-color), grey); - --accent-color: oklch(from var(--base-color) l c calc(h - 120)); - --action-color: oklch(from var(--base-color) l c calc(h + 180)); - --active-color: light-dark(oklch(from var(--action-color) calc(l / 0.85) c h), - oklch(from var(--action-color) calc(l * 0.9) c h)); - --highlight-color: oklch(from var(--base-color) l c calc(h + 60)); + --border-color: color-mix(in oklab, var(--base-color), grey);; + --border-highlight: var(--complement-color); --serif-font: "Nimbus Mono PS", "Courier New", monospace; --sans-serif-font: Bahnschrift, "DIN Alternate", "Franklin Gothic Medium", "Nimbus Sans Narrow", @@ -387,7 +402,7 @@ } } - @keyframes header-switch { + @keyframes header-hue-switch { from { --header-hue: 26.67; } From ad320ada3c5108952cdbeea97428a1f650752414 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Wed, 19 Nov 2025 11:30:44 +0100 Subject: [PATCH 07/21] adjust pressed state styles --- src/color-theme/style.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 9d27b12..68b9cb0 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -39,9 +39,8 @@ } &[aria-pressed="true"] { - --btn-bg: var(--background-color); - --btn-border: var(--active-color); - --btn-text: var(--text-color); + --btn-bg: var(--highlight-color); + --btn-border: var(--text-color); } } From 0ded3c6b87f5235cc427ed1544e24cab34db7588 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Wed, 19 Nov 2025 14:16:53 +0100 Subject: [PATCH 08/21] review updates from article --- src/color-theme/style.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 68b9cb0..f631d64 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -107,7 +107,7 @@ } [data-playlist-item~="blue"] { - --song-color: var(--base-color); + --song-color: oklch(0.476 0.275 264.05); } [data-playlist-item~="purple"] { @@ -239,7 +239,7 @@ background-clip: text; color: transparent; margin-block-end: var(--heading-margin-block-end, 0.15lh); - animation: header-hue-switch 5s ease-in-out infinite; + animation: header-hue-switch 5s ease-in-out infinite alternate; } .summary { @@ -343,7 +343,7 @@ --action-color: oklch(from var(--base-color) calc(l * 0.85) c h); --highlight-color: oklch(from var(--base-color) l c calc(h - 120)); - --active-color: light-dark(oklch(from var(--action-color) calc(l / 0.85) c h), + --active-color: light-dark(oklch(from var(--action-color) calc(l * 1.15) c h), oklch(from var(--action-color) calc(l * 0.9) c h)); --background-color: light-dark(oklch(95.5% 0 162), From d7d255658c068671fd0f4230ff2c3593bdd1d096 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Thu, 20 Nov 2025 15:38:18 +0100 Subject: [PATCH 09/21] clean up color custom properties --- src/color-theme/style.css | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index f631d64..c64c629 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -295,7 +295,7 @@ &:focus { --input-border: transparent; --outline-offset: 0; - --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h); + --focus-ring: var(--border-color-bright); } &:user-invalid:not(:active, :focus) { @@ -338,24 +338,39 @@ --gap: clamp(2cqi, 0.5lh, 5cqi); --base-color: light-dark(var(--base-color-light), var(--base-color-dark)); - --accent-color: oklch(from var(--base-color) l c calc(h + 120)); + --base-color-darkened: oklch(from var(--base-color) calc(l * 0.85) c h); + --base-color-bright-light: oklch(from var(--base-color) calc(l + 0.25) 0.202 h); + --base-color-bright-dark: oklch(from var(--base-color) 80% 0.202 h); + + --base-mix-grey-50: color-mix(in oklab, var(--base-color), grey); + --background-mix-base-80: color-mix(in oklab, + var(--background-color) 80%, + var(--base-color)); + + --triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120)); + --triadic-color-secondary: oklch(from var(--base-color) l c calc(h - 120)); + --complement-color: oklch(from var(--base-color) l c calc(h + 180)); + - --action-color: oklch(from var(--base-color) calc(l * 0.85) c h); - --highlight-color: oklch(from var(--base-color) l c calc(h - 120)); - --active-color: light-dark(oklch(from var(--action-color) calc(l * 1.15) c h), - oklch(from var(--action-color) calc(l * 0.9) c h)); + --action-color: var(--base-color-darkened); + --action-color-light: oklch(from var(--action-color) calc(l * 1.15) c h); + --action-color-dark: oklch(from var(--action-color) calc(l * 0.9) c h); + + --accent-color: var(--triadic-color-primary); + --highlight-color: var(--triadic-color-secondary); + --active-color: light-dark(var(--action-color-light), + var(--action-color-dark)); --background-color: light-dark(oklch(95.5% 0 162), oklch(22.635% 0.01351 291.83)); - --surface-feature: light-dark(oklch(from var(--base-color) calc(l + 0.25) 0.202 h), - oklch(from var(--base-color) 80% 0.202 h)); - --surface-light: color-mix(in oklab, - var(--background-color) 80%, - var(--base-color)); + --surface-feature: light-dark(var(--base-color-bright-light), + var(--base-color-bright-dark)); + --surface-light: var(--background-mix-base-80); --text-color: canvasText; - --border-color: color-mix(in oklab, var(--base-color), grey);; + --border-color: var(--base-mix-grey-50); + --border-color-bright: oklch(from var(--border-color) l calc(c + 0.1) h); --border-highlight: var(--complement-color); --serif-font: "Nimbus Mono PS", "Courier New", monospace; From 58a24f714f0c419031bdf4db2f2ef2e0552ae3e4 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Fri, 21 Nov 2025 13:35:44 +0100 Subject: [PATCH 10/21] adjust js logic --- src/color-theme/index.html | 2 +- src/color-theme/script.js | 53 ++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/color-theme/index.html b/src/color-theme/index.html index 8af49c3..15eb209 100644 --- a/src/color-theme/index.html +++ b/src/color-theme/index.html @@ -7,6 +7,7 @@ Baseline Color Theme Demo + @@ -148,6 +149,5 @@

Want to request a song? Have an idea for a playlist?

Baseline Radio footer information

- diff --git a/src/color-theme/script.js b/src/color-theme/script.js index b89b573..7e1258f 100644 --- a/src/color-theme/script.js +++ b/src/color-theme/script.js @@ -1,12 +1,38 @@ const pressedButton = '[data-scheme][aria-pressed="true"]'; +const storageKey = 'theme-preference'; + +const getColorPreference = () => { + if (localStorage.getItem(storageKey)) return localStorage.getItem(storageKey); + else + return window.matchMedia('(prefers-color-scheme: dark)').matches + ? 'dark' + : 'light'; +}; + +const setPreference = () => { + localStorage.setItem(storageKey, theme.value); + setScheme(); +}; + +const setInitialScheme = () => { + const savedScheme = localStorage.getItem('data-scheme'); + if (savedScheme) { + setScheme(savedScheme); + } +}; const setScheme = (scheme) => { - const target = document.querySelector(`[data-scheme="${scheme}"]`); + const target = document.querySelector( + `[data-button][data-scheme="${scheme}"]` + ); document.documentElement.setAttribute('data-scheme', scheme); - document.querySelector(pressedButton).setAttribute('aria-pressed', 'false'); - target.setAttribute('aria-pressed', 'true'); + + document.querySelector(pressedButton)?.setAttribute('aria-pressed', 'false'); + target?.setAttribute('aria-pressed', 'true'); }; +setInitialScheme(); + const handleSchemeSelection = (event) => { const target = event.target; const isPressed = target.getAttribute('aria-pressed'); @@ -18,18 +44,13 @@ const handleSchemeSelection = (event) => { } }; -const setInitialScheme = () => { - const savedScheme = localStorage.getItem('data-scheme'); - if (savedScheme) { - setScheme(savedScheme); - } -}; +window.onload = () => { + setInitialScheme(); -setInitialScheme(); + const themePicker = document.querySelector(`[data-options="theme"]`); + const schemeButtons = themePicker.querySelectorAll(`[data-scheme]`); -const themePicker = document.querySelector(`[data-options="theme"]`); -const schemeButtons = themePicker.querySelectorAll(`[data-scheme]`); - -schemeButtons.forEach((button) => { - button.addEventListener('click', handleSchemeSelection); -}); + schemeButtons.forEach((button) => { + button.addEventListener('click', handleSchemeSelection); + }); +}; From 59c8d41ecfa4fcd0877f58b5a1fa7d90ec495396 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Fri, 21 Nov 2025 14:52:05 +0100 Subject: [PATCH 11/21] add transition to details --- src/color-theme/index.html | 2 +- src/color-theme/style.css | 68 ++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/color-theme/index.html b/src/color-theme/index.html index 15eb209..6ab5758 100644 --- a/src/color-theme/index.html +++ b/src/color-theme/index.html @@ -20,7 +20,7 @@
- Light/Dark + Light/Dark diff --git a/src/color-theme/style.css b/src/color-theme/style.css index af2e60d..9e8ef28 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -349,6 +349,12 @@ color-scheme: dark; } + &[data-scheme="green"] { + --base-color-light: oklch(48.052% 0.11875 151.945); + --base-color-dark: oklch(92.124% 0.13356 151.558); + color-scheme: light dark; + } + accent-color: var(--accent-color); interpolate-size: allow-keywords; From 6efbed2a58cb7ca8c8c33266ce2066741f8659de Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Tue, 25 Nov 2025 12:28:26 -0500 Subject: [PATCH 16/21] Simplify script --- src/color-theme/script.js | 58 ++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/src/color-theme/script.js b/src/color-theme/script.js index a651d5b..632afc6 100644 --- a/src/color-theme/script.js +++ b/src/color-theme/script.js @@ -1,58 +1,46 @@ +const storageKey = "data-scheme"; const pressedButton = '[data-scheme][aria-pressed="true"]'; -const storageKey = 'theme-preference'; const getColorPreference = () => { - if (localStorage.getItem(storageKey)) return localStorage.getItem(storageKey); + const storedScheme = localStorage.getItem(storageKey); + if (storedScheme) return storedScheme; else - return window.matchMedia('(prefers-color-scheme: dark)').matches - ? 'dark' - : 'light'; -}; - -const setInitialScheme = () => { - const savedScheme = localStorage.getItem('data-scheme'); - if (savedScheme) { - setScheme(savedScheme); - } else { - getColorPreference(); - setScheme(theme.value); - } + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; }; const setScheme = (scheme) => { + // Switch to the new scheme + document.documentElement.setAttribute("data-scheme", scheme); + // Remove aria-pressed from the previously selected button + document.querySelector(pressedButton)?.setAttribute("aria-pressed", "false"); + // Set aria-pressed on the newly selected button const target = document.querySelector( `[data-button][data-scheme="${scheme}"]` ); - document.documentElement.setAttribute('data-scheme', scheme); - - document.querySelector(pressedButton)?.setAttribute('aria-pressed', 'false'); - target?.setAttribute('aria-pressed', 'true'); + target?.setAttribute("aria-pressed", "true"); + // Persist to localStorage + localStorage.setItem(storageKey, scheme); }; -const theme = { - value: getColorPreference(), -}; - -setInitialScheme(); - const handleSchemeSelection = (event) => { - const target = event.target; - const isPressed = target.getAttribute('aria-pressed'); - const scheme = target.getAttribute('data-scheme'); - - if (isPressed !== 'true') { + const target = event.currentTarget; + const isPressed = target.getAttribute("aria-pressed"); + const scheme = target.getAttribute("data-scheme"); + if (isPressed !== "true" && scheme) { setScheme(scheme); - localStorage.setItem('data-scheme', scheme); } }; window.onload = () => { - setInitialScheme(); + const colorPreference = getColorPreference(); + setScheme(colorPreference); const themePicker = document.querySelector(`[data-options="theme"]`); - const schemeButtons = themePicker.querySelectorAll(`[data-scheme]`); + const schemeButtons = themePicker?.querySelectorAll(`[data-scheme]`); - schemeButtons.forEach((button) => { - button.addEventListener('click', handleSchemeSelection); + schemeButtons?.forEach((button) => { + button.addEventListener("click", handleSchemeSelection); }); }; From 1abd533a315b5a49082fd990b6564f0ecdbd037c Mon Sep 17 00:00:00 2001 From: dvdherron Date: Wed, 26 Nov 2025 10:34:13 +0100 Subject: [PATCH 17/21] adjust pressed border color --- src/color-theme/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index 9e8ef28..b8a177b 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -155,7 +155,7 @@ [data-button] { align-items: center; background: var(--btn-bg, var(--action-color)); - border: 1px solid var(--btn-border, transparent); + border: medium solid var(--btn-border, transparent); color: var(--btn-text, var(--background-color)); cursor: pointer; display: inline-flex; @@ -173,7 +173,7 @@ &[aria-pressed="true"] { --btn-bg: var(--highlight-color); - --btn-border: var(--text-color); + --btn-border: var(--border-color-bright); } } From 3a90da04281ecf19432f007a3bdfa91d0cb27802 Mon Sep 17 00:00:00 2001 From: dvdherron Date: Fri, 28 Nov 2025 11:00:43 +0100 Subject: [PATCH 18/21] lighten surface background --- src/color-theme/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/color-theme/style.css b/src/color-theme/style.css index b8a177b..80fd6f0 100644 --- a/src/color-theme/style.css +++ b/src/color-theme/style.css @@ -168,7 +168,7 @@ &:hover, &:focus { --btn-bg: var(--active-color); - --btn-border: var(--border-color); + --btn-border: var(--accent-color); } &[aria-pressed="true"] { @@ -375,7 +375,7 @@ --base-mix-grey-50: color-mix(in oklab, var(--base-color), grey); --background-mix-base-80: color-mix(in oklab, - var(--background-color) 80%, + var(--background-color) 90%, var(--base-color)); --triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120)); From 47f41eceb775daa905346f435a7f5d240755b7ce Mon Sep 17 00:00:00 2001 From: dvdherron Date: Tue, 2 Dec 2025 11:22:38 +0100 Subject: [PATCH 19/21] address review --- src/color-theme/index.html | 24 ++++- src/color-theme/style.css | 214 +++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 96 deletions(-) diff --git a/src/color-theme/index.html b/src/color-theme/index.html index 735df37..abcf9dd 100644 --- a/src/color-theme/index.html +++ b/src/color-theme/index.html @@ -12,8 +12,8 @@