Something went wrong. Try again.
a tiny pet with a GPT-2 brain, living in your browser
Something went wrong. Try again.
5.8 kB · 177 lines
TSX
at cloud-pet
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178import { getBrain, olderBrain } from "../app/brain.ts";import { deleteBrain, exportSave, importSave, renameOwner, resetSave, setChatter,} from "../app/commands.ts";import { CFG } from "../app/config.ts";import { installApp, installEvent, isIOS, setAlerts, standalone } from "../app/pwa.ts";import { brain, store, ui, upgrade } from "../app/store.ts";import { fmtMB } from "../app/utils.ts";import { brainStatus } from "./Brain.tsx";import { HostingSettings } from "./Hosting.tsx";import { isRemote } from "../app/hosting.ts";export function Settings() { const s = store.state, st = brain.state, up = upgrade.state; const canUpgrade = !isRemote() && st === "ready" && olderBrain() && (up === "idle" || up === "error"); const installing = !standalone() && (!!installEvent || isIOS()); const alertNote = s.settings.alerts ? standalone() ? "Alerts arrive while the app is open or in the background; when it is closed, your device decides how often it may check." : "Alerts arrive while this tab is open in the background. Installed as an app, they can also come when it is closed, on some devices." : ui.alertsNote; return ( <> <HostingSettings /> <h2>Brain</h2> <p id="brain-status" role="status"> {brainStatus()} </p> <progress id="brain-bar" hidden={st !== "downloading" && up !== "downloading"} max={up === "downloading" ? CFG.size : brain.progress?.total} value={up === "downloading" ? Math.min(upgrade.loaded, CFG.size) : brain.progress?.loaded} /> <div class="pet-row"> <button id="brain-load" type="button" class="primary" disabled={ui.hostingBusy} hidden={!(st === "off" || st === "error" || canUpgrade)} onClick={getBrain} > {isRemote() ? ( "reconnect to server" ) : ( <> {canUpgrade ? "get the new brain" : "download brain"} ({fmtMB(CFG.size)}) </> )} </button> <button id="brain-forget" type="button" class="text-button" disabled={ui.hostingBusy} hidden={isRemote() || st === "downloading" || st === "warming" || up === "downloading"} onClick={deleteBrain} > delete brain </button> </div> <p id="brain-storage" class="muted small"> {ui.storage} </p> <label class="pet-check"> <input id="chatter-toggle" type="checkbox" checked={s.settings.chatter} disabled={ui.hostingBusy} onChange={(e) => setChatter(e.currentTarget.checked)} />{" "} Lively: your pet thinks for itself every few seconds (wanders, mutters, wants things). Off, it mostly waits for you.{" "} {isRemote() ? "The server keeps its thoughts going while this app is closed." : "Turning it off saves battery."} </label> <h2>App and alerts</h2> <div id="install-row" hidden={!installing}> <p class="muted small"> Install tokenling to open it from your home screen, use it offline and keep your pet's storage safer from browser clean-ups. </p> <div class="pet-row"> <button id="install-btn" type="button" class="primary" hidden={!installEvent} onClick={installApp} > install app </button> </div> <p id="install-note" class="muted small"> {isIOS() && !standalone() ? "On iPhone and iPad: tap Share, then Add to Home Screen." : ""} </p> </div> <label class="pet-check"> <input id="alerts-toggle" type="checkbox" disabled={!s.pet || ui.hostingBusy} checked={!!s.settings.alerts} onChange={(e) => setAlerts(e.currentTarget.checked)} />{" "} Alerts: tell me when my pet gets hungry, makes a mess, feels sick or grows up. Off unless you turn it on. </label> <p id="alerts-note" class="muted small"> {alertNote} </p> <h2>You</h2> <label for="owner-name-edit">Your name</label> <input id="owner-name-edit" maxLength={24} autoComplete="nickname" defaultValue={s.owner} disabled={ui.hostingBusy} onChange={(e) => renameOwner(e.currentTarget.value)} /> <h2>Save</h2> <p class="muted small"> {isRemote() ? "Your server holds your pet, chat and diary; this browser keeps the last synchronized copy. Exports are local recovery saves and omit the server access key." : "Your pet, chat and diary live in this browser's local storage."} </p> <div class="pet-row"> <button id="save-export" type="button" class="text-button" disabled={ui.hostingBusy} onClick={exportSave} > export save </button> <label class="text-button pet-file"> import save{" "} <input id="save-import" type="file" accept="application/json" disabled={ui.hostingBusy} onChange={async (e) => { const input = e.currentTarget, file = input.files?.[0]; if (file) await importSave(file); input.value = ""; }} /> </label> <button id="save-reset" type="button" class="text-button" disabled={ui.hostingBusy} onClick={resetSave} > start over </button> </div> </> );}