diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8f87f6a166..fad12709d3 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -338,6 +338,16 @@ Trilium provides powerful user scripting capabilities: - **Server-side**: `import { t } from "i18next"` with keys in `apps/server/src/assets/translations/en/server.json` - **Interpolation**: Use `{{variable}}` for normal interpolation; use `{{- variable}}` (with hyphen) for **unescaped** interpolation when the value contains special characters like quotes that shouldn't be HTML-escaped +### Storing User Preferences +- **Do not use `localStorage`** for user preferences — Trilium has a synced options system that persists across devices +- To add a new user preference: + 1. Add the option type to `OptionDefinitions` in `packages/commons/src/lib/options_interface.ts` + 2. Add a default value in `apps/server/src/services/options_init.ts` in the `defaultOptions` array + 3. **Whitelist the option** in `apps/server/src/routes/api/options.ts` by adding it to `ALLOWED_OPTIONS` (required for client updates) + 4. Use `useTriliumOption("optionName")` hook in React components to read/write the option +- Available hooks: `useTriliumOption` (string), `useTriliumOptionBool`, `useTriliumOptionInt`, `useTriliumOptionJson` +- See `docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md` for detailed documentation + ## Testing Conventions - **Write concise tests**: Group related assertions together in a single test case rather than creating many one-shot tests diff --git a/CLAUDE.md b/CLAUDE.md index ab6067e058..1b90b02881 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -157,6 +157,16 @@ Trilium provides powerful user scripting capabilities: - **Do not use `crypto.randomUUID()`** or other Web Crypto APIs that require secure contexts - Trilium can run over HTTP, not just HTTPS - Use `randomString()` from `apps/client/src/services/utils.ts` for generating IDs instead +### Storing User Preferences +- **Do not use `localStorage`** for user preferences — Trilium has a synced options system that persists across devices +- To add a new user preference: + 1. Add the option type to `OptionDefinitions` in `packages/commons/src/lib/options_interface.ts` + 2. Add a default value in `apps/server/src/services/options_init.ts` in the `defaultOptions` array + 3. **Whitelist the option** in `apps/server/src/routes/api/options.ts` by adding it to `ALLOWED_OPTIONS` (required for client updates) + 4. Use `useTriliumOption("optionName")` hook in React components to read/write the option +- Available hooks: `useTriliumOption` (string), `useTriliumOptionBool`, `useTriliumOptionInt`, `useTriliumOptionJson` +- See `docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md` for detailed documentation + ### Shared Types Policy - Types shared between client and server belong in `@triliumnext/commons` (`packages/commons/src/lib/`) - Import shared types directly from `@triliumnext/commons` - do not re-export them from app-specific modules diff --git a/apps/client/src/widgets/dialogs/include_note.tsx b/apps/client/src/widgets/dialogs/include_note.tsx index c8f818302d..74d41da6be 100644 --- a/apps/client/src/widgets/dialogs/include_note.tsx +++ b/apps/client/src/widgets/dialogs/include_note.tsx @@ -8,7 +8,7 @@ import Button from "../react/Button"; import { Suggestion, triggerRecentNotes } from "../../services/note_autocomplete"; import tree from "../../services/tree"; import froca from "../../services/froca"; -import { useTriliumEvent } from "../react/hooks"; +import { useTriliumEvent, useTriliumOption } from "../react/hooks"; import { type BoxSize, CKEditorApi } from "../type_widgets/text/CKEditorWithWatchdog"; export interface IncludeNoteOpts { @@ -18,11 +18,13 @@ export interface IncludeNoteOpts { export default function IncludeNoteDialog() { const editorApiRef = useRef(null); const [suggestion, setSuggestion] = useState(null); - const [boxSize, setBoxSize] = useState("medium"); + const [defaultBoxSize, setDefaultBoxSize] = useTriliumOption("includeNoteDefaultBoxSize"); + const [boxSize, setBoxSize] = useState(defaultBoxSize); const [shown, setShown] = useState(false); useTriliumEvent("showIncludeNoteDialog", ({ editorApi }) => { editorApiRef.current = editorApi; + setBoxSize(defaultBoxSize); // Reset to default when opening dialog setShown(true); }); @@ -35,10 +37,14 @@ export default function IncludeNoteDialog() { size="lg" onShown={() => triggerRecentNotes(autoCompleteRef.current)} onHidden={() => setShown(false)} - onSubmit={() => { + onSubmit={async () => { if (!suggestion?.notePath || !editorApiRef.current) return; setShown(false); - includeNote(suggestion.notePath, editorApiRef.current, boxSize as BoxSize); + await includeNote(suggestion.notePath, editorApiRef.current, boxSize as BoxSize); + // Save the selected box size as the new default + if (boxSize !== defaultBoxSize) { + setDefaultBoxSize(boxSize); + } }} footer={