Something went wrong. Try again.
a tiny pet with a GPT-2 brain, living in your browser
Something went wrong. Try again.
4.8 kB · 127 lines
TSX
at cloud-pet
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128import { useEffect, useState } from "preact/hooks";import type { HostingMode } from "../types.ts";import { CFG } from "../app/config.ts";import { changeHosting, isRemote, moveToLocal, resumeRemote } from "../app/hosting.ts";import { store, ui, view } from "../app/store.ts";
export function HostingSettings() { const current = store.state.hosting.mode; const [mode, setMode] = useState<HostingMode>(current); const [endpoint, setEndpoint] = useState(ui.remoteEndpoint || CFG.remoteEndpoint || ""); useEffect(() => setMode(current), [current]); useEffect(() => { if (ui.remoteEndpoint) setEndpoint(ui.remoteEndpoint); }, [ui.remoteEndpoint]); const busy = ui.hostingBusy || !!view.game; return ( <section aria-labelledby="hosting-title"> <h2 id="hosting-title">Where your pet lives</h2> <fieldset class="hosting-choices" disabled={busy}> <legend class="visually-hidden">Choose local or remote</legend> <label class="hosting-option" for="hosting-local"> <input id="hosting-local" type="radio" name="hosting-mode" checked={mode === "local"} onChange={() => setMode("local")} /> <span> <strong>Local · on this device</strong> <small>Your pet runs here and works offline once its brain is downloaded.</small> </span> </label> <label class="hosting-option" for="hosting-remote"> <input id="hosting-remote" type="radio" name="hosting-mode" checked={mode === "remote"} onChange={() => setMode("remote")} /> <span> <strong>Remote · on a server</strong> <small> Your pet can think while this app is closed. The server holds its save, chat and memories. </small> </span> </label> <div hidden={mode !== "remote"}> <label for="hosting-server">Server address</label> <input id="hosting-server" type="url" placeholder="https://your-server.example" readOnly={isRemote()} value={endpoint} onInput={(e) => setEndpoint(e.currentTarget.value)} /> <p class="muted small"> Use a server you trust. To change servers, bring your pet local first, then choose its new home. </p> </div> </fieldset> <p id="hosting-status" role="status" class={ui.remoteError ? "warn" : "muted small"}> {ui.hostingBusy ? "Moving your pet safely…" : ui.remoteError || (isRemote() ? "Your server is running the pet. This browser keeps a recovery copy." : "Your pet lives in this browser.")} </p> <div class="pet-row"> <button id="hosting-switch" type="button" class="primary" disabled={ busy || mode === current || !store.state.owner || (mode === "remote" && !endpoint) } onClick={() => changeHosting(mode, endpoint)} > {mode === "remote" ? "move to server" : "bring to this device"} </button> <button id="hosting-reconnect" type="button" class="text-button" hidden={!isRemote() || !ui.remoteError} disabled={busy} onClick={resumeRemote} > reconnect </button> </div> <p class="muted small"> Switching preserves the same pet, including its memories, gifts, chat and diary. Moving local may need the {Math.round(CFG.size / 1e6)} MB brain download. </p> <div hidden={!isRemote() || !ui.remoteError}> <p class="warn"> If the server cannot be reached, you can continue from this browser's checkpoint ( {new Date(store.state.lastTick).toLocaleString()}). Newer server progress may be missing. Its copy can keep thinking until the connection returns; the local recovery copy takes priority here. </p> <button id="hosting-recover" type="button" class="text-button" disabled={busy} onClick={() => { if ( confirm( "Continue locally from this browser's last checkpoint? Progress saved only on the unavailable server cannot be recovered yet. The app will request that its old copy stop when it reconnects.", ) ) void moveToLocal(true); }} > recover locally from checkpoint </button> </div> </section> );}