diff --git a/docs/_layouts/palette.njk b/docs/_layouts/palette.njk index 3238e3c7d..41dec2a34 100644 --- a/docs/_layouts/palette.njk +++ b/docs/_layouts/palette.njk @@ -166,7 +166,6 @@ :default-value="seedColors[colorToIndex[hue].core].inputColor.oklch.h" v-model:tweaking="tweaking.hue[hue]" - class="hue-shift-slider" color-component="oklch.h" :min="HUE_RANGES[hue].min + 1" :max="HUE_RANGES[hue].max" label="Tweak hue" :label-min="`More ${hueBefore[hue]}`" :label-max="`More ${hueAfter[hue]}`" @@ -178,7 +177,6 @@ :default-color="baseCoreColors[hue]" v-model:tweaking="tweaking.hue[hue]" - class="hue-shift-slider" color-component="oklch.h" :min="HUE_RANGES[hue].min + 1" :max="HUE_RANGES[hue].max" label="Tweak hue" :label-min="`More ${hueBefore[hue]}`" :label-max="`More ${hueAfter[hue]}`" diff --git a/docs/assets/scripts/tweak/util.js b/docs/assets/scripts/tweak/util.js index e31c759c0..ef9237469 100644 --- a/docs/assets/scripts/tweak/util.js +++ b/docs/assets/scripts/tweak/util.js @@ -1,3 +1,15 @@ +// https://lea.verou.me/blog/2016/12/resolve-promises-externally-with-this-one-weird-trick/ +export function promise() { + let res, rej; + + let promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + + return Object.assign(promise, { resolve: res, reject: rej }); +} + export function normalizeAngles(angles) { // First, normalize angles = angles.map(h => ((h % 360) + 360) % 360); diff --git a/docs/docs/palettes/app/color/generate-palette.js b/docs/docs/palettes/app/color/generate-palette.js index c4afb6c64..0982ce4ff 100644 --- a/docs/docs/palettes/app/color/generate-palette.js +++ b/docs/docs/palettes/app/color/generate-palette.js @@ -2,6 +2,7 @@ import Color from 'https://colorjs.io/dist/color.js'; import generateGrays from './generate-grays.js'; import generateScale from './generate-scale.js'; +import getMaxChroma from './get-max-chroma.js'; import { getCoreTint } from './util.js'; import { HUE_CHROMA_SCALE, @@ -13,9 +14,6 @@ import { } from '/assets/scripts/tweak/data.js'; import { clamp, clampAngle, interpolate, progressAngle, roundTo, subtractAngles } from '/assets/scripts/tweak/util.js'; -/** An OKLCh chroma value that is guaranteed to be OOG for every P3 color */ -const OOG_CHROMA = 0.4; - export default function generatePalette(seedHues, { huesAfter: allHuesAfter, ...options } = {}) { let ret = {}; @@ -36,9 +34,10 @@ export default function generatePalette(seedHues, { huesAfter: allHuesAfter, ... let coreLevel = (coreLevels[hue] = getCoreTint(seedColors)); let coreColor = seedColors[coreLevel]; + let [l, c, h] = coreColor.getAll('oklch'); - let lOffset = coreColor.get('oklch.l') - L_RANGES[coreLevel].mid; - let cScale = coreColor.get('oklch.c') / coreColor.to('oklch').clone().set('c', OOG_CHROMA).toGamut('p3').c; + let lOffset = l - L_RANGES[coreLevel].mid; + let cScale = c / getMaxChroma(l, h); let relativeCScale = cScale / HUE_CHROMA_SCALE[hue]; let levelOffset = coreLevel - HUE_TOP_TINT[hue]; seedMeta[hue] = { lOffset, cScale, relativeCScale, levelOffset }; @@ -111,7 +110,7 @@ export default function generatePalette(seedHues, { huesAfter: allHuesAfter, ... cScale *= HUE_CHROMA_SCALE[hue]; - let maxC = new Color('oklch', [l, OOG_CHROMA, h]).toGamut('p3').c; + let maxC = getMaxChroma(l, h); let c = cScale * maxC; // let c = interpolate( // hueProgress, diff --git a/docs/docs/palettes/app/util/get-max-chroma.js b/docs/docs/palettes/app/color/get-max-chroma.js similarity index 100% rename from docs/docs/palettes/app/util/get-max-chroma.js rename to docs/docs/palettes/app/color/get-max-chroma.js diff --git a/docs/docs/palettes/app/custom.css b/docs/docs/palettes/app/custom.css index bdbaeb6d5..ae5e6c849 100644 --- a/docs/docs/palettes/app/custom.css +++ b/docs/docs/palettes/app/custom.css @@ -33,14 +33,25 @@ background-color: var(--color); color: canvastext; - .original-color { + .tweak-icon { position: absolute; top: var(--wa-space-s); left: var(--wa-space-s); - padding: var(--wa-space-2xs); - border: 1px solid hsl(0 0 100 / 50%); - border-radius: var(--wa-border-radius-s); - background-color: var(--color-original); + + --background-color-hover: oklab(from currentColor l a b / 15%); + --text-color-hover: currentColor; + + &:is(.tweaked *) { + opacity: 1; + + &::part(base) { + transition: var(--wa-transition-normal); + transition-property: padding, border; + background-color: var(--color-original); + padding: var(--wa-space-s); + border: 1px solid hsl(0 0 100 / 60%); + } + } } .name { @@ -62,7 +73,7 @@ --text-color-hover: currentColor; } - &:not(:hover, :focus-within) .delete-button { + &:not(:hover, :focus-within) wa-icon-button { opacity: 0; } } diff --git a/docs/docs/palettes/app/tweak.css b/docs/docs/palettes/app/tweak.css index 14854bc89..1f95c1727 100644 --- a/docs/docs/palettes/app/tweak.css +++ b/docs/docs/palettes/app/tweak.css @@ -67,8 +67,8 @@ wa-dropdown > .color.swatch { } } -.hue-shift-slider { - --color-interpolation-space: oklch; +[data-component='oklch.h'] { + --color-interpolation-space: oklch increasing hue; } .popup { @@ -76,6 +76,7 @@ wa-dropdown > .color.swatch { flex-flow: column; gap: var(--wa-space-m); background: var(--wa-color-surface-default); + color: var(--wa-color-text-normal); border: 1px solid var(--wa-color-surface-border); padding: var(--wa-space-m) var(--wa-space-l); border-radius: var(--wa-border-radius-m); diff --git a/docs/docs/palettes/app/vue-components/color-input.js b/docs/docs/palettes/app/vue-components/color-input.js index 4c06ae54b..79bbf1841 100644 --- a/docs/docs/palettes/app/vue-components/color-input.js +++ b/docs/docs/palettes/app/vue-components/color-input.js @@ -1,7 +1,39 @@ +const template = ` + +
+ + + + + + + +
{{ capitalize(hue) || 'New color' }} {{ level }}
+
+ + + {{ capitalize(role) }} + + + +
+`; + import Color from 'https://colorjs.io/dist/color.js'; // import { nextTick } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'; import { nextTick } from 'https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.js'; +import getMaxChroma from '../color/get-max-chroma.js'; import { identifyColor, stringifyColor } from '../color/util.js'; +import ColorPopup from './color-popup.js'; +import ColorSlider from './color-slider.js'; +import InfoTip from './info-tip.js'; import { ROLES } from '/assets/scripts/tweak/data.js'; import { capitalize } from '/assets/scripts/tweak/util.js'; @@ -126,6 +158,7 @@ export default { }, methods: { capitalize, + getMaxChroma, handleInput(event) { this.editing++; @@ -225,26 +258,11 @@ export default { }, }, }, - template: ` - -
-
- -
- -
{{ capitalize(hue) || 'New color' }} {{ level }}
-
- - - {{ capitalize(role) }} - - - -
- `, + template, + components: { InfoTip, ColorSlider, ColorPopup }, + compilerOptions: { + isCustomElement: tag => tag.startsWith('wa-'), + }, }; function tryColor(value) { diff --git a/docs/docs/palettes/app/vue-components/color-popup.js b/docs/docs/palettes/app/vue-components/color-popup.js index 6cd84f006..c233a9559 100644 --- a/docs/docs/palettes/app/vue-components/color-popup.js +++ b/docs/docs/palettes/app/vue-components/color-popup.js @@ -10,6 +10,7 @@ export default { deletable: Boolean, pinnable: Boolean, pinned: Object, + placement: String, }, data() { return {}; @@ -17,11 +18,12 @@ export default { emits: ['delete', 'pin'], mounted() { let popup = this.$refs.popup; + if (popup) { // Find trigger let trigger = popup.previousElementSibling; if (trigger) { - trigger.slot ??= 'trigger'; + trigger.slot ||= 'trigger'; } } }, @@ -31,15 +33,15 @@ export default { }, }, template: ` - + -