feat(settings): a Pet page for the mascot
Settings -> Pet (/settings/pet, PetSettings.tsx): show/hide, speech bubbles, size with a live preview, and the pet grid - Sagi, featured codex-pets.net pets (downloaded on first pick), your own (deletable) - with image upload and .codex-pet.zip import. The Sagi block leaves General; the mascot menu's Pet settings opens the page. PetMenu and the page share components/Sagi/usePets.ts.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file Settings.tsx
|
||||
* @description The install-wide settings, as two pages of the Settings nav (`SettingsHub.tsx`): `section="general"` — total cost, workspaces housekeeping, import, remote sources, Sagi, data management and system information — and `section="notifications"` — browser notifications and alerts. Appearance is its own page (`components/settings/AppearanceSettings.tsx`); per-tool settings live in that tool's page under `/settings/agents/<id>`.
|
||||
* @description The install-wide settings, as two pages of the Settings nav (`SettingsHub.tsx`): `section="general"` — total cost, workspaces housekeeping, import, remote sources, data management and system information (Sagi has its own page, `components/settings/PetSettings.tsx`) — and `section="notifications"` — browser notifications and alerts. Appearance is its own page (`components/settings/AppearanceSettings.tsx`); per-tool settings live in that tool's page under `/settings/agents/<id>`.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
/* =============================================================================
|
||||
@@ -23,7 +23,6 @@
|
||||
* ## Internal dependencies
|
||||
* - `../lib/api`
|
||||
* - `../lib/eventBus`
|
||||
* - `../components/Sagi/prefs`
|
||||
* - `../lib/format`
|
||||
* - `../lib/push`
|
||||
* - `../components/Tip`
|
||||
@@ -90,7 +89,6 @@ import {
|
||||
import { api } from "../lib/api";
|
||||
import { eventBus } from "../lib/eventBus";
|
||||
import { isRemoteDataRefreshMessage } from "../lib/remoteDataEvents";
|
||||
import { sagiPrefs } from "../components/Sagi/prefs";
|
||||
import { fmt, fmtCost } from "../lib/format";
|
||||
import { subscribeToPush, unsubscribeFromPush } from "../lib/push";
|
||||
import {
|
||||
@@ -209,11 +207,6 @@ export function Settings({
|
||||
} | null>(null);
|
||||
const [confirmAction, setConfirmAction] = useState<string | null>(null);
|
||||
const [notifPrefs, setNotifPrefs] = useState<NotifPrefs>(loadNotifPrefs);
|
||||
const [sagiEnabled, setSagiEnabled] = useState(() => sagiPrefs.getEnabled());
|
||||
const setSagi = useCallback((v: boolean) => {
|
||||
sagiPrefs.setEnabled(v);
|
||||
setSagiEnabled(v);
|
||||
}, []);
|
||||
const [abandonHours, setAbandonHours] = useState("24");
|
||||
const [purgeDays, setPurgeDays] = useState("90");
|
||||
const [gcDryRun, setGcDryRun] = useState(false);
|
||||
@@ -458,49 +451,6 @@ export function Settings({
|
||||
<section id="remote-sources" className="scroll-mt-24">
|
||||
<RemoteSources />
|
||||
</section>
|
||||
|
||||
{/* ─── SAGI COMPANION ─── */}
|
||||
<section id="sagi" className="scroll-mt-24">
|
||||
<h3 className="text-sm font-medium text-fg-secondary flex items-center gap-2 mb-1">
|
||||
<span className="text-base leading-none" aria-hidden>
|
||||
🦸
|
||||
</span>
|
||||
{t("sagi.title", "Sagi companion")}
|
||||
</h3>
|
||||
<p className="text-xs text-fg-muted mb-4">
|
||||
{t("sagi.description", "A floating mascot that reacts to your live sessions.")}
|
||||
</p>
|
||||
|
||||
<div className="card p-5">
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className={`w-10 h-10 rounded-xl flex items-center justify-center transition-colors ${
|
||||
sagiEnabled
|
||||
? "bg-blue-600/10 border border-blue-600/20"
|
||||
: "bg-surface-2 border border-border"
|
||||
}`}
|
||||
>
|
||||
<span className="text-lg leading-none" aria-hidden>
|
||||
🦸
|
||||
</span>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<SettingsSwitchRow
|
||||
checked={sagiEnabled}
|
||||
onChange={setSagi}
|
||||
label={t("sagi.enable", "Show Sagi")}
|
||||
description={t(
|
||||
"sagi.enableDesc",
|
||||
"Display the corner companion across the dashboard (⌘B to open)"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p data-testid="sagi-pet-hint" className="mt-3 text-xs text-fg-muted">
|
||||
{t("sagi.petHint")}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user