{ANIMATIONS.map(({ type, title }) => {
const isSelected = selectedAnimation === type;
return (
diff --git a/src/components/focus/FocusTimer.tsx b/src/components/focus/FocusTimer.tsx
index bbae7ba..a21753f 100644
--- a/src/components/focus/FocusTimer.tsx
+++ b/src/components/focus/FocusTimer.tsx
@@ -192,6 +192,11 @@ export const FocusTimer = forwardRef(function
localStorage.setItem(SELECTED_ANIMATION_KEY, type);
};
+ const selectNextAnimation = () => {
+ const index = ANIMATIONS.findIndex((animation) => animation.type === selectedAnimation);
+ selectAnimation(ANIMATIONS[(index + 1) % ANIMATIONS.length].type);
+ };
+
const rerollAnimation = () => {
if (autoShuffle) setSelectedAnimation(randomAnimationOtherThan(selectedAnimation));
};
@@ -533,9 +538,16 @@ export const FocusTimer = forwardRef(function
useHotkey("timer.end", endCurrent, isActive);
useHotkey("timer.switch", switchMode, isActive);
useHotkey("timer.animation", () => setShowPicker((visible) => !visible), isActive && isIdle);
+ useHotkey("timer.shuffle", toggleAutoShuffle, isActive && isIdle);
+ useHotkey("timer.nextAnimation", selectNextAnimation, isActive && isIdle);
+ const isSessionComplete = !isIdle && !isOnBreak && focus.isCompleted;
+ useHotkey("timer.reset", resetTimer, isActive && !isIdle && !isDirectBreak && !isOnBreak);
+ useHotkey("timer.extend", () => void extendFocus(), isActive && isSessionComplete);
const toggleCombo = useHotkeyLabel("timer.toggle");
const endCombo = useHotkeyLabel("timer.end");
const switchCombo = useHotkeyLabel("timer.switch");
+ const resetCombo = useHotkeyLabel("timer.reset");
+ const extendCombo = useHotkeyLabel("timer.extend");
const inputForPhase = isOnBreak ? breakMinutes : inputMinutes;
const frameState: FrameState = {
isOnBreak,
@@ -631,7 +643,7 @@ export const FocusTimer = forwardRef(function
/>
- {focus.isCompleted && !isOnBreak ? (
+ {isSessionComplete ? (
@@ -654,6 +666,7 @@ export const FocusTimer = forwardRef
(function
min
diff --git a/src/components/hotkeys/bindings.ts b/src/components/hotkeys/bindings.ts
index 8eb5f7e..14e0177 100644
--- a/src/components/hotkeys/bindings.ts
+++ b/src/components/hotkeys/bindings.ts
@@ -19,6 +19,7 @@ export const HOTKEY_ACTIONS: readonly HotkeyAction[] = [
{ id: "nav.aboutme", group: "Navigate", label: "About Me", defaultCombo: "Alt+P" },
{ id: "nav.tags", group: "Navigate", label: "Tags", defaultCombo: "Alt+T" },
{ id: "nav.menu", group: "Navigate", label: "Open / close menu", defaultCombo: "Alt+M" },
+ { id: "page.back", group: "Navigate", label: "Back", defaultCombo: "Alt+Shift+B" },
{ id: "timer.toggle", group: "Focus timer", label: "Start / pause / resume", defaultCombo: "Alt+S" },
{ id: "timer.switch", group: "Focus timer", label: "Switch focus / break", defaultCombo: "Alt+B" },
@@ -26,12 +27,27 @@ export const HOTKEY_ACTIONS: readonly HotkeyAction[] = [
{ id: "timer.goal", group: "Focus timer", label: "Edit focus goal", defaultCombo: "Alt+G" },
{ id: "timer.animation", group: "Focus timer", label: "Choose animation", defaultCombo: "Alt+A" },
{ id: "timer.addTag", group: "Focus timer", label: "Add tag", defaultCombo: "Alt+Shift+T" },
+ { id: "timer.reset", group: "Focus timer", label: "Reset session", defaultCombo: "Alt+R" },
+ { id: "timer.extend", group: "Focus timer", label: "Extend finished session", defaultCombo: "Alt+Shift+E" },
+ { id: "timer.minutes", group: "Focus timer", label: "Edit minutes", defaultCombo: "Alt+I" },
+ { id: "timer.shuffle", group: "Focus timer", label: "Auto-shuffle animations on/off", defaultCombo: "Alt+Shift+A" },
+ { id: "timer.nextAnimation", group: "Focus timer", label: "Next animation", defaultCombo: "Alt+Shift+C" },
{ id: "list.new", group: "Lists", label: "New item on current page", defaultCombo: "Alt+N" },
{ id: "boost.post", group: "Lists", label: "Post to Boost", defaultCombo: "Ctrl+Enter" },
{ id: "boost.attach", group: "Lists", label: "Attach media to post", defaultCombo: "Alt+U" },
+ { id: "boost.visibility", group: "Lists", label: "Public / private post", defaultCombo: "Alt+Shift+V" },
+ { id: "list.archived", group: "Lists", label: "Show / hide archived", defaultCombo: "Alt+Shift+H" },
+ { id: "list.backlog", group: "Lists", label: "Show / hide backlog", defaultCombo: "Alt+Shift+K" },
+ { id: "list.range", group: "Lists", label: "Switch 7 / 30 days", defaultCombo: "Alt+Shift+D" },
+ { id: "list.prev", group: "Lists", label: "Previous period", defaultCombo: "Alt+Shift+Left" },
+ { id: "list.next", group: "Lists", label: "Next period", defaultCombo: "Alt+Shift+Right" },
+ { id: "history.period", group: "Lists", label: "Next chart range", defaultCombo: "Alt+Shift+P" },
{ id: "app.displayName", group: "App", label: "Edit display name", defaultCombo: "Alt+Shift+N" },
+ { id: "page.save", group: "App", label: "Save page", defaultCombo: "Ctrl+S" },
+ { id: "app.sounds", group: "App", label: "Sounds", defaultCombo: "Alt+Shift+S" },
+ { id: "app.notifications", group: "App", label: "Notifications", defaultCombo: "Alt+Shift+O" },
{ id: "app.fullPage", group: "App", label: "Open full page (extension popup)", defaultCombo: "Alt+Enter" },
{ id: "app.shortcuts", group: "App", label: "Show or hide this list", defaultCombo: "Ctrl+/" },
];
diff --git a/src/components/pages/AboutMePage.tsx b/src/components/pages/AboutMePage.tsx
index 47270ee..2e94101 100644
--- a/src/components/pages/AboutMePage.tsx
+++ b/src/components/pages/AboutMePage.tsx
@@ -1,6 +1,8 @@
"use client";
import { useEffect, useState } from "react";
+import { hotkeyHint } from "../focus/GoalForm";
+import { useHotkey, useHotkeyLabel } from "../hotkeys/HotkeysProvider";
import { Save } from "../icons";
import { localDb, type Row } from "../lib/local-db";
@@ -77,6 +79,12 @@ export function AboutMePage({ userId }: { userId: string }) {
setSaving(false);
};
+ // Always claimed on this page so Ctrl+S never opens the browser's "Save page" dialog here.
+ useHotkey("page.save", () => {
+ if (dirty && !saving) void save();
+ });
+ const saveCombo = useHotkeyLabel("page.save");
+
// Cmd/Ctrl+Enter saves from anywhere on the page.
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
@@ -142,6 +150,7 @@ export function AboutMePage({ userId }: { userId: string }) {