Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions windows/src-tauri/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub struct Settings {
/// Defaulted explicitly so a settings.json written by an older build still loads.
#[serde(default = "default_model")]
pub model: String,
/// Show the time and date in the island while it is compact or hidden,
/// for setups where the top panel (and its clock) auto-hides under it.
#[serde(default)]
pub show_clock: bool,
}

fn default_model() -> String {
Expand All @@ -43,6 +47,7 @@ impl Default for Settings {
autostart: false,
hooks_installed: false,
model: default_model(),
show_clock: false,
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions windows/src/core/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ export interface Settings {
hooksInstalled: boolean;
/** Claude model used by the chat. */
model: string;
/** Time and date in the island while compact or hidden. */
showClock: boolean;
}

export const DEFAULT_SETTINGS: Settings = {
Expand All @@ -106,6 +108,7 @@ export const DEFAULT_SETTINGS: Settings = {
autostart: false,
hooksInstalled: false,
model: "claude-opus-5",
showClock: false,
};

type Listener = () => void;
Expand Down
16 changes: 16 additions & 0 deletions windows/src/island/fsm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export class IslandStateMachine {
greetHoverCollapseDelay = 10;
/** An alert waiting for an answer stays open, even when the mouse leaves. */
pinned = false;
/** The clock is on: the compact island stays up instead of hiding. */
private keepPetit = false;

private petitHide: number | null = null;
private homeCollapse: number | null = null;
Expand Down Expand Up @@ -102,10 +104,24 @@ export class IslandStateMachine {
this.transition("hidden");
}

/** Clock on → the island rests compact (it shows the time) and never hides by
* itself; clock off → back to hiding after the usual delay. */
setKeepPetit(on: boolean, mouseInside: boolean) {
if (this.keepPetit === on) return;
this.keepPetit = on;
if (on) {
this.clear("petitHide");
if (this.state === "hidden") this.transition("petit");
} else if (this.state === "petit" && !mouseInside) {
this.schedulePetitHide();
}
}

// ── Timers ──────────────────────────────────────────────────────────────────

private schedulePetitHide() {
this.clear("petitHide");
if (this.keepPetit) return;
this.petitHide = window.setTimeout(() => {
this.petitHide = null;
if (this.state === "petit") this.transition("hidden");
Expand Down
32 changes: 32 additions & 0 deletions windows/src/island/island.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export class Island {
/** Last shape handed to Rust for the click-through test. */
private pushedRect = { x: -1, y: -1, w: -1, h: -1 };
private homeCollapseAt: number | null = null;
private clock!: HTMLElement;
private clockTimer: number | null = null;

// Bot hover → love (IslandWindowController.botHoverIn)
private botHovering = false;
Expand Down Expand Up @@ -175,6 +177,7 @@ export class Island {
this.greetingCanvas = h("canvas", { id: "greeting-canvas" });
this.miniGrid = h("div", { id: "mini-grid" });
this.countdown = h("div", { id: "countdown" });
this.clock = h("div", { id: "clock" });

this.header = buildHeader(actions);
this.views = buildViews(actions, () => this.animateGeometry(false));
Expand Down Expand Up @@ -209,6 +212,7 @@ export class Island {
this.botCanvas,
this.miniGrid,
this.countdown,
this.clock,
);

const dpr = Math.min(2, window.devicePixelRatio || 1);
Expand Down Expand Up @@ -861,6 +865,8 @@ export class Island {
}

// Compact mini grid
this.syncClock();

const showGrid = State.mode === "compact";
this.miniGrid.style.opacity = showGrid ? "1" : "0";
if (showGrid) {
Expand All @@ -880,11 +886,37 @@ export class Island {
this.engine.setState(State.effectiveState);
}

/** Time and date in the compact island, refreshed only while it is shown. */
private syncClock() {
const on = State.settings.showClock && State.mode === "compact";
this.clock.style.opacity = on ? "1" : "0";
if (on && this.clockTimer == null) {
const tick = () => {
const now = new Date();
const time = now.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" });
const date = now.toLocaleDateString(undefined, { weekday: "short", day: "numeric" });
this.clock.textContent = `${time} · ${date}`;
};
tick();
// Re-arm on the minute boundary, then every minute: cheap and never late.
const toNextMinute = 60_000 - (Date.now() % 60_000) + 50;
this.clockTimer = window.setTimeout(() => {
tick();
this.clockTimer = window.setInterval(tick, 60_000);
}, toNextMinute);
} else if (!on && this.clockTimer != null) {
window.clearTimeout(this.clockTimer);
window.clearInterval(this.clockTimer);
this.clockTimer = null;
}
}

/** Applies settings coming from Rust at boot. */
applySettings() {
Sound.setEnabled(State.settings.soundEnabled);
Sound.setVolume(State.settings.soundVolume);
this.fsm.homeToPetitDelay = State.settings.autoCloseInterval;
this.fsm.setKeepPetit(State.settings.showClock, this.wasInIsland);
State.notify();
}

Expand Down
5 changes: 5 additions & 0 deletions windows/src/settings/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ function generalSection(): HTMLElement {
autoClose,
h("span", { class: "hint", text: "seconds after you leave the island" }),
),
h("div", { class: "row" },
h("label", { text: "Clock" }),
toggle(settings.showClock, (v) => { settings.showClock = v; void save(); }),
h("span", { class: "hint", text: "time and date in the island while it rests" }),
),
h("div", { class: "row" },
h("label", { text: "Island lives on" }),
screen,
Expand Down
20 changes: 20 additions & 0 deletions windows/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ body {
transition: opacity 0.4s ease-in-out, background 0.4s ease-in-out;
}

/* Clock in the compact island (Settings → Clock). */
#clock {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
font: 600 12.5px var(--font);
letter-spacing: 0.2px;
font-variant-numeric: tabular-nums;
color: var(--ink);
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.25s ease-in-out;
}

#countdown {
position: absolute;
bottom: 0;
Expand Down