From a7c398fca648bc50a3563ccf464c6048a5bcf12a Mon Sep 17 00:00:00 2001 From: Natalie Date: Mon, 29 Jun 2026 19:45:23 -0400 Subject: [PATCH] feat(web): adopt the cocotte design system (P-1 foundation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First consumer of @cocotte/ui-theme. Wires the brand theme and the styled-components runtime so views can migrate off styles.css. - .npmrc: scope @cocotte/@lilith → ct-forge verdaccio (CI-resolvable) - deps: styled-components@^6.3.8 (aligned to @lilith/ui-styled-components' copy), @cocotte/ui-theme, ui-icons, ui-fab, ui-zname, site-themes@^0.1.1 - main.tsx: ThemeProvider themeName="luxe" + site-themes luxeDarkTheme customTheme (cocotte brand; lilith was the previous brand) + cssVariables + GlobalScrollbarStyles - vite: resolve.dedupe styled-components/react/react-dom — without this the ThemeProvider and styled components resolve different ThemeContexts (theme undefined) typecheck + build green; app renders clean (no console errors). Existing views still use styles.css (emerald) until the per-view migration in P1. Co-Authored-By: Claude Opus 4.8 --- .npmrc | 8 ++ package-lock.json | 352 ++++++++++++++++++++++++++++++++++++++++++++- web/package.json | 8 +- web/src/main.tsx | 12 +- web/vite.config.ts | 5 + 5 files changed, 378 insertions(+), 7 deletions(-) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..3e3812c --- /dev/null +++ b/.npmrc @@ -0,0 +1,8 @@ +# Scoped registry routing for the cocotte/lilith design system. +# @cocotte/ui-* (theme, icons, fab, zname) and their @lilith/* deps are published +# to the ct-forge Verdaccio. Default registry stays npmjs. +# Auth (_authToken for 134.199.243.61:4873) comes from user-level ~/.npmrc in dev +# and from CI env (NPM_TOKEN) on the forge runners. +registry=https://registry.npmjs.org/ +@cocotte:registry=http://134.199.243.61:4873/ +@lilith:registry=http://134.199.243.61:4873/ diff --git a/package-lock.json b/package-lock.json index 508fa78..f0f2a85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -435,6 +435,72 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/@cocotte/site-themes": { + "version": "0.1.1", + "resolved": "http://134.199.243.61:4873/@cocotte/site-themes/-/site-themes-0.1.1.tgz", + "integrity": "sha512-JQR9gIy3yZJtvxzXbam4VScInegDLfT75IYV0czgUHwJRfcGZVKEIsV4gHib86WTK2+aCBlren4uO9FGr9FKZQ==", + "dependencies": { + "@cocotte/ui-theme": "^1.5.2" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@cocotte/ui-fab": { + "version": "2.3.10", + "resolved": "http://134.199.243.61:4873/@cocotte/ui-fab/-/ui-fab-2.3.10.tgz", + "integrity": "sha512-UFdoYa9eTGsrsYWb88QyLTBUfWhrTaWC4n5joLNkMA+ptKw5zy75v+2u0tsZd5lQR2UMug8GVYBx/PocDticsA==", + "license": "UNLICENSED", + "dependencies": { + "@cocotte/ui-zname": "^1.2.5", + "@lilith/ui-design-tokens": "^1.2.1", + "@lilith/ui-motion": "^2.2.0", + "@lilith/ui-styled-components": "^6.3.9" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "styled-components": "^6.0.0" + } + }, + "node_modules/@cocotte/ui-icons": { + "version": "1.2.3", + "resolved": "http://134.199.243.61:4873/@cocotte/ui-icons/-/ui-icons-1.2.3.tgz", + "integrity": "sha512-mbfKon8tpQ5W4hbLWQ263NTIe0MpBw/TSOH2Egu/AMgQepbQa8O3fkXFNlQP9nif9j/hdWlkmAp5SQscf+xtlw==", + "license": "UNLICENSED", + "dependencies": { + "@cocotte/ui-theme": "^1.5.2", + "@lilith/ui-accessibility": "^1.2.2", + "@lilith/ui-styled-components": "^6.3.9" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "styled-components": "^6.0.0" + } + }, + "node_modules/@cocotte/ui-theme": { + "version": "1.5.2", + "resolved": "http://134.199.243.61:4873/@cocotte/ui-theme/-/ui-theme-1.5.2.tgz", + "integrity": "sha512-6lwkBH+02slFtoWRapoLT8fal1rFBfN0ufa/sccGrGJ7Y8ahD8mtWMNq0yCsYSxM+VneNi/NBXnDlOGDTyyLOQ==", + "dependencies": { + "@lilith/ui-design-tokens": "^1.2.1", + "@lilith/ui-styled-components": "^6.3.9" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "styled-components": "^6.0.0" + } + }, + "node_modules/@cocotte/ui-zname": { + "version": "1.2.5", + "resolved": "http://134.199.243.61:4873/@cocotte/ui-zname/-/ui-zname-1.2.5.tgz", + "integrity": "sha512-bsxXfHNDNsCDijc1/82lEXh8Rlr1qvMyxQbxJ/tMkvd3tkX+ix1oOjxOoxWfV549ORAY+kpRgHAJK8Ic1SBouw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "dev": true, @@ -444,6 +510,28 @@ "node": ">=0.1.90" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "http://134.199.243.61:4873/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -1345,6 +1433,109 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lilith/ui-accessibility": { + "version": "1.2.2", + "resolved": "http://134.199.243.61:4873/@lilith/ui-accessibility/-/ui-accessibility-1.2.2.tgz", + "integrity": "sha512-tb6W+ioZcRI11GzyEQOhuUWSMUulpISj9MtsuLasajKJ16gpjKq1DDW7w7Rby3OVx/7K2V1fIIRgirPK0G3xcQ==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@lilith/ui-design-tokens": { + "version": "1.2.1", + "resolved": "http://134.199.243.61:4873/@lilith/ui-design-tokens/-/ui-design-tokens-1.2.1.tgz", + "integrity": "sha512-eOVzcfEHXp/k3Kt5qR7oEw+sz8QRfFUf5ssnqfpo/St7W5mtdrgokBhXuhY8KWjtuvV9PnRFpHyDC2fGxGUI3Q==" + }, + "node_modules/@lilith/ui-motion": { + "version": "2.2.0", + "resolved": "http://134.199.243.61:4873/@lilith/ui-motion/-/ui-motion-2.2.0.tgz", + "integrity": "sha512-ZoYUCDmyjYl/pG40aIN9+RZaQNXLV5P/3Y1P29MgxzmmVzNgtyY4vH0tzD92BIyxYFxxG1nwMIir1K4bBFfD6Q==", + "dependencies": { + "framer-motion": ">=11.18.2", + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1" + }, + "peerDependencies": { + "framer-motion": ">=11.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@lilith/ui-styled-components": { + "version": "6.3.9", + "resolved": "http://134.199.243.61:4873/@lilith/ui-styled-components/-/ui-styled-components-6.3.9.tgz", + "integrity": "sha512-vwgr0RwOZlPKW5KhP+A20yIMKW0nCdlYxy6yzdBDmqFEuf18y71mY4hwTJnVd5J4oWKf2nrMxIKkXFwj6qXLeA==", + "dependencies": { + "styled-components": "6.3.8" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@lilith/ui-styled-components/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@lilith/ui-styled-components/node_modules/styled-components": { + "version": "6.3.8", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.3.8.tgz", + "integrity": "sha512-Kq/W41AKQloOqKM39zfaMdJ4BcYDw/N5CIq4/GTI0YjU6pKcZ1KKhk6b4du0a+6RA9pIfOP/eu94Ge7cu+PDCA==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "@emotion/unitless": "0.10.0", + "@types/stylis": "4.2.7", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.6", + "tslib": "2.8.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "license": "MIT", @@ -2264,6 +2455,12 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/stylis": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.7.tgz", + "integrity": "sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA==", + "license": "MIT" + }, "node_modules/@types/validator": { "version": "13.15.10", "license": "MIT" @@ -2898,6 +3095,15 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001799", "dev": true, @@ -3242,9 +3448,28 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.2.3", - "dev": true, "license": "MIT" }, "node_modules/dayjs": { @@ -3797,6 +4022,48 @@ "node": ">= 0.6" } }, + "node_modules/framer-motion": { + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.42.0.tgz", + "integrity": "sha512-wp7EJnfWaaEScVygKv3e20udoRz+LbtxScsuTkakAxfXmt+ReC6WyPW2nINRAGvd+hG9odwcjBLyOTPjH5pBRA==", + "license": "MIT", + "dependencies": { + "motion-dom": "^12.42.0", + "motion-utils": "^12.39.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/framer-motion/node_modules/motion-dom": { + "version": "12.42.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.42.0.tgz", + "integrity": "sha512-M63h4n8R+quJdNhBwuLlgxM+OLYa9+I/T2pzDRboB9fLXRdbou+Gw7Zury+SkpaCyACP1JHSjHgZ1EgTkBr30w==", + "license": "MIT", + "dependencies": { + "motion-utils": "^12.39.0" + } + }, + "node_modules/framer-motion/node_modules/motion-utils": { + "version": "12.39.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz", + "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==", + "license": "MIT" + }, "node_modules/fresh": { "version": "2.0.0", "license": "MIT", @@ -4492,6 +4759,21 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "license": "MIT" @@ -4557,7 +4839,6 @@ }, "node_modules/nanoid": { "version": "3.3.15", - "dev": true, "funding": [ { "type": "github", @@ -4841,7 +5122,6 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -4906,6 +5186,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/postgres-array": { "version": "2.0.0", "license": "MIT", @@ -5003,6 +5289,7 @@ "node_modules/react-dom": { "version": "18.3.1", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -5316,6 +5603,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "license": "MIT", @@ -5422,7 +5715,6 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -5580,6 +5872,49 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/styled-components": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.4.3.tgz", + "integrity": "sha512-wYXrhu+JmDjZ1Tv7O0OopGTfztbzun43Pjjhh2H+xc0h5A09dwpZ5FJbrifJDcL8g5TA9btpWOX2+iSRuJTExw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@emotion/is-prop-valid": "1.4.0", + "css-to-react-native": "3.2.0", + "csstype": "3.2.3", + "stylis": "4.3.6" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "css-to-react-native": ">= 3.2.0", + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-native": ">= 0.68.0" + }, + "peerDependenciesMeta": { + "css-to-react-native": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "dev": true, @@ -6640,10 +6975,17 @@ } }, "web": { + "name": "@prospector/web", "version": "0.1.0", "dependencies": { + "@cocotte/site-themes": "^0.1.1", + "@cocotte/ui-fab": "^2.3.10", + "@cocotte/ui-icons": "^1.2.3", + "@cocotte/ui-theme": "^1.5.2", + "@cocotte/ui-zname": "^1.2.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "styled-components": "^6.3.8" }, "devDependencies": { "@types/react": "^18.3.12", diff --git a/web/package.json b/web/package.json index b127ad9..6d21c05 100644 --- a/web/package.json +++ b/web/package.json @@ -9,8 +9,14 @@ "typecheck": "tsc --noEmit" }, "dependencies": { + "@cocotte/site-themes": "^0.1.1", + "@cocotte/ui-fab": "^2.3.10", + "@cocotte/ui-icons": "^1.2.3", + "@cocotte/ui-theme": "^1.5.2", + "@cocotte/ui-zname": "^1.2.5", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "styled-components": "^6.3.8" }, "devDependencies": { "@types/react": "^18.3.12", diff --git a/web/src/main.tsx b/web/src/main.tsx index 52c2e37..89e2e4b 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -1,5 +1,7 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; +import { ThemeProvider, GlobalScrollbarStyles } from '@cocotte/ui-theme'; +import { luxeDarkTheme } from '@cocotte/site-themes'; import { App } from './App'; import './styles.css'; @@ -8,9 +10,17 @@ if (!rootEl) { throw new Error('Root element #root not found'); } +// Platform design system: the cocotte brand theme = the `luxe` adapter deep-merged +// with @cocotte/site-themes' luxe-dark customTheme (gold/pink/cream on near-black; +// lilith was the previous brand). cssVariables injects the semantic tokens onto +// :root so the remaining styles.css rules can reference them during the incremental +// migration to styled-components. createRoot(rootEl).render( - + + + + , ); diff --git a/web/vite.config.ts b/web/vite.config.ts index de34483..b94b198 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -46,6 +46,11 @@ export default defineConfig(({ mode }) => { return { plugins, + // Force a single styled-components (and React) instance across the app and the + // @cocotte/ui-* + @lilith/ui-styled-components design-system packages. Without + // this, ui-theme's ThemeProvider (which feeds the theme via its own copy) and + // app/styled components resolve different ThemeContexts → `theme` is undefined. + resolve: { dedupe: ['styled-components', 'react', 'react-dom'] }, server: { proxy: devProxy }, preview: { proxy: previewProxy }, };