From 29c6686ad7bdf537e2ee87963c4f81466538917a Mon Sep 17 00:00:00 2001 From: QuietImCoding Date: Mon, 2 Feb 2026 09:44:12 -0800 Subject: [PATCH 1/4] use accent color for sparkline --- app/components/Package/WeeklyDownloadStats.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Package/WeeklyDownloadStats.vue b/app/components/Package/WeeklyDownloadStats.vue index 1a5b257b3..450a19649 100644 --- a/app/components/Package/WeeklyDownloadStats.vue +++ b/app/components/Package/WeeklyDownloadStats.vue @@ -163,7 +163,7 @@ const config = computed(() => { color: colors.value.fg, }, line: { - color: colors.value.borderHover, + color: transparentizeOklch(accent.value, 0.5), pulse: { show: true, loop: true, // runs only once if false From 8a4c9ef080ee55a76713c1535b12b7811464be04 Mon Sep 17 00:00:00 2001 From: QuietImCoding Date: Mon, 2 Feb 2026 09:46:51 -0800 Subject: [PATCH 2/4] increase transparency to look better in light mode, might need to just interpolate with black instead --- app/components/Package/WeeklyDownloadStats.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Package/WeeklyDownloadStats.vue b/app/components/Package/WeeklyDownloadStats.vue index 450a19649..7c813234f 100644 --- a/app/components/Package/WeeklyDownloadStats.vue +++ b/app/components/Package/WeeklyDownloadStats.vue @@ -163,7 +163,7 @@ const config = computed(() => { color: colors.value.fg, }, line: { - color: transparentizeOklch(accent.value, 0.5), + color: transparentizeOklch(accent.value, 0.75), pulse: { show: true, loop: true, // runs only once if false From 091e5ca7f38b6b046379d734a9885047581207e8 Mon Sep 17 00:00:00 2001 From: QuietImCoding Date: Mon, 2 Feb 2026 09:59:18 -0800 Subject: [PATCH 3/4] use darken / lighten instead of transparency to avoid awkward artifacts --- .../Package/WeeklyDownloadStats.vue | 4 +- app/utils/colors.ts | 60 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/app/components/Package/WeeklyDownloadStats.vue b/app/components/Package/WeeklyDownloadStats.vue index 7c813234f..1eddaf45d 100644 --- a/app/components/Package/WeeklyDownloadStats.vue +++ b/app/components/Package/WeeklyDownloadStats.vue @@ -152,7 +152,7 @@ const config = computed(() => { backgroundColor: 'transparent', animation: { show: false }, area: { - color: colors.value.borderHover, + color: transparentizeOklch(accent.value, 0.2), useGradient: false, opacity: 10, }, @@ -163,7 +163,7 @@ const config = computed(() => { color: colors.value.fg, }, line: { - color: transparentizeOklch(accent.value, 0.75), + color: isDarkMode.value ? darkenOklch(accent.value, 0.5) : darkenOklch(accent.value, 0.125), pulse: { show: true, loop: true, // runs only once if false diff --git a/app/utils/colors.ts b/app/utils/colors.ts index 1e6e4a95f..ae461ebf5 100644 --- a/app/utils/colors.ts +++ b/app/utils/colors.ts @@ -147,6 +147,66 @@ export function lightenOklch( : `oklch(${lightness} ${chroma} ${hue} / ${alpha})` } +/** + * Lighten an OKLCH color by a given factor. + * + * Works with strict TypeScript settings including `noUncheckedIndexedAccess`, + * where `match[n]` is typed as `string | undefined`. + * + * @param oklch - Color in the form "oklch(L C H)" or "oklch(L C H / A)" + * @param factor - Lightening force in range [0, 1] + * @returns Lightened OKLCH color string (0.5 = 50% lighter) + */ +export function darkenOklch( + oklch: string | null | undefined, + factor: number, +): string | null | undefined { + if (oklch == null) { + return oklch + } + + const input = oklch.trim() + + const match = input.match( + /^oklch\(\s*([+-]?[\d.]+%?)\s+([+-]?[\d.]+)\s+([+-]?[\d.]+)(?:\s*\/\s*([+-]?[\d.]+%?))?\s*\)$/i, + ) + + if (!match) { + throw new Error('Invalid OKLCH color format') + } + + const [, lightnessText, chromaText, hueText, alphaText] = match + + if (lightnessText === undefined || chromaText === undefined || hueText === undefined) { + throw new Error('Invalid OKLCH color format') + } + + let lightness = lightnessText.endsWith('%') + ? Number.parseFloat(lightnessText) / 100 + : Number.parseFloat(lightnessText) + let chroma = Number.parseFloat(chromaText) + const hue = Number.parseFloat(hueText) + const alpha = + alphaText === undefined + ? null + : alphaText.endsWith('%') + ? Number.parseFloat(alphaText) / 100 + : Number.parseFloat(alphaText) + + const clampedFactor = Math.min(Math.max(factor, 0), 1) + lightness = lightness - (1 - lightness) * clampedFactor + + // Reduce chroma slightly as lightness increases + chroma = chroma * (1 + clampedFactor * 0.3) + + lightness = Math.min(Math.max(lightness, 0), 1) + chroma = Math.max(chroma, 0) + + return alpha === null + ? `oklch(${lightness} ${chroma} ${hue})` + : `oklch(${lightness} ${chroma} ${hue} / ${alpha})` +} + /** * Make an OKLCH color transparent by a given factor. * From 3921fb517e11dfada42c5a3de31ee4613b9ca37b Mon Sep 17 00:00:00 2001 From: QuietImCoding Date: Mon, 2 Feb 2026 10:00:56 -0800 Subject: [PATCH 4/4] fixed docstrings to be less confusing --- app/utils/colors.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/utils/colors.ts b/app/utils/colors.ts index ae461ebf5..dae5ba17b 100644 --- a/app/utils/colors.ts +++ b/app/utils/colors.ts @@ -148,14 +148,14 @@ export function lightenOklch( } /** - * Lighten an OKLCH color by a given factor. + * Darken an OKLCH color by a given factor. * * Works with strict TypeScript settings including `noUncheckedIndexedAccess`, * where `match[n]` is typed as `string | undefined`. * * @param oklch - Color in the form "oklch(L C H)" or "oklch(L C H / A)" - * @param factor - Lightening force in range [0, 1] - * @returns Lightened OKLCH color string (0.5 = 50% lighter) + * @param factor - Darkening force in range [0, 1] + * @returns Darkened OKLCH color string (0.5 = 50% lighter) */ export function darkenOklch( oklch: string | null | undefined,