Something went wrong. Try again.
a tiny pet with a GPT-2 brain, living in your browser
Something went wrong. Try again.
3.5 kB · 108 lines
TSX
at cloud-pet
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109import { useRef, useState } from "preact/hooks";import { DEBUG } from "../app/config.ts";import { takeOver } from "../app/lifecycle.ts";import { store, ui } from "../app/store.ts";import { BrainNotice, UpgradeDialog } from "./Brain.tsx";import { Chat } from "./Chat.tsx";import { Debug } from "./Debug.tsx";import { Device } from "./Device.tsx";import { Diary } from "./Diary.tsx";import { Settings } from "./Settings.tsx";import { Icon, useApp } from "./shared.tsx";import { Shelf } from "./Shelf.tsx";const tabs = [ ["chat", "chat"], ["diary", "diary"], ["shelf", "shelf"], ["care", "settings"], ...(DEBUG ? [["debug", "debug"]] : []),];export function App() { useApp(); const [active, setActive] = useState("chat"); const buttons = useRef<HTMLDivElement>(null); if (!store.tabOwned) return ( <div id="pet-elsewhere" class="pet-notice" role="alert"> <p> Your pet is open in another tab or window. Only one can look after it at a time, so your changes don't undo each other. </p> <button id="elsewhere-here" type="button" class="primary" onClick={takeOver}> use it here </button> </div> ); return ( <> <div class="pet-app"> <BrainNotice /> <Device /> <section class="pet-panel" aria-label="chat, diary and settings"> <div class="pet-tabs" role="tablist" aria-label="pet panels" ref={buttons}> {tabs.map(([id, label], i) => ( <button key={id} type="button" role="tab" id={`tab-${id}`} aria-controls={`panel-${id}`} aria-selected={active === id} tabIndex={active === id ? 0 : -1} onClick={() => setActive(id)} onKeyDown={(e) => { const next = e.key === "ArrowRight" ? (i + 1) % tabs.length : e.key === "ArrowLeft" ? (i + tabs.length - 1) % tabs.length : e.key === "Home" ? 0 : e.key === "End" ? tabs.length - 1 : -1; if (next < 0) return; e.preventDefault(); setActive(tabs[next][0]); buttons.current?.querySelectorAll("button")[next]?.focus(); }} > {label} </button> ))} </div> {tabs.map(([id]) => ( <div key={id} id={`panel-${id}`} role="tabpanel" aria-labelledby={`tab-${id}`} hidden={active !== id} > {id === "chat" ? ( <Chat active={active === id} /> ) : id === "diary" ? ( <Diary /> ) : id === "shelf" ? ( <Shelf /> ) : id === "care" ? ( <Settings /> ) : ( <Debug /> )} </div> ))} </section> </div> <div id="pet-toasts" class="pet-toasts" aria-live="polite"> {ui.toasts.map((t) => ( <div key={t.id} class="pet-toast" role="status"> {t.icon && <Icon name={t.icon} scale={2} />} {t.text} </div> ))} </div> <UpgradeDialog /> </> );}