From 3dcb862a9c05e661349e201ff6b6ec93a461439a Mon Sep 17 00:00:00 2001 From: Paul Mulligan Date: Fri, 26 Jun 2026 11:57:54 -0400 Subject: [PATCH 1/5] refactor: rebrand AI SEO Copilot to Optia Rename all brand references across code, config, docs and UI from "AI SEO Copilot"/"SEO Copilot" to "Optia". Updates package names (optia-extension, optia), manifest name/short_name/default_title, HTML tags, service-worker log prefixes, internal CSS identifiers (optia-highlight/optia-styles), and rewords the robot/copilot framing toward a score-first concept. External properties (GitHub repo/remote, Webflow site, Chrome Web Store listing, GitBook docs, Featurebase, Figma file) are intentionally left unchanged and documented as manual-rename TODOs in README.md. Build passes; 309 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- README.md | 17 ++++++++++++-- app/CHANGELOG.md | 2 +- app/PRIVACY_POLICY.md | 6 ++--- app/QA-PROMPT.md | 6 ++--- app/README.md | 10 ++++---- app/dev.html | 2 +- app/manifest.json | 6 ++--- app/package.json | 2 +- app/src/background/service-worker.ts | 34 ++++++++++++++-------------- app/src/components/Onboarding.tsx | 4 ++-- app/src/content/highlighter.ts | 4 ++-- app/src/options/index.html | 2 +- app/src/sidepanel/App.tsx | 6 ++--- app/src/sidepanel/index.html | 2 +- docs/chrome-web-store-listing.md | 6 ++--- docs/launch-social-posts.md | 18 +++++++-------- package.json | 2 +- 17 files changed, 71 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 2c56d20..5b77832 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,22 @@ -# AI SEO Copilot - Chrome Extension +# Optia - Chrome Extension A Chrome extension that analyzes web pages for SEO optimization and provides AI-powered recommendations to improve search rankings. **Website:** https://ai-seo-copilot.webflow.io/ +> ⚠️ **Rebrand in progress (AI SEO Copilot → Optia).** The codebase, UI, docs, and package names have been renamed to **Optia**. The items below live on **external systems** and must be renamed/migrated **manually by the project owner** — they were intentionally left unchanged so links don't break before migration: +> +> - **GitHub repository & remote URL** — currently `die-Manufaktur/AISEOC-Chrome-Extension`. Rename the repo, update the git remote, then update the links in `docs/` and `app/src/components/Footer.tsx`. +> - **Marketing website** — `https://ai-seo-copilot.webflow.io/` (Webflow project). +> - **Chrome Web Store listing** — extension name, description, screenshots, and the public store URL. +> - **Documentation site** — `ai-seo-copilot.gitbook.io` (referenced in `app/src/lib/docs-links.ts` and `app/src/components/Footer.tsx`). +> - **Feature-request portal** — `aiseocopilot.featurebase.app` (referenced in `app/src/components/Footer.tsx`). +> - **Bug-report repo link** — `github.com/PMDevSolutions/seo-copilot` (referenced in `app/src/components/Footer.tsx`). +> - **Figma design file** — `…/AI-SEO-Copilot-design` (referenced in `app/QA-PROMPT.md`). +> - **Donation / sponsor links** — none found in the repo; update if any exist outside it. +> +> After migrating each external property, update the corresponding URL in `Footer.tsx`, `docs-links.ts`, and the docs to the new Optia domain. + ## Features - **Real-time SEO Analysis** - Instant scoring for titles, meta descriptions, headings, images, and more @@ -29,7 +42,7 @@ pnpm build ## Project Structure ``` -ai-seo-copilot-extension/ +optia-extension/ ├── app/ # Chrome extension source code │ ├── src/ # React + TypeScript source │ ├── dist/ # Built extension (load this in Chrome) diff --git a/app/CHANGELOG.md b/app/CHANGELOG.md index 115cffc..8455569 100644 --- a/app/CHANGELOG.md +++ b/app/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -All notable changes to AI SEO Copilot will be documented in this file. +All notable changes to Optia will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/app/PRIVACY_POLICY.md b/app/PRIVACY_POLICY.md index d98222b..5590474 100644 --- a/app/PRIVACY_POLICY.md +++ b/app/PRIVACY_POLICY.md @@ -1,8 +1,8 @@ -# Privacy Policy — AI SEO Copilot +# Privacy Policy — Optia **Last updated:** April 1, 2026 -AI SEO Copilot is a Chrome browser extension that analyzes web pages for SEO issues and provides recommendations. This privacy policy explains what data the extension accesses, how it is used, and how it is stored. +Optia is a Chrome browser extension that analyzes web pages for SEO issues and provides recommendations. This privacy policy explains what data the extension accesses, how it is used, and how it is stored. ## Data the Extension Accesses @@ -53,7 +53,7 @@ No data is stored on external servers. No cookies are set. No analytics or track ## Data Sharing -AI SEO Copilot does **not**: +Optia does **not**: - Collect or transmit personal information - Use analytics, telemetry, or tracking of any kind diff --git a/app/QA-PROMPT.md b/app/QA-PROMPT.md index ec2a8d6..4953c2f 100644 --- a/app/QA-PROMPT.md +++ b/app/QA-PROMPT.md @@ -1,4 +1,4 @@ -# AI SEO Copilot — Visual QA, Functional Testing & Code Review +# Optia — Visual QA, Functional Testing & Code Review ## Your Role @@ -73,7 +73,7 @@ The app uses a strict dark-mode design system. Match these tokens against both F #### Screen 1: Setup Page (initial state) - Navigate to the dev app URL. This is the default view. - **Expected elements:** - - Blue circle icon with Settings gear + "AI SEO Copilot" heading + - Blue circle icon with Settings gear + "Optia" heading - "Dev mode" subtitle - "Page URL to Analyze" input (dev mode only) - "OpenAI API Key (optional)" password input @@ -329,7 +329,7 @@ Read the following files and review for correctness, consistency, and bugs: Produce your report in this structure: ```markdown -# AI SEO Copilot — QA Report +# Optia — QA Report ## 1. Visual Comparison diff --git a/app/README.md b/app/README.md index eefc9b2..8409174 100644 --- a/app/README.md +++ b/app/README.md @@ -1,4 +1,4 @@ -# AI SEO Copilot - Chrome Extension +# Optia - Chrome Extension A Chrome extension that analyzes web pages for SEO issues and provides AI-powered recommendations to improve search rankings. @@ -46,8 +46,8 @@ You should see something like `9.x.x` Clone or download this repository from GitHub: ```bash -git clone https://github.com/YOUR-USERNAME/ai-seo-copilot-extension.git -cd ai-seo-copilot-extension +git clone https://github.com/YOUR-USERNAME/optia-extension.git +cd optia-extension ``` Or download the ZIP file from GitHub and extract it. @@ -85,7 +85,7 @@ This creates a `dist` folder with the built extension. 4. Navigate to the `app/dist` folder inside this project and select it -5. The AI SEO Copilot extension icon should appear in your browser toolbar +5. The Optia extension icon should appear in your browser toolbar --- @@ -93,7 +93,7 @@ This creates a `dist` folder with the built extension. 1. Navigate to any website you want to analyze -2. Click the AI SEO Copilot icon in your toolbar (the little robot) +2. Click the Optia icon in your toolbar 3. Enter your target keyword and click **Analyze** diff --git a/app/dev.html b/app/dev.html index ef29677..9bd72f7 100644 --- a/app/dev.html +++ b/app/dev.html @@ -4,7 +4,7 @@ <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="icon" type="image/svg+xml" href="/icons/icon-32.svg" /> - <title>AI SEO Copilot — Dev Preview + Optia — Dev Preview diff --git a/app/eslint.config.js b/app/eslint.config.js index bf11856..84fca11 100644 --- a/app/eslint.config.js +++ b/app/eslint.config.js @@ -127,6 +127,19 @@ export default [ "no-unused-vars": "off", }, }, + { + // Build scripts (icon generation, etc.) - Node.js environment + files: ["scripts/**/*.{js,mjs}"], + languageOptions: { + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + }, + globals: { + ...globals.node, + }, + }, + }, { ignores: [ "node_modules/**", diff --git a/app/icons/icon-128.png b/app/icons/icon-128.png index 19207cc5ebf00ba85a18d5e61533dc8e00d9938f..8afcb2e34422e360a38fbb989f45cab1c8ce0d93 100644 GIT binary patch literal 6391 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 M07*qoM6N<$f@+4fAOHXW delta 756 zcmV%WG9v6vlsR?|okP=A=n(k~W4)Yg8IhDfoa! zq_nh_(m{thDTTI!wu4Um4;-r_2P!@$LI*8mCly#$-Oz} ztg_F!N;l`6Jvi%I>s#ylmNY)TphgTTpdyGEL1#N*KlbwDgpl3#){IBMvON zYM%o*PuU|q$b*N2oRfzJIDT}RS`wlKM8~F>`=`ezSAL|m(IW|L*;2(oD%!aSp;11a z>T+P)2xrb;<$w0vcc?1cCMG!X;d@;E=pBwMfL&9saOTo4#9>&< z?o0k mHedydV10CD-Kzio0{;h$QvJN@(~H>v0000|;_SADM@c9<_VuF4t z1byElh)5$%W)L=(cFU97#)XEbX4!H2yc@N3UW8jUb$?!zSGtk3-mb$J5)62kpg)7B z>hQ?-2_n)7US2|~wQ{hUC&q|~H{do4e1eFi6a|;BHsSxSil3VC#z%GzPvh`DO9^^s z5cJ9jiH7?!mFIT_`!OqU3~%qvu_?@rMWAz^!mM z`>P!sJn#Ik&3G}J!=L|%LSUvx zzb;|SBnc@i9OmW*w-*WXDTYnA)Z2h3OPI7$!Oc7OaI^XzCah7ynm%-`jD{wj(a9wa zbbt55yRD-Tw8=I}AFJmo8qJL*N7S(JiP;KdXN$R){Z3q`gf@LS!RBuo%)LjiHJb3Q z>nQ|drjMQ~nL~!PTKpm!()3`sv1nZjY`ID((-D;?qs5;Dhs%rZIXe8=JPN^>>2sIa z&BLzW@`N-!9NZd2T!9i~x?b-e{=R4Ki+?R~Xz*tWD1?zy^$R7dsMg$Y+#4mf(X`T{(qUCSIz@ie_GX3zDlq6^J_U=lP#a3O5_rbDs`aK z7K$gfQV53WLy{#p>UkTE$&@v?HrayUtj$>3jg@moHD%M_ITX(s@B)g+ZHn23vdgQ( zw^2O)358%az5Fs4Yul*?K2{C5euuMb6uGA@0i0DeIFpUlo2A@+9^c>cATrYeU+y0;*#z^;xU_RWcXD_>MVA7Krwb{b*+_BWFMi(H zKbz5UJ4FWu|5V1KB{GCy*?%VH+R^CY5%2oe#o=tYWOLb)4my!^$Z49+Wb3j)hqE@@ zR^>9!aozJ_$U#Q{y!~z&!hl7RFWB_-eNOX*#IAbHnf_mr%6$=6vNu zhhkZW?~?JzZW-WYMS|D@pbLHQku$8l2TT*z_Pcd-7IrV|7lee&B`GB&GWrda>JD xYQG=TjhSx97Q%D}x3@h&E3}#$Y4@*x0G9$Pddv{ReED%PDHLkV1no5d0+ql delta 2157 zcmV-z2$J`m4*3v}BYy}$Nkl~XW02TquCAKA8ik(hprqh{o z=3Mt)%dEBcIdkSrsa5cM*ZfItG=-zJfkBa+%2YT=Oixoo(=biPrjm9>E z8Mfd1UR$?N|AWH#;K#jZo4Z*Guof}|#uST4P)hpu8^AcAR{*xb1Goi?820aj9w-nf z38{fv#}G=WmVaVOp+b_e+)7z)q#j%~(MSi*p>cdFKn#1Zw_ok1y$^~V`uotAN(gGH zU@}pBVt%~eU!0ELZCw~w=({9zQz-$7I^aY1q>PGP?Ncx2!X+R!fl2DV)D~J z_isIj0#@!>o9|x;T1If&wB%DaR=9E36y+p9h7qMwnSXMrLKH<1Do9g~zj}dh{O;ep zcA>_2DI_(y(VQD2%8H$ za^EbqR-Pe_TN@w<(M!{w;N(}^2xgNGJHrl{&?HHTAN=q~ym9(0<0CP)xlGoq<$922 zWPfQ&mZjLVgKgEBo*bvOy2!&{eT4gG$NAvSDveI&#cLw~Tn@V5g`yQ71j2H#)Fd^A zYPHH=PdvpxUwWCbN=R$Vb+m7J0CV*rY}z6-8SPG&Mx)8)Mw`Zg`;Z^`ERzRr=cSV` zaQshy;Mi?@SZk+9nX9K4zv7ZTA&wzsYSq4|dDY3|ilM?67y~EtxdxVuqI?*KM=YEW;U&4-Wr+wfKGNmx>27gj( z~YH|igXO5%RmLZ5ytMjBMpCC;w-EKxZwPa_Xqp>v4noVddFJtE3q}J-vs$XW` zwkn;}8|-U=v#SRSkPCxCP|+46B!3;_G9dOfz*9wPjBw?{V04^&%uOoC@RY6%(2ncf zrgwF%krIUw@87eB@p_t91#i5dqHq8T<2@a4MaQLNCPG%58P^@Wo?CCeiRVwg3{s<{ z^!YBW^O8a;P|kCi#dO;k( zg|W)*lSWr_?AT|x_10H8b?OxVxp0xy)jEwvo76>8f{~IqjHo0D6XO%?y=Esjec*cT zx%*CbTy+&ID>YV{2I&asE@S(`tJgIl&jPpmxsK+VC?zzKwYDKMDF<%2g+qr9BSnTW z8A%{$rm$mKGPtki2rfNu(vlw|UNbUh;HamwHuD zpas0u3fU8-Yzqxt?P|MZZn;hpC`OW)ayjAn*-ISWJI%FQM+hQ?(%K8y_x^l_{ZnP` zy?&b2R>qcC@vGM^aeAf8NaVa)gxo6cckQykk*}z|UK*PgPOe3KSbw&O5v2Z77@_Di z3^FjhyKtGuo;u6y?yYPcPkhOKZP~DEJm&s`TUlIfp|s?=b8Q}dWtlkAK3shccn|_H z`NhZc3S9tj!=;Kdx0}>P!a};SV<;E0$zT5i4&(5SZW)_MoZkif10B= zZ1V&}8qU=$kG{UfVt>;TDea|uLnX8zwm1O2=CUB9n|2_ayGBHZ8Qo+mwj`k@4iq}j zXek&=G+IbZW+}x1aUiL+GT(%}Sr1u3P-5NpZOTGx9fbOzQ^-@L45lDC@y^KC__B!6)Lt|=PsNqePFr|ovX z73-f7ilX7f$mOmh=b{K%vLRubk+kt)&{`l}L3hoI4QOO}`{ve)T({}F9%sDQid_Lf zckOb&PqV!sc^o~}%EMumL?}f|2GmuE(t%S`q;|ROLZW>8O#djdaknm3S0Z6FI+eTL zx)2!uY@C6i{>=lB3ZdN2H9{(+4hW(c9k`IF9DwJ~=4ONI6%VI?jz_l)xF{DSN4m}1 z5Wf1kop?>}g~jW8Uf-qr>1}P3u`8a99CwQ2w?FjdQ*MWwV_1MF&XReSp*iqU}|0Phe7-oAUY_k!AlQ+00000NkvXXu0mjfrSdO- diff --git a/app/icons/icon-48.png b/app/icons/icon-48.png index 9273bb1bb7b13e4751b58c64792b5699e409df4a..5b1bb65920e28942654bd1b6a9a64b6b07fbd806 100644 GIT binary patch delta 2672 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 + + + + + + + + + + + + + diff --git a/app/package.json b/app/package.json index e80e327..51dac05 100644 --- a/app/package.json +++ b/app/package.json @@ -8,6 +8,7 @@ "dev:ext": "vite", "build": "tsc && vite build", "preview": "vite preview", + "icons": "node scripts/generate-icons.mjs", "test": "vitest run", "test:watch": "vitest", "lint": "eslint .", @@ -49,6 +50,7 @@ "globals": "^17.4.0", "jsdom": "^26.1.0", "postcss": "^8.5.4", + "sharp": "^0.35.2", "standard-version": "^9.5.0", "tailwindcss": "^3.4.17", "typescript": "^5.8.3", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index 46a5678..82ed86c 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: postcss: specifier: ^8.5.4 version: 8.5.8 + sharp: + specifier: ^0.35.2 + version: 0.35.2 standard-version: specifier: ^9.5.0 version: 9.5.0 @@ -247,6 +250,9 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -461,6 +467,152 @@ packages: resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} engines: {node: '>=6.9.0'} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.2': + resolution: {integrity: sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.2': + resolution: {integrity: sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.2': + resolution: {integrity: sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.1': + resolution: {integrity: sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.1': + resolution: {integrity: sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.1': + resolution: {integrity: sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.3.1': + resolution: {integrity: sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.3.1': + resolution: {integrity: sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.3.1': + resolution: {integrity: sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.3.1': + resolution: {integrity: sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.3.1': + resolution: {integrity: sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': + resolution: {integrity: sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + resolution: {integrity: sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.35.2': + resolution: {integrity: sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.35.2': + resolution: {integrity: sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.35.2': + resolution: {integrity: sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.35.2': + resolution: {integrity: sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.35.2': + resolution: {integrity: sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.35.2': + resolution: {integrity: sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.35.2': + resolution: {integrity: sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.35.2': + resolution: {integrity: sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.35.2': + resolution: {integrity: sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.2': + resolution: {integrity: sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.2': + resolution: {integrity: sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.2': + resolution: {integrity: sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.2': + resolution: {integrity: sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1289,6 +1441,10 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -2599,6 +2755,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2611,6 +2772,10 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + sharp@0.35.2: + resolution: {integrity: sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==} + engines: {node: '>=20.9.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3323,6 +3488,11 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true @@ -3460,6 +3630,112 @@ snapshots: '@hutson/parse-repository-url@3.0.2': {} + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.1 + optional: true + + '@img/sharp-darwin-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.1 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.1': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.1': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.1': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.1': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + optional: true + + '@img/sharp-linux-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.1 + optional: true + + '@img/sharp-linux-arm@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.1 + optional: true + + '@img/sharp-linux-ppc64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.1 + optional: true + + '@img/sharp-linux-riscv64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.1 + optional: true + + '@img/sharp-linux-s390x@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.1 + optional: true + + '@img/sharp-linux-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.1 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.2': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 + optional: true + + '@img/sharp-wasm32@0.35.2': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 + optional: true + + '@img/sharp-win32-arm64@0.35.2': + optional: true + + '@img/sharp-win32-ia32@0.35.2': + optional: true + + '@img/sharp-win32-x64@0.35.2': + optional: true + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -4385,6 +4661,8 @@ snapshots: detect-indent@6.1.0: {} + detect-libc@2.1.2: {} + detect-newline@3.1.0: {} didyoumean@1.2.2: {} @@ -5858,6 +6136,8 @@ snapshots: semver@7.7.4: {} + semver@7.8.5: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5880,6 +6160,38 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 + sharp@0.35.2: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.2 + '@img/sharp-darwin-x64': 0.35.2 + '@img/sharp-freebsd-wasm32': 0.35.2 + '@img/sharp-libvips-darwin-arm64': 1.3.1 + '@img/sharp-libvips-darwin-x64': 1.3.1 + '@img/sharp-libvips-linux-arm': 1.3.1 + '@img/sharp-libvips-linux-arm64': 1.3.1 + '@img/sharp-libvips-linux-ppc64': 1.3.1 + '@img/sharp-libvips-linux-riscv64': 1.3.1 + '@img/sharp-libvips-linux-s390x': 1.3.1 + '@img/sharp-libvips-linux-x64': 1.3.1 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 + '@img/sharp-linux-arm': 0.35.2 + '@img/sharp-linux-arm64': 0.35.2 + '@img/sharp-linux-ppc64': 0.35.2 + '@img/sharp-linux-riscv64': 0.35.2 + '@img/sharp-linux-s390x': 0.35.2 + '@img/sharp-linux-x64': 0.35.2 + '@img/sharp-linuxmusl-arm64': 0.35.2 + '@img/sharp-linuxmusl-x64': 0.35.2 + '@img/sharp-webcontainers-wasm32': 0.35.2 + '@img/sharp-win32-arm64': 0.35.2 + '@img/sharp-win32-ia32': 0.35.2 + '@img/sharp-win32-x64': 0.35.2 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 diff --git a/app/scripts/generate-icons.mjs b/app/scripts/generate-icons.mjs new file mode 100644 index 0000000..bb6b1ed --- /dev/null +++ b/app/scripts/generate-icons.mjs @@ -0,0 +1,28 @@ +/** + * Generate the Optia extension icons (PNG) from the SVG master. + * + * Usage: pnpm icons + * Source: icons/icon.svg -> icons/icon-{16,32,48,128}.png + * + * Requires `sharp` (devDependency). Re-run whenever icon.svg changes. + */ +import sharp from "sharp"; +import { readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const here = dirname(fileURLToPath(import.meta.url)); +const iconsDir = join(here, "..", "icons"); +const svg = readFileSync(join(iconsDir, "icon.svg")); +const sizes = [16, 32, 48, 128]; + +for (const size of sizes) { + const out = join(iconsDir, `icon-${size}.png`); + await sharp(svg, { density: 512 }) + .resize(size, size, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }) + .png() + .toFile(out); + console.log(`✓ icon-${size}.png`); +} + +console.log("Done — Optia icons regenerated."); diff --git a/app/src/components/AltTextEditor.tsx b/app/src/components/AltTextEditor.tsx index c64c9d9..4a5983b 100644 --- a/app/src/components/AltTextEditor.tsx +++ b/app/src/components/AltTextEditor.tsx @@ -35,18 +35,18 @@ export function AltTextEditor({ }; return ( -
+
{alt
setAlt(e.target.value)} placeholder="Enter alt text..." - className="w-full rounded-input bg-bg-500 px-3 py-2 text-body-12 text-text-primary placeholder:text-bg-300 outline-none focus:ring-1 focus:ring-accent-blue" + className="w-full rounded-input bg-surface-2 px-3 py-2 text-body-12 text-ink placeholder:text-faint outline-none focus:ring-1 focus:ring-brand" />
diff --git a/app/src/components/Footer.tsx b/app/src/components/Footer.tsx index 537a3ce..5613a76 100644 --- a/app/src/components/Footer.tsx +++ b/app/src/components/Footer.tsx @@ -9,7 +9,7 @@ const links = [ export function Footer() { return ( -