@canopy-iiif/app 1.2.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ui/theme.js +102 -1
package/package.json
CHANGED
package/ui/theme.js
CHANGED
|
@@ -116,6 +116,87 @@ function lightenHex(hex, amount = 0.15) {
|
|
|
116
116
|
return `#${toHex(adjust(r))}${toHex(adjust(g))}${toHex(adjust(b))}`;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
function adjustSaturation(hex, amount = 0.15) {
|
|
120
|
+
if (!hex) return hex;
|
|
121
|
+
const normalized = hex.replace("#", "");
|
|
122
|
+
if (!/^[0-9a-fA-F]{6}$/.test(normalized)) return hex;
|
|
123
|
+
const num = parseInt(normalized, 16);
|
|
124
|
+
let r = ((num >> 16) & 255) / 255;
|
|
125
|
+
let g = ((num >> 8) & 255) / 255;
|
|
126
|
+
let b = (num & 255) / 255;
|
|
127
|
+
const max = Math.max(r, g, b);
|
|
128
|
+
const min = Math.min(r, g, b);
|
|
129
|
+
let h = 0;
|
|
130
|
+
let s = 0;
|
|
131
|
+
const l = (max + min) / 2;
|
|
132
|
+
if (max !== min) {
|
|
133
|
+
const d = max - min;
|
|
134
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
135
|
+
switch (max) {
|
|
136
|
+
case r:
|
|
137
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
138
|
+
break;
|
|
139
|
+
case g:
|
|
140
|
+
h = (b - r) / d + 2;
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
h = (r - g) / d + 4;
|
|
144
|
+
}
|
|
145
|
+
h /= 6;
|
|
146
|
+
}
|
|
147
|
+
const delta = Number(amount);
|
|
148
|
+
if (!Number.isFinite(delta) || delta === 0) return hex;
|
|
149
|
+
s = Math.max(0, Math.min(1, s + delta));
|
|
150
|
+
const hueToRgb = (p, q, t) => {
|
|
151
|
+
if (t < 0) t += 1;
|
|
152
|
+
if (t > 1) t -= 1;
|
|
153
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
154
|
+
if (t < 1 / 2) return q;
|
|
155
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
156
|
+
return p;
|
|
157
|
+
};
|
|
158
|
+
let rOut;
|
|
159
|
+
let gOut;
|
|
160
|
+
let bOut;
|
|
161
|
+
if (s === 0) {
|
|
162
|
+
rOut = gOut = bOut = l;
|
|
163
|
+
} else {
|
|
164
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
165
|
+
const p = 2 * l - q;
|
|
166
|
+
rOut = hueToRgb(p, q, h + 1 / 3);
|
|
167
|
+
gOut = hueToRgb(p, q, h);
|
|
168
|
+
bOut = hueToRgb(p, q, h - 1 / 3);
|
|
169
|
+
}
|
|
170
|
+
const toHex = (value) =>
|
|
171
|
+
Math.round(Math.max(0, Math.min(1, value)) * 255)
|
|
172
|
+
.toString(16)
|
|
173
|
+
.padStart(2, "0");
|
|
174
|
+
return `#${toHex(rOut)}${toHex(gOut)}${toHex(bOut)}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function mixHexColors(colorA, colorB, amount = 0.5) {
|
|
178
|
+
const normalize = (hex) =>
|
|
179
|
+
hex && /^[0-9a-fA-F]{6}$/.test(hex.replace("#", ""))
|
|
180
|
+
? hex.replace("#", "")
|
|
181
|
+
: null;
|
|
182
|
+
const first = normalize(colorA);
|
|
183
|
+
const second = normalize(colorB);
|
|
184
|
+
if (!first || !second) return colorA || colorB || null;
|
|
185
|
+
const a = parseInt(first, 16);
|
|
186
|
+
const b = parseInt(second, 16);
|
|
187
|
+
const clampAmount = Math.max(0, Math.min(1, Number(amount) || 0));
|
|
188
|
+
const mixChannel = (shift) =>
|
|
189
|
+
Math.round(
|
|
190
|
+
((a >> shift) & 255) +
|
|
191
|
+
(((b >> shift) & 255) - ((a >> shift) & 255)) * clampAmount
|
|
192
|
+
);
|
|
193
|
+
const toHex = (value) => value.toString(16).padStart(2, "0");
|
|
194
|
+
const r = mixChannel(16);
|
|
195
|
+
const g = mixChannel(8);
|
|
196
|
+
const bl = mixChannel(0);
|
|
197
|
+
return `#${toHex(r)}${toHex(g)}${toHex(bl)}`;
|
|
198
|
+
}
|
|
199
|
+
|
|
119
200
|
function normalizeDarkenAmount(raw) {
|
|
120
201
|
const value = Number(raw);
|
|
121
202
|
if (!Number.isFinite(value)) return null;
|
|
@@ -138,6 +219,18 @@ function toTailwindScale(name, options = {}) {
|
|
|
138
219
|
if (!value) return null;
|
|
139
220
|
scale[lvl] = value;
|
|
140
221
|
}
|
|
222
|
+
if (scale["50"] && scale["100"]) {
|
|
223
|
+
scale["50"] = mixHexColors(scale["50"], scale["100"], 0.6);
|
|
224
|
+
}
|
|
225
|
+
const saturate700 = options.saturate700 !== false;
|
|
226
|
+
if (scale["700"]) {
|
|
227
|
+
let adjusted =
|
|
228
|
+
appearance === "dark"
|
|
229
|
+
? lightenHex(scale["700"], 0.15)
|
|
230
|
+
: darkenHex(scale["700"], 0.15);
|
|
231
|
+
if (saturate700) adjusted = adjustSaturation(adjusted, 0.15);
|
|
232
|
+
scale["700"] = adjusted;
|
|
233
|
+
}
|
|
141
234
|
const darkestKey = `${prefix}${steps["900"]}`;
|
|
142
235
|
if (scale["800"] && palette[darkestKey]) {
|
|
143
236
|
const amount = darken900Amount != null ? darken900Amount : 0.25;
|
|
@@ -146,6 +239,9 @@ function toTailwindScale(name, options = {}) {
|
|
|
146
239
|
? lightenHex(palette[darkestKey], amount)
|
|
147
240
|
: darkenHex(palette[darkestKey], amount);
|
|
148
241
|
}
|
|
242
|
+
if (scale["800"] && scale["900"]) {
|
|
243
|
+
scale["800"] = mixHexColors(scale["800"], scale["900"], 0.65);
|
|
244
|
+
}
|
|
149
245
|
return scale;
|
|
150
246
|
}
|
|
151
247
|
|
|
@@ -226,7 +322,11 @@ function loadCanopyTheme(options = {}) {
|
|
|
226
322
|
|
|
227
323
|
let grayName = normalizePaletteName(grayRequested);
|
|
228
324
|
let grayScale = grayName
|
|
229
|
-
? toTailwindScale(grayName, {
|
|
325
|
+
? toTailwindScale(grayName, {
|
|
326
|
+
appearance,
|
|
327
|
+
darken900Amount: 0.4,
|
|
328
|
+
saturate700: false,
|
|
329
|
+
})
|
|
230
330
|
: null;
|
|
231
331
|
let grayFallback = false;
|
|
232
332
|
if (!grayScale) {
|
|
@@ -235,6 +335,7 @@ function loadCanopyTheme(options = {}) {
|
|
|
235
335
|
grayScale = toTailwindScale(DEFAULT_GRAY, {
|
|
236
336
|
appearance,
|
|
237
337
|
darken900Amount: 0.4,
|
|
338
|
+
saturate700: false,
|
|
238
339
|
});
|
|
239
340
|
}
|
|
240
341
|
|