codehost 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/web/discovery.tsx +79 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [0.22.1](https://github.com/snomiao/codehost/compare/v0.22.0...v0.22.1) (2026-06-15)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **web:** stack the setup-card command rows on narrow screens ([4348ef7](https://github.com/snomiao/codehost/commit/4348ef72d766aba4254ecf693277a6064b06d333))
|
|
7
|
+
|
|
8
|
+
# [0.22.0](https://github.com/snomiao/codehost/compare/v0.21.0...v0.22.0) (2026-06-14)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **web:** "Set up a machine" card on the home page ([c2cec58](https://github.com/snomiao/codehost/commit/c2cec580695cf759a986b18fc8fedd1494fc542f))
|
|
14
|
+
|
|
1
15
|
# [0.21.0](https://github.com/snomiao/codehost/compare/v0.20.5...v0.21.0) (2026-06-13)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/web/discovery.tsx
CHANGED
|
@@ -196,6 +196,69 @@ function RoomClient(props: {
|
|
|
196
196
|
return null;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
+
/** Track a `(max-width: …)` media query so inline-styled components can go
|
|
200
|
+
* responsive without a stylesheet. SSR-safe and listener-cleaned. */
|
|
201
|
+
function useNarrow(maxWidth = 560): boolean {
|
|
202
|
+
const [narrow, setNarrow] = useState(
|
|
203
|
+
() => typeof window !== "undefined" && window.matchMedia(`(max-width:${maxWidth}px)`).matches,
|
|
204
|
+
);
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
const mq = window.matchMedia(`(max-width:${maxWidth}px)`);
|
|
207
|
+
const on = () => setNarrow(mq.matches);
|
|
208
|
+
on();
|
|
209
|
+
mq.addEventListener("change", on);
|
|
210
|
+
return () => mq.removeEventListener("change", on);
|
|
211
|
+
}, [maxWidth]);
|
|
212
|
+
return narrow;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** A copy-to-clipboard command row: label, the command, and a Copy button. On
|
|
216
|
+
* narrow screens the three stack vertically so the long command doesn't get
|
|
217
|
+
* crushed between a fixed label and the button. */
|
|
218
|
+
function CopyCommand({ label, command }: { label: string; command: string }) {
|
|
219
|
+
const [copied, setCopied] = useState(false);
|
|
220
|
+
const narrow = useNarrow();
|
|
221
|
+
const copy = async () => {
|
|
222
|
+
try {
|
|
223
|
+
await navigator.clipboard.writeText(command);
|
|
224
|
+
} catch {
|
|
225
|
+
// clipboard blocked (insecure context / permission) — fall back to prompt
|
|
226
|
+
window.prompt("Copy this command:", command);
|
|
227
|
+
}
|
|
228
|
+
setCopied(true);
|
|
229
|
+
setTimeout(() => setCopied(false), 1500);
|
|
230
|
+
};
|
|
231
|
+
return (
|
|
232
|
+
<div style={{ ...styles.cmdRow, ...(narrow ? styles.cmdRowNarrow : null) }}>
|
|
233
|
+
<span style={{ ...styles.cmdLabel, ...(narrow ? styles.cmdLabelNarrow : null) }}>{label}</span>
|
|
234
|
+
<code style={styles.cmdCode}>{command}</code>
|
|
235
|
+
<button style={{ ...styles.cmdCopy, ...(narrow ? styles.cmdCopyNarrow : null) }} onClick={copy}>
|
|
236
|
+
{copied ? "Copied!" : "Copy"}
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* "Set up a machine" card: the one-liner that turns any machine into a codehost
|
|
244
|
+
* server. The script bootstraps everything (Bun, the CLI, VS Code, the daemon),
|
|
245
|
+
* so the user needs no prerequisites — not even Bun. setup.sh/.ps1 are aliases
|
|
246
|
+
* of install.* served by Pages (see public/_redirects).
|
|
247
|
+
*/
|
|
248
|
+
function SetupCard() {
|
|
249
|
+
return (
|
|
250
|
+
<div style={styles.setupCard}>
|
|
251
|
+
<div style={styles.setupHead}>Set up a machine</div>
|
|
252
|
+
<p style={styles.setupSub}>
|
|
253
|
+
Run this on a machine to serve it here. It installs everything — Bun, VS Code, and the
|
|
254
|
+
codehost daemon — no prerequisites, and it picks a token and opens the browser for you.
|
|
255
|
+
</p>
|
|
256
|
+
<CopyCommand label="macOS / Linux" command="curl -fsSL https://codehost.dev/setup.sh | sh" />
|
|
257
|
+
<CopyCommand label="Windows" command={'powershell -c "irm codehost.dev/setup.ps1 | iex"'} />
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
199
262
|
export function Discovery() {
|
|
200
263
|
// Joined rooms — each token *is* a room id, and we keep one live signaling
|
|
201
264
|
// client per room (see RoomClient). Seeded from the persisted room list plus
|
|
@@ -1070,12 +1133,10 @@ export function Discovery() {
|
|
|
1070
1133
|
</span>
|
|
1071
1134
|
)}
|
|
1072
1135
|
</div>
|
|
1073
|
-
{tokens.length === 0 && <p style={styles.dim}>Join a room to see your workspaces.</p>}
|
|
1074
1136
|
{tokens.length > 0 && serverCount === 0 && (
|
|
1075
|
-
<p style={styles.dim}>
|
|
1076
|
-
No servers online. Run <code style={styles.code}>bunx codehost serve -t <token></code> on a machine.
|
|
1077
|
-
</p>
|
|
1137
|
+
<p style={styles.dim}>No servers online in your rooms yet.</p>
|
|
1078
1138
|
)}
|
|
1139
|
+
{serverCount === 0 && <SetupCard />}
|
|
1079
1140
|
{serverCount > 0 && (
|
|
1080
1141
|
<>
|
|
1081
1142
|
<input
|
|
@@ -1225,6 +1286,10 @@ export function Discovery() {
|
|
|
1225
1286
|
</p>
|
|
1226
1287
|
</section>
|
|
1227
1288
|
)}
|
|
1289
|
+
|
|
1290
|
+
{/* When servers already exist the empty-state card is hidden, so keep an
|
|
1291
|
+
"add another machine" affordance available down here. */}
|
|
1292
|
+
{serverCount > 0 && <SetupCard />}
|
|
1228
1293
|
</main>
|
|
1229
1294
|
</div>
|
|
1230
1295
|
</>
|
|
@@ -1312,6 +1377,16 @@ const styles: Record<string, React.CSSProperties> = {
|
|
|
1312
1377
|
echoBad: { marginTop: 6, fontSize: 12, color: "#f48771", fontFamily: "monospace" },
|
|
1313
1378
|
rosterSection: { marginTop: 28 },
|
|
1314
1379
|
rosterHead: { fontSize: 14, color: "#aaa", fontWeight: 600, margin: "0 0 12px" },
|
|
1380
|
+
setupCard: { marginTop: 20, background: "#252525", border: "1px solid #3d3d3d", borderRadius: 8, padding: "16px 18px" },
|
|
1381
|
+
setupHead: { fontSize: 15, color: "#fff", fontWeight: 600, marginBottom: 6 },
|
|
1382
|
+
setupSub: { fontSize: 13, color: "#aaa", margin: "0 0 14px", lineHeight: 1.5 },
|
|
1383
|
+
cmdRow: { display: "flex", alignItems: "center", gap: 10, marginTop: 8 },
|
|
1384
|
+
cmdRowNarrow: { flexDirection: "column", alignItems: "stretch", gap: 6, marginTop: 12 },
|
|
1385
|
+
cmdLabel: { fontSize: 11, color: "#888", width: 88, flexShrink: 0 },
|
|
1386
|
+
cmdLabelNarrow: { width: "auto" },
|
|
1387
|
+
cmdCode: { flex: 1, minWidth: 0, background: "#1b1b1b", border: "1px solid #3d3d3d", borderRadius: 6, padding: "8px 10px", fontFamily: "monospace", fontSize: 12.5, color: "#dcdcaa", overflow: "auto", whiteSpace: "nowrap" },
|
|
1388
|
+
cmdCopy: { flexShrink: 0, background: "#0e639c", border: "none", color: "#fff", padding: "8px 12px", borderRadius: 6, cursor: "pointer", fontSize: 12 },
|
|
1389
|
+
cmdCopyNarrow: { width: "100%", padding: "10px 12px" },
|
|
1315
1390
|
rosterHint: { margin: "10px 0 0", fontSize: 12, color: "#888" },
|
|
1316
1391
|
personRow: { display: "flex", alignItems: "center", gap: 10, background: "#252525", border: "1px solid #3d3d3d", borderRadius: 8, padding: "8px 14px", fontSize: 13 },
|
|
1317
1392
|
personDot: { color: "#4ec9b0", fontSize: 10 },
|