ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto

fix: extension dark mode and build mode messaging

- Changed darkMode from 'class' to 'media' for automatic system preference detection
- Made server offline message conditional on build mode (dev vs prod)
- Hide dev server instructions in production builds

byarielm.fyi bd3aabb7 d07180cd

verified
Changed files
+211 -21
docs
packages
extension
+24 -16
docs/git-history.json
··· 1 1 [ 2 2 { 3 - "hash": "fe29bb3e5faa0151f63c14724f7509af669860de", 4 - "short_hash": "fe29bb3", 3 + "hash": "d07180cd3a19328b82b35118e525b59d4e2e060b", 4 + "short_hash": "d07180c", 5 5 "author": "Ariel M. Lighty", 6 - "date": "2025-12-27T16:02:10-05:00", 7 - "message": "docs: update all .md files to reflect current project status\n\nUpdated 4 markdown files with current state:\n\nEXTENSION_STATUS.md:\n- Changed status from DEBUGGING to COMPLETE\n- Updated decision graph count (295 → 332 nodes)\n- Added recently completed section (nodes 296-332)\n- Marked all extension bugs as resolved\n\nCONTRIBUTING.md:\n- Replaced npm with pnpm throughout\n- Added monorepo structure documentation\n- Updated development commands (netlify-cli dev --filter)\n- Added extension development workflow\n\nPLAN.md:\n- Updated status to Phase 1 COMPLETE\n- Added all recent fixes to completion list\n- Updated decision graph count to 332 nodes\n- Added changelog entries for latest work\n\npackages/extension/README.md:\n- Added prerequisites section (dev server + login required)\n- Updated build commands with dev/prod distinction\n- Added Step 0: Start ATlast Dev Server\n- Added common issues for auth and server states\n\nAll files now accurately reflect completion status and use pnpm.", 8 - "files_changed": 6 6 + "date": "2025-12-27T18:38:39-05:00", 7 + "message": "feat: add Tailwind CSS to extension\n\nReplaced 299 lines of vanilla CSS with Tailwind for design consistency with web app. Production build minified to 13KB.", 8 + "files_changed": 9 9 + }, 10 + { 11 + "hash": "6ac877ee6d1990bdab4ef3b03ac59f4682afe0a5", 12 + "short_hash": "6ac877e", 13 + "author": "Ariel M. Lighty", 14 + "date": "2025-12-27T16:03:56-05:00", 15 + "message": "docs: update decision graph after markdown updates", 16 + "files_changed": 2 9 17 }, 10 18 { 11 19 "hash": "fe29bb3e5faa0151f63c14724f7509af669860de", ··· 24 32 "files_changed": 4 25 33 }, 26 34 { 27 - "hash": "e04934ffb5e2d78791fcd23bc3afeb4d438a5546", 28 - "short_hash": "e04934f", 35 + "hash": "46bab1202f69d8d03093a20bc8ada5ad6d365401", 36 + "short_hash": "46bab12", 29 37 "author": "Ariel M. Lighty", 30 - "date": "2025-12-26T21:57:05-05:00", 31 - "message": "perf: optimize Vite dev server startup\n\nAdded explicit optimizeDeps.include to pre-bundle common dependencies:\n- React ecosystem (react, react-dom, react-router-dom)\n- Icon libraries (@icons-pack/react-simple-icons, lucide-react)\n- Other deps (date-fns, jszip, zustand, @tanstack/react-virtual)\n\nAlso added server.fs.allow config for monorepo file serving.\n\nThis should speed up subsequent dev server starts by ensuring these\ndependencies are consistently pre-bundled.", 32 - "files_changed": 1 38 + "date": "2025-12-26T22:10:11-05:00", 39 + "message": "docs: update decision graph after Vite optimization", 40 + "files_changed": 2 33 41 }, 34 42 { 35 43 "hash": "e04934ffb5e2d78791fcd23bc3afeb4d438a5546", ··· 136 144 "files_changed": 3 137 145 }, 138 146 { 139 - "hash": "32cdee3aeac7ef986df47e0fff786b5f7471e55b", 140 - "short_hash": "32cdee3", 147 + "hash": "ba29fd68872913ba0a587aa7f29f97b3d373a732", 148 + "short_hash": "ba29fd6", 141 149 "author": "Ariel M. Lighty", 142 150 "date": "2025-12-25T13:22:32-05:00", 143 151 "message": "configure Netlify dev for monorepo with --filter flag\n\nFixed Netlify CLI monorepo detection issue by using --filter flag:\n- Updated root package.json scripts to use 'npx netlify-cli dev --filter @atlast/web'\n- Updated netlify.toml [dev] section to use npm with --prefix for framework command\n- Added monorepo development instructions to CLAUDE.md\n- Documented Windows Git Bash compatibility issue with netlify command\n\nSolution: Use 'npx netlify-cli dev --filter @atlast/web' to bypass monorepo\nproject selection prompt and specify which workspace package to run.\n\nDev server now runs successfully at http://localhost:8888 with all backend\nfunctions loaded.", 144 - "files_changed": 4 152 + "files_changed": 5 145 153 }, 146 154 { 147 - "hash": "ba29fd68872913ba0a587aa7f29f97b3d373a732", 148 - "short_hash": "ba29fd6", 155 + "hash": "32cdee3aeac7ef986df47e0fff786b5f7471e55b", 156 + "short_hash": "32cdee3", 149 157 "author": "Ariel M. Lighty", 150 158 "date": "2025-12-25T13:22:32-05:00", 151 159 "message": "configure Netlify dev for monorepo with --filter flag\n\nFixed Netlify CLI monorepo detection issue by using --filter flag:\n- Updated root package.json scripts to use 'npx netlify-cli dev --filter @atlast/web'\n- Updated netlify.toml [dev] section to use npm with --prefix for framework command\n- Added monorepo development instructions to CLAUDE.md\n- Documented Windows Git Bash compatibility issue with netlify command\n\nSolution: Use 'npx netlify-cli dev --filter @atlast/web' to bypass monorepo\nproject selection prompt and specify which workspace package to run.\n\nDev server now runs successfully at http://localhost:8888 with all backend\nfunctions loaded.", 152 - "files_changed": 5 160 + "files_changed": 4 153 161 }, 154 162 { 155 163 "hash": "c3e7afad396d130791d801a85cbfc9643bcd6309",
+165
docs/graph-data.json
··· 3849 3849 "created_at": "2025-12-27T18:07:49.869572400-05:00", 3850 3850 "updated_at": "2025-12-27T18:07:52.136827400-05:00", 3851 3851 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 3852 + }, 3853 + { 3854 + "id": 351, 3855 + "change_id": "9468bcb3-78ec-4dae-8d8f-968ba6f5b3fe", 3856 + "node_type": "outcome", 3857 + "title": "Committed Tailwind CSS integration to git", 3858 + "description": null, 3859 + "status": "completed", 3860 + "created_at": "2025-12-27T18:38:55.689869700-05:00", 3861 + "updated_at": "2025-12-27T18:39:01.013284600-05:00", 3862 + "metadata_json": "{\"branch\":\"master\",\"commit\":\"d07180c\",\"confidence\":95}" 3863 + }, 3864 + { 3865 + "id": 352, 3866 + "change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 3867 + "node_type": "goal", 3868 + "title": "Fix extension dark mode and dev/prod detection issues", 3869 + "description": null, 3870 + "status": "completed", 3871 + "created_at": "2025-12-27T22:05:50.675487800-05:00", 3872 + "updated_at": "2025-12-27T22:09:32.111749500-05:00", 3873 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90,\"prompt\":\"there now seems to be an issue with dark mode not activating, and either an issue with detecting dev vs prod or the copy is just wrong. analyze and fix.\"}" 3874 + }, 3875 + { 3876 + "id": 353, 3877 + "change_id": "eaed6e9b-9f16-4b45-8783-44ea2ea1f2a9", 3878 + "node_type": "observation", 3879 + "title": "Found two issues: 1) darkMode: 'class' requires manual .dark class addition, 2) Dev/prod detection may be incorrect", 3880 + "description": null, 3881 + "status": "completed", 3882 + "created_at": "2025-12-27T22:06:19.509001-05:00", 3883 + "updated_at": "2025-12-27T22:06:23.515277300-05:00", 3884 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 3885 + }, 3886 + { 3887 + "id": 354, 3888 + "change_id": "d66fc83e-9737-4047-8ce2-e2ba857aeea9", 3889 + "node_type": "decision", 3890 + "title": "Choose dark mode strategy: media queries vs class-based with JS", 3891 + "description": null, 3892 + "status": "completed", 3893 + "created_at": "2025-12-27T22:07:01.587088200-05:00", 3894 + "updated_at": "2025-12-27T22:07:07.798171700-05:00", 3895 + "metadata_json": "{\"branch\":\"master\",\"confidence\":85}" 3896 + }, 3897 + { 3898 + "id": 355, 3899 + "change_id": "76e2a379-7803-4c82-8013-be6b62f2d360", 3900 + "node_type": "outcome", 3901 + "title": "Chose media queries - simpler and matches original behavior", 3902 + "description": null, 3903 + "status": "completed", 3904 + "created_at": "2025-12-27T22:07:04.660558100-05:00", 3905 + "updated_at": "2025-12-27T22:07:07.897193100-05:00", 3906 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 3907 + }, 3908 + { 3909 + "id": 356, 3910 + "change_id": "df681aa8-e470-4ead-a0d2-a4095febfa3d", 3911 + "node_type": "action", 3912 + "title": "Fixing dark mode config to use media queries", 3913 + "description": null, 3914 + "status": "completed", 3915 + "created_at": "2025-12-27T22:07:24.774976300-05:00", 3916 + "updated_at": "2025-12-27T22:07:30.392290200-05:00", 3917 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 3918 + }, 3919 + { 3920 + "id": 357, 3921 + "change_id": "57060303-5a30-4f11-a752-a02376df5ea7", 3922 + "node_type": "action", 3923 + "title": "Making server offline message conditional on build mode", 3924 + "description": null, 3925 + "status": "completed", 3926 + "created_at": "2025-12-27T22:07:49.952419800-05:00", 3927 + "updated_at": "2025-12-27T22:09:00.514201500-05:00", 3928 + "metadata_json": "{\"branch\":\"master\",\"confidence\":90}" 3929 + }, 3930 + { 3931 + "id": 358, 3932 + "change_id": "fc211ac7-7a1a-4b69-835a-992c354e8237", 3933 + "node_type": "outcome", 3934 + "title": "Successfully fixed dark mode and dev/prod messaging", 3935 + "description": null, 3936 + "status": "completed", 3937 + "created_at": "2025-12-27T22:09:28.843864300-05:00", 3938 + "updated_at": "2025-12-27T22:09:32.017503200-05:00", 3939 + "metadata_json": "{\"branch\":\"master\",\"confidence\":95}" 3852 3940 } 3853 3941 ], 3854 3942 "edges": [ ··· 7701 7789 "weight": 1.0, 7702 7790 "rationale": "Final outcome of Tailwind integration", 7703 7791 "created_at": "2025-12-27T18:07:51.011406300-05:00" 7792 + }, 7793 + { 7794 + "id": 351, 7795 + "from_node_id": 344, 7796 + "to_node_id": 351, 7797 + "from_change_id": "2a06900e-ea62-4adf-81d5-7f0cf1a29b31", 7798 + "to_change_id": "9468bcb3-78ec-4dae-8d8f-968ba6f5b3fe", 7799 + "edge_type": "leads_to", 7800 + "weight": 1.0, 7801 + "rationale": "Git commit for Tailwind integration", 7802 + "created_at": "2025-12-27T18:38:58.347778400-05:00" 7803 + }, 7804 + { 7805 + "id": 352, 7806 + "from_node_id": 352, 7807 + "to_node_id": 353, 7808 + "from_change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 7809 + "to_change_id": "eaed6e9b-9f16-4b45-8783-44ea2ea1f2a9", 7810 + "edge_type": "leads_to", 7811 + "weight": 1.0, 7812 + "rationale": "Initial analysis of issues", 7813 + "created_at": "2025-12-27T22:06:21.516165300-05:00" 7814 + }, 7815 + { 7816 + "id": 353, 7817 + "from_node_id": 352, 7818 + "to_node_id": 354, 7819 + "from_change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 7820 + "to_change_id": "d66fc83e-9737-4047-8ce2-e2ba857aeea9", 7821 + "edge_type": "leads_to", 7822 + "weight": 1.0, 7823 + "rationale": "Need to decide dark mode approach", 7824 + "created_at": "2025-12-27T22:07:03.103941500-05:00" 7825 + }, 7826 + { 7827 + "id": 354, 7828 + "from_node_id": 354, 7829 + "to_node_id": 355, 7830 + "from_change_id": "d66fc83e-9737-4047-8ce2-e2ba857aeea9", 7831 + "to_change_id": "76e2a379-7803-4c82-8013-be6b62f2d360", 7832 + "edge_type": "leads_to", 7833 + "weight": 1.0, 7834 + "rationale": "Decision outcome", 7835 + "created_at": "2025-12-27T22:07:06.239151500-05:00" 7836 + }, 7837 + { 7838 + "id": 355, 7839 + "from_node_id": 352, 7840 + "to_node_id": 356, 7841 + "from_change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 7842 + "to_change_id": "df681aa8-e470-4ead-a0d2-a4095febfa3d", 7843 + "edge_type": "leads_to", 7844 + "weight": 1.0, 7845 + "rationale": "Implementation of dark mode fix", 7846 + "created_at": "2025-12-27T22:07:26.713411300-05:00" 7847 + }, 7848 + { 7849 + "id": 356, 7850 + "from_node_id": 352, 7851 + "to_node_id": 357, 7852 + "from_change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 7853 + "to_change_id": "57060303-5a30-4f11-a752-a02376df5ea7", 7854 + "edge_type": "leads_to", 7855 + "weight": 1.0, 7856 + "rationale": "Implementation of server message fix", 7857 + "created_at": "2025-12-27T22:07:51.662925600-05:00" 7858 + }, 7859 + { 7860 + "id": 357, 7861 + "from_node_id": 352, 7862 + "to_node_id": 358, 7863 + "from_change_id": "b852ce18-1747-4c26-a65e-acfbbed2b1a5", 7864 + "to_change_id": "fc211ac7-7a1a-4b69-835a-992c354e8237", 7865 + "edge_type": "leads_to", 7866 + "weight": 1.0, 7867 + "rationale": "Final outcome of fixes", 7868 + "created_at": "2025-12-27T22:09:30.425884400-05:00" 7704 7869 } 7705 7870 ] 7706 7871 }
+2 -2
packages/extension/src/popup/popup.html
··· 80 80 <!-- Server offline state --> 81 81 <div id="state-offline" class="w-full text-center hidden"> 82 82 <div class="text-5xl mb-4">🔌</div> 83 - <p class="text-base font-semibold mb-3 text-slate-700 dark:text-cyan-50">ATlast server not running</p> 84 - <p class="text-[13px] text-red-600 dark:text-red-400 mt-2 p-3 bg-red-50 dark:bg-red-950/50 rounded border-l-[3px] border-red-600"> 83 + <p class="text-base font-semibold mb-3 text-slate-700 dark:text-cyan-50">Server not available</p> 84 + <p id="dev-instructions" class="text-[13px] text-red-600 dark:text-red-400 mt-2 p-3 bg-red-50 dark:bg-red-950/50 rounded border-l-[3px] border-red-600"> 85 85 Start the dev server:<br /> 86 86 <code class="bg-black/10 dark:bg-white/10 px-2 py-1 rounded font-mono text-[11px] inline-block my-2">npx netlify-cli dev --filter @atlast/web</code> 87 87 </p>
+18 -1
packages/extension/src/popup/popup.ts
··· 5 5 type ExtensionState 6 6 } from '../lib/messaging.js'; 7 7 8 + // Build mode injected at build time 9 + declare const __BUILD_MODE__: string; 10 + 8 11 /** 9 12 * DOM elements 10 13 */ ··· 26 29 statusMessage: document.getElementById('status-message')!, 27 30 errorMessage: document.getElementById('error-message')!, 28 31 serverUrl: document.getElementById('server-url')!, 32 + devInstructions: document.getElementById('dev-instructions')!, 29 33 progressFill: document.getElementById('progress-fill')! as HTMLElement, 30 34 btnStart: document.getElementById('btn-start')! as HTMLButtonElement, 31 35 btnUpload: document.getElementById('btn-upload')! as HTMLButtonElement, ··· 214 218 if (!isOnline) { 215 219 console.log('[Popup] ❌ Server is offline'); 216 220 showState('offline'); 217 - elements.serverUrl.textContent = `Trying to reach: ${getApiUrl()}`; 221 + 222 + // Show appropriate message based on build mode 223 + const apiUrl = getApiUrl(); 224 + const isDev = __BUILD_MODE__ === 'development'; 225 + 226 + // Hide dev instructions in production 227 + if (!isDev) { 228 + elements.devInstructions.classList.add('hidden'); 229 + } 230 + 231 + elements.serverUrl.textContent = isDev 232 + ? `Development server at ${apiUrl}` 233 + : `Cannot reach ${apiUrl}`; 234 + 218 235 return false; 219 236 } 220 237
+2 -2
packages/extension/tailwind.config.js
··· 1 1 /** @type {import('tailwindcss').Config} */ 2 2 export default { 3 - // Use class-based dark mode to match web app 4 - darkMode: "class", 3 + // Use media query dark mode to automatically respect system preference 4 + darkMode: "media", 5 5 6 6 // Scan popup HTML and TypeScript files 7 7 content: [