mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 20:19:13 +00:00
Various changes around tweaks
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
<div id="palette-app" data-slug="{{ page.fileSlug }}" data-palette-id="{{ page.fileSlug }}">
|
||||
<div
|
||||
:class="{
|
||||
seeded: seedColorObjects.length,
|
||||
seeded: isSeeded,
|
||||
tweaking: tweaking.chromaScale,
|
||||
'tweaking-chroma': tweaking.chromaScale,
|
||||
'tweaking-hue': tweaking.chromaScale,
|
||||
@@ -115,7 +115,7 @@
|
||||
</thead>
|
||||
{% raw %}
|
||||
<tbody v-cloak>
|
||||
<tr v-for="hue in [...hues, 'gray']" v-show="hue === 'gray' || seedHues[hue] || !isCustom" :data-hue="hue"
|
||||
<tr v-for="hue in paletteScalesList" :data-hue="hue" :key="hue"
|
||||
class="color-scale" :class="{
|
||||
tweaking: hue === 'gray' ? tweaking.grayChroma : tweaking.hue?.[hue],
|
||||
tweaked: hue === 'gray' ? tweaked.grayChroma || tweaked.grayColor : hueShifts[hue],
|
||||
@@ -148,7 +148,7 @@
|
||||
Gray undertone
|
||||
</div>
|
||||
</wa-radio-group>
|
||||
<color-slider class="gray-chroma-slider" type="percentage" :default-value="originalGrayChroma"
|
||||
<color-slider class="gray-chroma-slider" type="scale" :default-value="originalGrayChroma"
|
||||
:model-value="computedGrayChroma"
|
||||
@update:model-value="grayChroma = $event"
|
||||
v-model:tweaking="tweaking.grayChroma"
|
||||
@@ -157,16 +157,30 @@
|
||||
label="Gray colorfulness" label-min="Neutral" :label-max="moreHue[computedGrayColor]"
|
||||
></color-slider>
|
||||
</template>
|
||||
<color-slider v-else class="hue-shift-slider"
|
||||
:model-value="tweak('hueShift', {hue, level: 'core'})"
|
||||
@update:model-value="tweak('hueShift', {hue, level: 'core'}, $event)"
|
||||
:default-value="tweakDefault('hueShift', {hue, level: 'core'})"
|
||||
<template v-else>
|
||||
<color-slider v-if="isCustom && seedColors[colorToIndex[hue].core]"
|
||||
v-model:color="seedColors[colorToIndex[hue].core].color"
|
||||
: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"
|
||||
:get-color="h => baseCoreColors[hue].clone().set('oklch.h', h)"
|
||||
:label="`Tweak ${ hue } hue`" :label-min="`More ${hueBefore[hue]}`" :label-max="`More ${hueAfter[hue]}`"
|
||||
></color-slider>
|
||||
|
||||
<color-slider v-if="!isCustom && baseCoreColors[hue]"
|
||||
type="shift"
|
||||
v-model="hueShifts[hue]"
|
||||
: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 } hue`" :label-min="`More ${hueBefore[hue]}`" :label-max="`More ${hueAfter[hue]}`"
|
||||
></color-slider>
|
||||
</template>
|
||||
<div class="wa-gap-s">
|
||||
<code>--wa-color-{{ hue }}</code>
|
||||
<wa-copy-button value="--wa-color-{{ hue }}" copy-label="--wa-color-{{ hue }}"></wa-copy-button>
|
||||
@@ -190,7 +204,7 @@
|
||||
|
||||
<color-slider
|
||||
class="chroma-scale-slider wa-palette-{{ paletteId }}" :class="{ tweaked: chromaScale !== 1 }"
|
||||
type="percentage" :default-value="1"
|
||||
type="scale" :default-value="1"
|
||||
v-model="chromaScale"
|
||||
v-model:tweaking="tweaking.chromaScale"
|
||||
:min="chromaScaleBounds.min" :max="chromaScaleBounds.max" :step="0.01"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// TODO move these to local imports
|
||||
import Color from 'https://colorjs.io/dist/color.js';
|
||||
import { createApp, nextTick } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
|
||||
// import { createApp, nextTick } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
|
||||
import { createApp, nextTick } from 'https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.js';
|
||||
import generatePalette from './color/generate-palette.js';
|
||||
import getPaletteCode from './color/get-palette-code.js';
|
||||
import allPalettes from './color/palettes.js';
|
||||
@@ -124,7 +125,7 @@ let paletteAppSpec = {
|
||||
*/
|
||||
step() {
|
||||
if (this.isCustom) {
|
||||
if (this.seedColorObjects.length > 0) {
|
||||
if (this.isSeeded) {
|
||||
return 2;
|
||||
} else if (this.seedColors.length > 0) {
|
||||
return 1;
|
||||
@@ -248,14 +249,15 @@ let paletteAppSpec = {
|
||||
},
|
||||
|
||||
seedColorObjects() {
|
||||
return this.seedColors.map(c => c.color).filter(Boolean);
|
||||
return this.seedColors.map(c => c.color);
|
||||
},
|
||||
|
||||
isSeeded() {
|
||||
return this.seedColorObjectsRaw.filter(Boolean).length > 0;
|
||||
},
|
||||
|
||||
seedColorInfo() {
|
||||
return this.seedColors.map(({ hue, level }) => ({ hue, level }));
|
||||
// return this.seedColorObjectsRaw.map(colorObject =>
|
||||
// colorObject ? identifyColor(colorObject, this.seedColorObjects) : null,
|
||||
// );
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -268,7 +270,7 @@ let paletteAppSpec = {
|
||||
ret[hue] = {};
|
||||
}
|
||||
|
||||
if (this.seedColorObjects.length === 0) {
|
||||
if (!this.isSeeded) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -365,8 +367,12 @@ let paletteAppSpec = {
|
||||
return ret;
|
||||
},
|
||||
|
||||
paletteScalesList() {
|
||||
return Object.keys(this.paletteScales);
|
||||
},
|
||||
|
||||
paletteScalesSet() {
|
||||
return new Set(Object.keys(this.paletteScales));
|
||||
return new Set(this.paletteScalesList);
|
||||
},
|
||||
|
||||
tweaks() {
|
||||
@@ -400,7 +406,7 @@ let paletteAppSpec = {
|
||||
},
|
||||
|
||||
baseColors() {
|
||||
if (this.seedColorObjects.length === 0) {
|
||||
if (!this.isSeeded) {
|
||||
return this.originalColors;
|
||||
}
|
||||
|
||||
@@ -866,60 +872,6 @@ let paletteAppSpec = {
|
||||
|
||||
return { color, index };
|
||||
},
|
||||
|
||||
tweak(type, ref, value) {
|
||||
let { color, index } = this.getColor(ref);
|
||||
|
||||
if (color === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'hueShift') {
|
||||
if (this.isCustom) {
|
||||
if (index === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
return color.get('oklch.h');
|
||||
} else {
|
||||
// console.log(`About to set h of ${color} to ${value}`);
|
||||
color.set('oklch.h', value);
|
||||
}
|
||||
} else {
|
||||
let { hue, level } = ref;
|
||||
let color = this.baseColors[hue][level];
|
||||
let h = color.get('oklch.h');
|
||||
|
||||
if (value === undefined) {
|
||||
// Get
|
||||
return h + this.hueShifts[hue];
|
||||
} else {
|
||||
// Set
|
||||
let { hue } = ref;
|
||||
this.hueShifts[hue] = value - h;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
tweakDefault(type, ref) {
|
||||
if (type === 'hueShift') {
|
||||
if (this.isCustom) {
|
||||
let { index } = this.getColor(ref);
|
||||
|
||||
if (index === undefined || !this.seedColors[index]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { inputColor } = this.seedColors[index];
|
||||
|
||||
return inputColor?.get('oklch.h');
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
directives: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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://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 { identifyColor, stringifyColor } from '../color/util.js';
|
||||
import { ROLES } from '/assets/scripts/tweak/data.js';
|
||||
import { capitalize } from '/assets/scripts/tweak/util.js';
|
||||
@@ -49,6 +50,7 @@ export default {
|
||||
inputColor,
|
||||
editing: 0,
|
||||
inputFocused: false,
|
||||
watching: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -129,10 +131,9 @@ export default {
|
||||
this.editing++;
|
||||
|
||||
let value = event.target.value;
|
||||
// Editing the input manually also incorporates tweaks as part of the color itself
|
||||
// Editing the input manually also incorporates any tweaks as part of the color itself
|
||||
// I.e. input color and color are now the same
|
||||
this.valueRaw = this.modelValue.valueRaw = this.modelValue.inputValueRaw = this.inputValueRaw = value;
|
||||
this.$emit('update:modelValue', this.modelValue);
|
||||
this.valueRaw = this.inputValueRaw = value;
|
||||
|
||||
nextTick().then(() => {
|
||||
if (this.colorRaw) {
|
||||
@@ -147,12 +148,44 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
mutateModelValue(mutator) {
|
||||
if (this.watching.modelValue === null) {
|
||||
// If we're not watching modelValue, it means we're reacting to a change to it
|
||||
// so no point in updating it again
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.watching.modelValue) {
|
||||
this.watching.modelValue();
|
||||
this.watching.modelValue = null;
|
||||
}
|
||||
|
||||
mutator();
|
||||
|
||||
this.watching.modelValue = this.$watch('modelValue', {
|
||||
deep: true,
|
||||
handler() {
|
||||
let computedValue = this.computedValue;
|
||||
// What changed?
|
||||
|
||||
if (this.modelValue.value !== computedValue.value) {
|
||||
this.valueRaw = this.modelValue.value;
|
||||
}
|
||||
|
||||
if (this.modelValue.color + '' !== computedValue.color + '') {
|
||||
this.color = this.modelValue.color;
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
revert() {
|
||||
this.$emit('update:modelValue', this.inputValue);
|
||||
this.$emit('update:color', this.inputColor);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
/** colorRaw -> color */
|
||||
colorRaw: {
|
||||
deep: true,
|
||||
handler() {
|
||||
@@ -161,6 +194,7 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
/** inputColorRaw -> inputColor */
|
||||
inputColorRaw: {
|
||||
deep: true,
|
||||
handler() {
|
||||
@@ -169,22 +203,25 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
/** color -> value, valueRaw, modelValue.value */
|
||||
color: {
|
||||
deep: true,
|
||||
handler() {
|
||||
if (this.tweaked && this.color) {
|
||||
// If tweaked, color is the source of truth
|
||||
this.value = this.valueRaw = this.modelValue.value = this.color + '';
|
||||
this.$emit('update:modelValue', this.modelValue);
|
||||
this.value = this.valueRaw = this.color + '';
|
||||
}
|
||||
},
|
||||
},
|
||||
/** computedValue -> modelValue */
|
||||
computedValue: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler() {
|
||||
Object.assign(this.modelValue, this.computedValue);
|
||||
this.$emit('update:modelValue', this.modelValue);
|
||||
this.mutateModelValue(() => {
|
||||
Object.assign(this.modelValue, this.computedValue);
|
||||
this.$emit('update:modelValue', this.modelValue);
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,26 +1,36 @@
|
||||
import Color from 'https://colorjs.io/dist/color.js';
|
||||
import { capitalize } from '/assets/scripts/tweak/util.js';
|
||||
import { capitalize, clamp } from '/assets/scripts/tweak/util.js';
|
||||
|
||||
const percentFormatter = value => value.toLocaleString(undefined, { style: 'percent' });
|
||||
|
||||
export default {
|
||||
props: {
|
||||
colorComponent: String,
|
||||
defaultColor: {
|
||||
type: Color,
|
||||
},
|
||||
defaultValue: {
|
||||
type: Number,
|
||||
},
|
||||
|
||||
modelValue: {
|
||||
type: Number,
|
||||
default(rawProps) {
|
||||
return rawProps.defaultValue ?? 0;
|
||||
return rawProps.defaultValue;
|
||||
},
|
||||
},
|
||||
min: Number,
|
||||
max: Number,
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
default(rawProps) {
|
||||
return clamp(0, Math.abs((rawProps.max - rawProps.min) / 100), 1);
|
||||
},
|
||||
},
|
||||
defaultValue: Number,
|
||||
|
||||
type: {
|
||||
type: String,
|
||||
default: 'number',
|
||||
default: 'raw',
|
||||
},
|
||||
|
||||
getColor: {
|
||||
@@ -29,7 +39,11 @@ export default {
|
||||
color: {
|
||||
type: Color,
|
||||
default(rawProps) {
|
||||
return rawProps.getColor(rawProps.modelValue);
|
||||
if (rawProps.defaultColor) {
|
||||
return rawProps.defaultColor;
|
||||
}
|
||||
|
||||
return rawProps.getColor(getValue(rawProps), rawProps.modelValue);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -41,56 +55,171 @@ export default {
|
||||
},
|
||||
emits: ['update:modelValue', 'update:tweaking', 'update:color'],
|
||||
data() {
|
||||
return {};
|
||||
let { type, modelValue, defaultValue } = this;
|
||||
let value = getValue({ type, modelValue, defaultValue });
|
||||
|
||||
return {
|
||||
initialColor: this.color,
|
||||
value,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (this.value === undefined) {
|
||||
this.value = this.computedDefaultValue;
|
||||
}
|
||||
|
||||
if (this.$refs.slider) {
|
||||
if (this.type === 'scale') {
|
||||
this.$refs.slider.tooltipFormatter = percentFormatter;
|
||||
}
|
||||
this.$refs.slider.colorSliderData = this; // for debugging
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
delete this.$refs.slider?.colorSliderData;
|
||||
},
|
||||
computed: {
|
||||
colorCurrent() {
|
||||
return this.getColor(this.modelValue);
|
||||
return this.getColorAt(this.value, this.modelValue) ?? this.initialColor;
|
||||
},
|
||||
|
||||
colorCurrentString() {
|
||||
return this.colorCurrent + '';
|
||||
},
|
||||
|
||||
h() {
|
||||
return this.colorCurrent?.get('oklch.h') ?? this.initialColor?.get('oklch.h');
|
||||
},
|
||||
|
||||
c() {
|
||||
return this.colorCurrent?.get('oklch.c') ?? this.initialColor?.get('oklch.c');
|
||||
},
|
||||
|
||||
l() {
|
||||
return this.colorCurrent?.get('oklch.l') ?? this.initialColor?.get('oklch.l');
|
||||
},
|
||||
|
||||
colorMin() {
|
||||
return this.getColor(this.min);
|
||||
return this.getColorAt(this.min);
|
||||
},
|
||||
|
||||
colorMax() {
|
||||
return this.getColor(this.max);
|
||||
return this.getColorAt(this.max);
|
||||
},
|
||||
|
||||
computedDefaultValue() {
|
||||
let { defaultValue, colorComponent, defaultColor, type, min, max } = this;
|
||||
|
||||
if (defaultValue !== undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (colorComponent && defaultColor) {
|
||||
return this.computedDefaultColor.get(colorComponent);
|
||||
}
|
||||
|
||||
return clamp(min, type === 'scale' ? 1 : 0, max);
|
||||
},
|
||||
|
||||
computedDefaultColor() {
|
||||
if (this.defaultColor) {
|
||||
return this.defaultColor;
|
||||
}
|
||||
|
||||
let defaultValue = this.computedDefaultValue;
|
||||
|
||||
if (this.colorComponent && this.defaultValue !== undefined) {
|
||||
switch (this.colorComponent) {
|
||||
case 'oklch.l':
|
||||
return new Color('oklch', [defaultValue, this.c, this.h]);
|
||||
case 'oklch.c':
|
||||
return new Color('oklch', [this.l, defaultValue, this.h]);
|
||||
case 'oklch.h':
|
||||
return new Color('oklch', [this.l, this.c, defaultValue]);
|
||||
}
|
||||
}
|
||||
|
||||
return this.getColor?.(defaultValue);
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.slider && this.type === 'percentage') {
|
||||
this.$refs.slider.tooltipFormatter = percentFormatter;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
capitalize,
|
||||
|
||||
getColorAt(value) {
|
||||
if (this.getColor) {
|
||||
return this.getColor(value, this.modelValue);
|
||||
}
|
||||
|
||||
if (this.computedDefaultColor && this.colorComponent) {
|
||||
return this.computedDefaultColor.clone().set(this.colorComponent, value);
|
||||
}
|
||||
},
|
||||
|
||||
handleInput(event) {
|
||||
let value = (this.value = event.target.value);
|
||||
let modelValue = getModelValue({ type: this.type, value, defaultValue: this.computedDefaultValue });
|
||||
|
||||
this.$emit('update:tweaking', true);
|
||||
this.$emit('update:modelValue', event.target.value);
|
||||
this.$emit('update:modelValue', modelValue);
|
||||
},
|
||||
|
||||
reset() {
|
||||
let { value, type, defaultValue } = this;
|
||||
this.$emit('update:modelValue', getModelValue({ value, type, defaultValue }));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
colorCurrent() {
|
||||
colorCurrentString() {
|
||||
this.$emit('update:color', this.colorCurrent);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div class="decorated-slider" :style="{
|
||||
'--color': colorCurrent,
|
||||
'--color-1': colorMin,
|
||||
'--color-2': colorMax,
|
||||
}">
|
||||
<wa-slider ref="slider" :min="min" :max="max" :step="step"
|
||||
@change="$emit('update:tweaking', false)" :value="modelValue" @input="handleInput">
|
||||
<div slot="label">
|
||||
{{ label }}
|
||||
<wa-icon-button @click="$emit('update:modelValue', defaultValue)" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
|
||||
</div>
|
||||
</wa-slider>
|
||||
<div class="label-min">{{ labelMin }}</div>
|
||||
<div class="label-max">{{ labelMax }}</div>
|
||||
</div>
|
||||
<div class="decorated-slider"
|
||||
:style="{'--color': colorCurrent, '--color-1': colorMin, '--color-2': colorMax}">
|
||||
<wa-slider ref="slider" :min="min" :max="max" :step="step" :value="value"
|
||||
@change="$emit('update:tweaking', false)" @input="handleInput">
|
||||
<div slot="label">
|
||||
{{ label }}
|
||||
<wa-icon-button @click="reset" class="clear-button" name="circle-xmark" library="system" variant="regular" label="Reset"></wa-icon-button>
|
||||
</div>
|
||||
</wa-slider>
|
||||
<div class="label-min">{{ labelMin }}</div>
|
||||
<div class="label-max">{{ labelMax }}</div>
|
||||
</div>
|
||||
`,
|
||||
compilerOptions: {
|
||||
isCustomElement: tag => tag.startsWith('wa-'),
|
||||
},
|
||||
};
|
||||
|
||||
function getValue({ type, modelValue, defaultValue }) {
|
||||
if (defaultValue === undefined && (type === 'shift' || type === 'scale')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (type === 'shift') {
|
||||
return modelValue + defaultValue;
|
||||
}
|
||||
|
||||
if (type === 'scale') {
|
||||
return modelValue * defaultValue;
|
||||
}
|
||||
|
||||
return modelValue;
|
||||
}
|
||||
|
||||
function getModelValue({ value, type, defaultValue }) {
|
||||
if (defaultValue === undefined && (type === 'shift' || type === 'scale')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (type === 'shift') {
|
||||
return value - defaultValue;
|
||||
}
|
||||
|
||||
if (type === 'scale') {
|
||||
return value / defaultValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user