Refactor voice HUD with improved state management and settings #4036
6 changed files+377−18
Addedapp/install/page.jsx+127−0View fileUnifiedSplit
@@ -0,0 +1,127 @@
1'use client'
2
3import { useState } from 'react'
4
5const STEPS = [
6 {
7 number: '1',
8 title: 'Download',
9 desc: 'Click the button above. You\'ll get a .zip file called 48co-extension.zip.',
10 detail: null,
11 },
12 {
13 number: '2',
14 title: 'Unzip',
15 desc: 'Extract the zip file. You\'ll see a folder called extension/ with these files inside:',
16 detail: 'manifest.json, background.js, content.js, popup.html, and more.',
17 },
18 {
19 number: '3',
20 title: 'Open Chrome Extensions',
21 desc: 'Type this into your Chrome address bar and press Enter:',
22 detail: 'chrome://extensions',
23 },
24 {
25 number: '4',
26 title: 'Enable Developer Mode',
27 desc: 'In the top-right corner of the extensions page, flip the "Developer mode" toggle ON.',
28 detail: null,
29 },
30 {
31 number: '5',
32 title: 'Load the extension',
33 desc: 'Click "Load unpacked" (top-left), then select the extension/ folder you unzipped.',
34 detail: null,
35 },
36 {
37 number: '6',
38 title: 'Done — go to an AI chat',
39 desc: 'Open Claude.ai, ChatGPT, Gemini, or DeepSeek. The 48co mic widget appears in the bottom-right. Scroll up to record.',
40 detail: null,
41 },
42]
43
44export default function InstallPage() {
45 const [downloaded, setDownloaded] = useState(false)
46
47 return (
48 <main className="min-h-screen bg-[#0a0a0e] text-white font-mono">
49 <div className="max-w-xl mx-auto px-4 py-16">
50 {/* Back link */}
51 <a href="/" className="text-[11px] text-white/20 hover:text-white/40 transition-colors">
52 ← Back to 48co.nz
53 </a>
54
55 <h1 className="text-3xl font-bold mt-8 mb-2">Install 48co</h1>
56 <p className="text-white/35 text-sm mb-10">
57 Takes about 60 seconds. No account needed.
58 </p>
59
60 {/* Download button */}
61 <a
62 href="/48co-extension.zip"
63 download="48co-extension.zip"
64 onClick={() => setDownloaded(true)}
65 className={`
66 inline-flex items-center gap-3 px-8 py-4 rounded-xl text-sm font-bold tracking-wider transition-all mb-12
67 ${downloaded
68 ? 'bg-[#00ff88]/10 border border-[#00ff88]/30 text-[#00ff88]'
69 : 'bg-[#00f0ff]/10 border border-[#00f0ff]/30 text-[#00f0ff] hover:bg-[#00f0ff]/20'
70 }
71 `}
72 >
73 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
74 <path d="M12 5v14M5 12l7 7 7-7" strokeLinecap="round" strokeLinejoin="round"/>
75 </svg>
76 {downloaded ? 'Downloaded! Now follow the steps below' : 'Download 48co-extension.zip'}
77 </a>
78
79 {/* Steps */}
80 <div className="space-y-4">
81 {STEPS.map((step, i) => (
82 <div
83 key={step.number}
84 className="glass rounded-2xl p-5"
85 >
86 <div className="flex items-start gap-4">
87 <span className="flex-shrink-0 w-8 h-8 rounded-full bg-[#00f0ff]/10 text-[#00f0ff] flex items-center justify-center text-sm font-bold">
88 {step.number}
89 </span>
90 <div className="flex-1">
91 <h3 className="text-sm font-bold text-white/80 mb-1">{step.title}</h3>
92 <p className="text-[12px] text-white/40 leading-relaxed">{step.desc}</p>
93 {step.detail && (
94 <code className="inline-block mt-2 text-[11px] text-[#00f0ff]/70 bg-[#00f0ff]/5 px-3 py-1.5 rounded border border-[#00f0ff]/10">
95 {step.detail}
96 </code>
97 )}
98 </div>
99 </div>
100 </div>
101 ))}
102 </div>
103
104 {/* Troubleshooting */}
105 <div className="mt-12 glass rounded-2xl p-6">
106 <h3 className="text-[11px] tracking-[0.15em] text-white/25 mb-4 uppercase">Troubleshooting</h3>
107 <div className="space-y-3 text-[12px] text-white/35 leading-relaxed">
108 <p><span className="text-white/50">Widget not showing?</span> Refresh the AI chat page after installing. The extension only loads on claude.ai, chatgpt.com, gemini.google.com, and chat.deepseek.com.</p>
109 <p><span className="text-white/50">Mic not working?</span> Chrome will ask for microphone permission the first time. Click "Allow".</p>
110 <p><span className="text-white/50">Nothing happens when you speak?</span> Make sure you're using Chrome or Edge. Firefox and Safari don't support the Web Speech API.</p>
111 </div>
112 </div>
113
114 {/* Quick start after install */}
115 <div className="mt-8 text-center">
116 <p className="text-white/20 text-[11px] mb-4">After installing, try it on:</p>
117 <div className="flex gap-3 justify-center flex-wrap">
118 <a href="https://claude.ai" target="_blank" className="px-4 py-2 rounded-lg border border-white/10 text-white/40 text-[11px] hover:border-white/20 transition-all">Claude.ai</a>
119 <a href="https://chatgpt.com" target="_blank" className="px-4 py-2 rounded-lg border border-white/10 text-white/40 text-[11px] hover:border-white/20 transition-all">ChatGPT</a>
120 <a href="https://gemini.google.com" target="_blank" className="px-4 py-2 rounded-lg border border-white/10 text-white/40 text-[11px] hover:border-white/20 transition-all">Gemini</a>
121 <a href="https://chat.deepseek.com" target="_blank" className="px-4 py-2 rounded-lg border border-white/10 text-white/40 text-[11px] hover:border-white/20 transition-all">DeepSeek</a>
122 </div>
123 </div>
124 </div>
125 </main>
126 )
127}
Modifiedapp/page.jsx+10−16View fileUnifiedSplit
@@ -128,13 +128,13 @@ export default function LandingPage() {
128128 </div>
129129
130130 <a
131 href="#install"
131 href="/install"
132132 className="px-8 py-3 rounded-xl bg-[#00f0ff]/10 border border-[#00f0ff]/30 text-[#00f0ff] text-sm tracking-wider hover:bg-[#00f0ff]/20 transition-all"
133133 >
134 INSTALL CHROME EXTENSION
134 DOWNLOAD CHROME EXTENSION
135135 </a>
136136
137 <p className="text-[10px] text-white/15 mt-4">Free · No account required · Open source</p>
137 <p className="text-[10px] text-white/15 mt-4">Free · No account required · 60-second install</p>
138138 </section>
139139
140140 {/* ── Features Grid ─────────────────────────────────────────── */}
@@ -230,30 +230,24 @@ export default function LandingPage() {
230230
231231 <div className="flex flex-col md:flex-row gap-4 justify-center items-center mb-8">
232232 <a
233 href="#"
233 href="/install"
234234 className="px-8 py-3 rounded-xl bg-[#00f0ff]/10 border border-[#00f0ff]/30 text-[#00f0ff] text-sm tracking-wider hover:bg-[#00f0ff]/20 transition-all"
235235 >
236 Chrome Web Store (coming soon)
236 Download + Install Guide
237237 </a>
238238 <a
239239 href="https://github.com/ccantynz-alt/-48co-ai-pa"
240 target="_blank"
240241 className="px-8 py-3 rounded-xl border border-white/10 text-white/40 text-sm tracking-wider hover:border-white/20 transition-all"
241242 >
242243 View on GitHub
243244 </a>
244245 </div>
245246
246 <div className="glass rounded-2xl p-6 text-left max-w-lg mx-auto">
247 <p className="text-[10px] tracking-[0.15em] text-white/25 mb-3 uppercase">Manual Install</p>
248 <ol className="text-[11px] text-white/40 space-y-2 list-decimal list-inside">
249 <li>Download or clone the <code className="text-[#00f0ff]/60">extension/</code> folder</li>
250 <li>Open <code className="text-[#00f0ff]/60">chrome://extensions</code></li>
251 <li>Enable “Developer mode” (top right toggle)</li>
252 <li>Click “Load unpacked” and select the extension folder</li>
253 <li>Navigate to Claude, ChatGPT, Gemini, or DeepSeek</li>
254 <li>Scroll up to record, scroll down to paste</li>
255 </ol>
256 </div>
247 <p className="text-[11px] text-white/25 max-w-md mx-auto text-center leading-relaxed">
248 Download the .zip, unzip it, load it into Chrome. Takes 60 seconds.
249 No accounts, no API keys, no config. Just works.
250 </p>
257251 </section>
258252
259253 {/* ── Footer ────────────────────────────────────────────────── */}
Modifiedextension/background.js+3−0View fileUnifiedSplit
@@ -137,5 +137,8 @@ chrome.runtime.onInstalled.addListener((details) => {
137137 autoSubmit: false,
138138 engine: 'web-speech',
139139 })
140
141 // Open welcome page so user knows what to do next
142 chrome.tabs.create({ url: chrome.runtime.getURL('welcome.html') })
140143 }
141144})
Modifiedextension/manifest.json+1−2View fileUnifiedSplit
@@ -17,8 +17,7 @@
1717 "https://chat.deepseek.com/*"
1818 ],
1919 "background": {
20 "service_worker": "background.js",
21 "type": "module"
20 "service_worker": "background.js"
2221 },
2322 "content_scripts": [
2423 {
Addedextension/welcome.html+236−0View fileUnifiedSplit
@@ -0,0 +1,236 @@
1
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <title>Welcome to 48co</title>
6 <style>
7 * { box-sizing: border-box; margin: 0; padding: 0; }
8
9 body {
10 background: #0a0a0e;
11 color: #fff;
12 font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
13 min-height: 100vh;
14 display: flex;
15 align-items: center;
16 justify-content: center;
17 padding: 40px 20px;
18 }
19
20 .container {
21 max-width: 560px;
22 width: 100%;
23 }
24
25 .logo {
26 font-family: 'JetBrains Mono', 'SF Mono', monospace;
27 font-size: 32px;
28 font-weight: 700;
29 text-align: center;
30 margin-bottom: 8px;
31 }
32 .logo .co { color: #00f0ff; }
33
34 .subtitle {
35 text-align: center;
36 color: rgba(255,255,255,0.3);
37 font-size: 13px;
38 margin-bottom: 40px;
39 }
40
41 .card {
42 background: rgba(255,255,255,0.03);
43 border: 1px solid rgba(255,255,255,0.06);
44 border-radius: 16px;
45 padding: 28px;
46 margin-bottom: 16px;
47 }
48
49 .step-number {
50 display: inline-flex;
51 align-items: center;
52 justify-content: center;
53 width: 28px;
54 height: 28px;
55 border-radius: 50%;
56 background: rgba(0, 240, 255, 0.1);
57 color: #00f0ff;
58 font-size: 13px;
59 font-weight: 700;
60 margin-bottom: 12px;
61 }
62
63 .card h3 {
64 font-size: 16px;
65 font-weight: 600;
66 color: rgba(255,255,255,0.9);
67 margin-bottom: 8px;
68 }
69
70 .card p {
71 font-size: 13px;
72 line-height: 1.7;
73 color: rgba(255,255,255,0.4);
74 }
75
76 .highlight {
77 color: #00f0ff;
78 font-weight: 500;
79 }
80
81 .sites {
82 display: flex;
83 gap: 8px;
84 margin-top: 16px;
85 flex-wrap: wrap;
86 }
87 .site-badge {
88 padding: 6px 14px;
89 border-radius: 8px;
90 background: rgba(255,255,255,0.04);
91 border: 1px solid rgba(255,255,255,0.08);
92 font-size: 12px;
93 color: rgba(255,255,255,0.5);
94 }
95
96 .controls-grid {
97 display: grid;
98 grid-template-columns: 1fr 1fr 1fr;
99 gap: 12px;
100 margin-top: 16px;
101 }
102 .control {
103 text-align: center;
104 padding: 14px 8px;
105 border-radius: 12px;
106 background: rgba(255,255,255,0.03);
107 border: 1px solid rgba(255,255,255,0.06);
108 }
109 .control-icon {
110 font-size: 20px;
111 margin-bottom: 6px;
112 }
113 .control-label {
114 font-size: 10px;
115 color: rgba(255,255,255,0.3);
116 letter-spacing: 0.05em;
117 }
118
119 .commands-list {
120 margin-top: 12px;
121 }
122 .cmd-row {
123 display: flex;
124 justify-content: space-between;
125 padding: 6px 0;
126 border-bottom: 1px solid rgba(255,255,255,0.04);
127 font-size: 12px;
128 }
129 .cmd-row:last-child { border-bottom: none; }
130 .cmd-trigger { color: #00f0ff; }
131 .cmd-action { color: rgba(255,255,255,0.25); }
132
133 .cta {
134 display: block;
135 text-align: center;
136 margin-top: 32px;
137 padding: 14px 32px;
138 border-radius: 12px;
139 background: rgba(0, 240, 255, 0.1);
140 border: 1px solid rgba(0, 240, 255, 0.25);
141 color: #00f0ff;
142 font-size: 14px;
143 font-weight: 600;
144 text-decoration: none;
145 cursor: pointer;
146 transition: background 0.2s;
147 }
148 .cta:hover { background: rgba(0, 240, 255, 0.2); }
149
150 .footer {
151 text-align: center;
152 margin-top: 24px;
153 color: rgba(255,255,255,0.15);
154 font-size: 11px;
155 }
156 .footer a { color: rgba(255,255,255,0.2); text-decoration: none; }
157 .footer a:hover { color: #00f0ff; }
158 </style>
159</head>
160<body>
161 <div class="container">
162 <div class="logo">48<span class="co">co</span></div>
163 <p class="subtitle">Voice input for AI chat — installed successfully</p>
164
165 <!-- Step 1: Go to a supported site -->
166 <div class="card">
167 <div class="step-number">1</div>
168 <h3>Open an AI chat</h3>
169 <p>Navigate to any of these sites. The <span class="highlight">48co widget</span> appears automatically in the bottom-right corner.</p>
170 <div class="sites">
171 <a href="https://claude.ai" target="_blank" class="site-badge">Claude.ai</a>
172 <a href="https://chatgpt.com" target="_blank" class="site-badge">ChatGPT</a>
173 <a href="https://gemini.google.com" target="_blank" class="site-badge">Gemini</a>
174 <a href="https://chat.deepseek.com" target="_blank" class="site-badge">DeepSeek</a>
175 </div>
176 </div>
177
178 <!-- Step 2: Start recording -->
179 <div class="card">
180 <div class="step-number">2</div>
181 <h3>Start talking</h3>
182 <p>Three ways to start recording. Pick whichever feels natural.</p>
183 <div class="controls-grid">
184 <div class="control">
185 <div class="control-icon">⇧</div>
186 <div class="control-label">Scroll up</div>
187 </div>
188 <div class="control">
189 <div class="control-icon">◉</div>
190 <div class="control-label">Click widget</div>
191 </div>
192 <div class="control">
193 <div class="control-icon">⌘⇧␣</div>
194 <div class="control-label">Shortcut</div>
195 </div>
196 </div>
197 </div>
198
199 <!-- Step 3: Stop and it types -->
200 <div class="card">
201 <div class="step-number">3</div>
202 <h3>Stop — and it types for you</h3>
203 <p><span class="highlight">Scroll down</span> or click again to stop. Your transcript is typed directly into the chat input. No clipboard. No paste. It just appears.</p>
204 </div>
205
206 <!-- Voice commands -->
207 <div class="card">
208 <div class="step-number">★</div>
209 <h3>Voice commands</h3>
210 <p>Say these phrases and 48co does the rest.</p>
211 <div class="commands-list">
212 <div class="cmd-row"><span class="cmd-trigger">“refactor this”</span> <span class="cmd-action">Pastes refactor prompt</span></div>
213 <div class="cmd-row"><span class="cmd-trigger">“explain this”</span> <span class="cmd-action">Pastes explain prompt</span></div>
214 <div class="cmd-row"><span class="cmd-trigger">“debug this”</span> <span class="cmd-action">Pastes debug prompt</span></div>
215 <div class="cmd-row"><span class="cmd-trigger">“send it”</span> <span class="cmd-action">Submits message</span></div>
216 <div class="cmd-row"><span class="cmd-trigger">“cancel”</span> <span class="cmd-action">Clears & resets</span></div>
217 </div>
218 </div>
219
220 <!-- Tip: code mode -->
221 <div class="card">
222 <div class="step-number"></></div>
223 <h3>Auto code mode</h3>
224 <p>If you say words like <span class="highlight">function</span>, <span class="highlight">class</span>, <span class="highlight">import</span>, or <span class="highlight">const</span>, your transcript is automatically wrapped in markdown code fences. Click <span class="highlight">CODE</span> on the widget to force it on.</p>
225 </div>
226
227 <a href="https://claude.ai" target="_blank" class="cta">
228 Open Claude.ai →
229 </a>
230
231 <div class="footer">
232 <a href="https://48co.nz">48co.nz</a> · v1.0.0
233 </div>
234 </div>
235</body>
236</html>
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts