global: snapshot

This commit is contained in:
nym21
2026-01-20 15:04:00 +01:00
parent 486871379c
commit 9613fce919
53 changed files with 1811 additions and 4081 deletions

View File

@@ -1,70 +1,45 @@
/**
* Reduce color opacity to 50% for dimming effect
* @param {string} color - oklch color string
*/
export function tameColor(color) {
if (color === "transparent") return color;
return `${color.slice(0, -1)} / 50%)`;
}
/**
* @typedef {Object} ColorMethods
* @property {() => string} tame - Returns tamed (50% opacity) version
* @property {(highlighted: boolean) => string} highlight - Returns normal if highlighted, tamed otherwise
*/
/**
* @typedef {(() => string) & ColorMethods} Color
*/
/**
* Creates a Color object that is callable and has utility methods
* @param {() => string} getter
* @returns {Color}
*/
function createColor(getter) {
const color = /** @type {Color} */ (() => getter());
color.tame = () => tameColor(getter());
color.highlight = (highlighted) => highlighted ? getter() : tameColor(getter());
return color;
}
/**
* @param {Accessor<boolean>} dark
*/
export function createColors(dark) {
const globalComputedStyle = getComputedStyle(window.document.documentElement);
/**
* @param {string} color
* @param {string} name
*/
function getColor(color) {
return globalComputedStyle.getPropertyValue(`--${color}`);
}
function red() {
return getColor("red");
}
function orange() {
return getColor("orange");
}
function amber() {
return getColor("amber");
}
function yellow() {
return getColor("yellow");
}
function avocado() {
return getColor("avocado");
}
function lime() {
return getColor("lime");
}
function green() {
return getColor("green");
}
function emerald() {
return getColor("emerald");
}
function teal() {
return getColor("teal");
}
function cyan() {
return getColor("cyan");
}
function sky() {
return getColor("sky");
}
function blue() {
return getColor("blue");
}
function indigo() {
return getColor("indigo");
}
function violet() {
return getColor("violet");
}
function purple() {
return getColor("purple");
}
function fuchsia() {
return getColor("fuchsia");
}
function pink() {
return getColor("pink");
}
function rose() {
return getColor("rose");
}
function gray() {
return getColor("gray");
function getColor(name) {
return globalComputedStyle.getPropertyValue(`--${name}`);
}
/**
@@ -76,41 +51,33 @@ export function createColors(dark) {
return dark() ? _dark : light;
}
function textColor() {
return getLightDarkValue("--color");
}
function borderColor() {
return getLightDarkValue("--border-color");
}
return {
default: textColor,
gray,
border: borderColor,
default: createColor(() => getLightDarkValue("--color")),
gray: createColor(() => getColor("gray")),
border: createColor(() => getLightDarkValue("--border-color")),
red,
orange,
amber,
yellow,
avocado,
lime,
green,
emerald,
teal,
cyan,
sky,
blue,
indigo,
violet,
purple,
fuchsia,
pink,
rose,
red: createColor(() => getColor("red")),
orange: createColor(() => getColor("orange")),
amber: createColor(() => getColor("amber")),
yellow: createColor(() => getColor("yellow")),
avocado: createColor(() => getColor("avocado")),
lime: createColor(() => getColor("lime")),
green: createColor(() => getColor("green")),
emerald: createColor(() => getColor("emerald")),
teal: createColor(() => getColor("teal")),
cyan: createColor(() => getColor("cyan")),
sky: createColor(() => getColor("sky")),
blue: createColor(() => getColor("blue")),
indigo: createColor(() => getColor("indigo")),
violet: createColor(() => getColor("violet")),
purple: createColor(() => getColor("purple")),
fuchsia: createColor(() => getColor("fuchsia")),
pink: createColor(() => getColor("pink")),
rose: createColor(() => getColor("rose")),
};
}
/**
* @typedef {ReturnType<typeof createColors>} Colors
* @typedef {Colors["orange"]} Color
* @typedef {keyof Colors} ColorName
*/

View File

@@ -215,15 +215,13 @@ export function importStyle(href) {
/**
* @template T
* @param {Object} args
* @param {T} args.defaultValue
* @param {T} args.defaultValue - Fallback when selected value is no longer in choices
* @param {string} [args.id]
* @param {readonly T[] | Accessor<readonly T[]>} args.choices
* @param {string} [args.keyPrefix]
* @param {string} [args.key]
* @param {boolean} [args.sorted]
* @param {Signals} args.signals
* @param {Signal<T>} [args.signal] - Optional external signal to use instead of creating one
* @param {(choice: T) => string} [args.toKey] - Extract string key for storage (defaults to identity for strings)
* @param {Signal<T>} args.selected
* @param {(choice: T) => string} [args.toKey] - Extract string key (defaults to identity for strings)
* @param {(choice: T) => string} [args.toLabel] - Extract display label (defaults to identity for strings)
* @param {"radio" | "select"} [args.type] - Render as radio buttons or select dropdown
*/
@@ -231,10 +229,8 @@ export function createChoiceField({
id,
choices: unsortedChoices,
defaultValue,
keyPrefix,
key,
signals,
signal: externalSignal,
selected,
sorted,
toKey = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c),
toLabel = /** @type {(choice: T) => string} */ ((/** @type {any} */ c) => c),
@@ -260,25 +256,8 @@ export function createChoiceField({
: c;
});
/**
* @param {string} storedKey
* @returns {T}
*/
function fromKey(storedKey) {
const found = choices().find((c) => toKey(c) === storedKey);
return found ?? defaultValue;
}
/** @type {Signal<T>} */
const selected = externalSignal ?? signals.createSignal(defaultValue, {
save: {
serialize: (v) => toKey(v),
deserialize: (s) => fromKey(s),
keyPrefix: keyPrefix ?? "",
key: key ?? "",
saveDefaultValue: true,
},
});
/** @param {string} key */
const fromKey = (key) => choices().find((c) => toKey(c) === key) ?? defaultValue;
const field = window.document.createElement("div");
field.classList.add("field");
@@ -317,8 +296,8 @@ export function createChoiceField({
}
} else if (type === "select") {
const select = window.document.createElement("select");
select.id = id ?? key ?? "";
select.name = id ?? key ?? "";
select.id = id ?? "";
select.name = id ?? "";
choices.forEach((choice) => {
const option = window.document.createElement("option");
@@ -346,7 +325,7 @@ export function createChoiceField({
}
}
} else {
const fieldId = id ?? key ?? "";
const fieldId = id ?? "";
choices.forEach((choice) => {
const choiceKey = toKey(choice);
const choiceLabel = toLabel(choice);
@@ -372,7 +351,7 @@ export function createChoiceField({
}
});
return { field, selected };
return field;
}
/**

View File

@@ -104,10 +104,8 @@ export const serdeBool = {
deserialize(v) {
if (v === "true" || v === "1") {
return true;
} else if (v === "false" || v === "0") {
return false;
} else {
throw "deser bool err";
return false;
}
},
};

View File

@@ -1,25 +1,3 @@
/**
* @param {string} key
*/
export function readStoredNumber(key) {
const saved = readStored(key);
if (saved) {
return Number(saved);
}
return null;
}
/**
* @param {string} key
*/
export function readStoredBool(key) {
const saved = readStored(key);
if (saved) {
return saved === "true" || saved === "1";
}
return null;
}
/**
* @param {string} key
*/

View File

@@ -3,10 +3,12 @@
*/
function processPathname(pathname) {
pathname ||= window.location.pathname;
return Array.isArray(pathname) ? pathname.join("/") : pathname;
const result = Array.isArray(pathname) ? pathname.join("/") : pathname;
// Strip leading slash to avoid double slashes when prepending /
return result.startsWith("/") ? result.slice(1) : result;
}
const chartParamsWhitelist = ["from", "to"];
const chartParamsWhitelist = ["range"];
/**
* @param {string | string[]} pathname
@@ -16,7 +18,6 @@ export function pushHistory(pathname) {
pathname = processPathname(pathname);
try {
const url = `/${pathname}?${urlParams.toString()}`;
console.log(`push history: ${url}`);
window.history.pushState(null, "", url);
} catch (_) {}
}
@@ -31,7 +32,6 @@ export function replaceHistory({ urlParams, pathname }) {
pathname = processPathname(pathname);
try {
const url = `/${pathname}?${urlParams.toString()}`;
console.log(`replace history: ${url}`);
window.history.replaceState(null, "", url);
} catch (_) {}
}