From 7a0d1e93f302a8496ad84d1f636e9417712471e8 Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Sat, 4 Jul 2026 22:25:06 +0200 Subject: [PATCH] fix(review): restore cookie attrs + color fallback, drop stale knip entry Code-review findings: - donation-toast: restore path/secure/sameSite cookie attributes the inlined useCookie dropped (security/scope regression). - utils/color: restore @uiw fallback so percentage-notation rgb() still converts (custom style-rule colors are arbitrary strings); add tests pinning the one real difference vs the black fallback. - knip: drop stale npm-check-updates ignoreDependencies entry. Claude-Session: https://claude.ai/code/session_012Bnvt1MghwHj4qQRxuQUGa --- apps/web/src/components/ui/donation-toast.tsx | 3 ++- knip.json | 2 +- packages/utils/package.json | 1 + packages/utils/src/color.test.ts | 8 ++++++++ packages/utils/src/color.ts | 10 ++++++---- pnpm-lock.yaml | 3 +++ 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/web/src/components/ui/donation-toast.tsx b/apps/web/src/components/ui/donation-toast.tsx index 8b5a4a98b..81e9be77d 100644 --- a/apps/web/src/components/ui/donation-toast.tsx +++ b/apps/web/src/components/ui/donation-toast.tsx @@ -18,7 +18,8 @@ export function DonationToast() { const [dismissed, setDismissedState] = useState(() => Cookies.get(DISMISSED_COOKIE_NAME) ?? null); const setDismissed = useCallback((value: string, options?: { expires?: Date }) => { - Cookies.set(DISMISSED_COOKIE_NAME, value, options); + // Attributes match the former useCookie DEFAULT_COOKIE_ATTRIBUTES; options (expiry) override. + Cookies.set(DISMISSED_COOKIE_NAME, value, { path: "/", secure: true, sameSite: "lax", ...options }); setDismissedState(value); }, []); diff --git a/knip.json b/knip.json index 6988b5ba6..788720647 100644 --- a/knip.json +++ b/knip.json @@ -53,5 +53,5 @@ "ignoreDependencies": ["ioredis"] } }, - "ignoreDependencies": ["@reactive-resume/config", "npm-check-updates"] + "ignoreDependencies": ["@reactive-resume/config"] } diff --git a/packages/utils/package.json b/packages/utils/package.json index 14e3f2b93..3c73006e4 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -23,6 +23,7 @@ }, "dependencies": { "@sindresorhus/slugify": "^3.0.0", + "@uiw/color-convert": "^2.10.3", "clsx": "^2.1.1", "tailwind-merge": "^3.6.0", "unique-names-generator": "^4.7.1", diff --git a/packages/utils/src/color.test.ts b/packages/utils/src/color.test.ts index fb82e3f33..23a88d060 100644 --- a/packages/utils/src/color.test.ts +++ b/packages/utils/src/color.test.ts @@ -26,6 +26,14 @@ describe("rgbaStringToHex", () => { expect(rgbaStringToHex("#F1F5F9")).toBe("#f1f5f9"); expect(rgbaStringToHex("#0F172A")).toBe("#0f172a"); }); + + it("converts percentage-notation rgb via the @uiw fallback (integer parser misses it)", () => { + expect(rgbaStringToHex("rgb(100%, 0%, 0%)")).toBe("#ff0000"); + }); + + it("returns black for formats neither parser nor @uiw understands", () => { + expect(rgbaStringToHex("not-a-color")).toBe("#000000"); + }); }); describe("isDarkColor", () => { diff --git a/packages/utils/src/color.ts b/packages/utils/src/color.ts index 14f54fcff..0ae17a0ee 100644 --- a/packages/utils/src/color.ts +++ b/packages/utils/src/color.ts @@ -1,12 +1,14 @@ +import { hsvaToHex, rgbaStringToHsva } from "@uiw/color-convert"; + type ParsedColor = { r: number; g: number; b: number; a: number }; export function rgbaStringToHex(rgba: string): string { const color = parseColorString(rgba); if (color) return `#${toHexComponent(color.r)}${toHexComponent(color.g)}${toHexComponent(color.b)}`; - // ponytail: unrecognized format → black. Callers only pass builder-picker output (hex/rgba), - // which parseColorString handles; named-color/hsl inputs never reach here. If a caller ever needs - // those, restore a real converter (e.g. @uiw/color-convert) instead of this black fallback. - return "#000000"; + // Fallback: the local parser is integer-only, so percentage-notation rgb() (e.g. "rgb(100%,0%,0%)") + // reaches here — @uiw converts it. Everything @uiw can't parse (named colors, hsl, transparent) + // yields black, same as it always has. Custom style-rule colors are arbitrary strings, so keep this. + return hsvaToHex(rgbaStringToHsva(rgba)); } function toHexComponent(value: number): string { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c311db387..13db928ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1080,6 +1080,9 @@ importers: '@sindresorhus/slugify': specifier: ^3.0.0 version: 3.0.0 + '@uiw/color-convert': + specifier: ^2.10.3 + version: 2.10.3(@babel/runtime@7.29.7) clsx: specifier: ^2.1.1 version: 2.1.1