1import { createSignal, onMount, Show } from "solid-js";2import type { VaultEntry } from "../../shared/types";3import { sendMessage } from "../../shared/bridge";4import { NotesTOC } from "./NotesTOC";5import { NotesEditor } from "./NotesEditor";67interface NotesModeProps {8 onBack: () => void;9 onNoteListChanged: () => void;10 initialNoteId?: string;11 notes: VaultEntry[];12}1314type Phase = "toc" | "editor" | "collapsing";1516const FADE_MS = 200;1718export function NotesMode(props: NotesModeProps) {19 const [phase, setPhase] = createSignal<Phase>("toc");20 const [activeNote, setActiveNote] = createSignal<VaultEntry | null>(null);21 const [isNewNote, setIsNewNote] = createSignal(false);2223 onMount(() => {24 if (props.initialNoteId) {25 const note = props.notes.find((n) => n.id === props.initialNoteId);26 if (note) {27 setActiveNote(note);28 setPhase("editor");29 }30 }31 });3233 function vibrate(ms: number) {34 try { navigator.vibrate?.(ms); } catch { }35 }3637 function handleNoteRowTap(note: VaultEntry, _rowEl: HTMLElement) {38 if (phase() !== "toc") return;39 vibrate(12);40 setActiveNote(note);41 setIsNewNote(false);42 requestAnimationFrame(() => setPhase("editor"));43 }4445 function handleNewNote() {46 if (phase() !== "toc") return;47 vibrate(12);48 setActiveNote(null);49 setIsNewNote(true);50 requestAnimationFrame(() => setPhase("editor"));51 }5253 function handleEditorBack() {54 if (phase() !== "editor") return;55 vibrate(12);56 setPhase("collapsing");57 setTimeout(() => {58 setActiveNote(null);59 setIsNewNote(false);60 setPhase("toc");61 }, FADE_MS);62 }6364 function handleSaved(note: VaultEntry) {65 if (!activeNote() || activeNote()!.id !== note.id) {66 setActiveNote(note);67 }68 props.onNoteListChanged();69 }7071 function handleDeleteNote(note: VaultEntry) {72 void sendMessage({ type: "DELETE_NOTE", payload: { id: note.id } });73 props.onNoteListChanged();74 handleEditorBack();75 }7677 return (78 <div class="peach-notes-mode" data-phase={phase()}>79 {}80 <div81 class="peach-notes-toc-wrapper"82 classList={{ "is-hidden": phase() === "editor" }}83 aria-hidden={phase() !== "toc"}84 >85 <NotesTOC86 notes={props.notes}87 onBack={props.onBack}88 onOpenNote={handleNoteRowTap}89 onNewNote={handleNewNote}90 onRefresh={props.onNoteListChanged}91 />92 </div>9394 {}95 <Show when={activeNote() !== null || isNewNote()}>96 <div97 class="peach-notes-editor-wrapper"98 classList={{ "is-visible": phase() === "editor" }}99 >100 <NotesEditor101 note={activeNote()}102 onBack={handleEditorBack}103 onSaved={handleSaved}104 onDelete={handleDeleteNote}105 autoFocusTitle={isNewNote()}106 />107 </div>108 </Show>109 </div>110 );111}