diff --git a/apps/server/src/services/llm/skills/frontend_scripting.md b/apps/server/src/services/llm/skills/frontend_scripting.md index 2d17e04e56..826f98dad9 100644 --- a/apps/server/src/services/llm/skills/frontend_scripting.md +++ b/apps/server/src/services/llm/skills/frontend_scripting.md @@ -2,151 +2,25 @@ Frontend scripts run in the browser. They can manipulate the UI, navigate notes, show dialogs, and create custom widgets. +IMPORTANT: Always prefer Preact JSX widgets over legacy jQuery widgets. Use JSX code notes with `import`/`export` syntax. + ## Creating a frontend script -1. Create a Code note with language "JS frontend" (or "JSX" for Preact widgets). -2. Run manually (Execute button) or set `#run=frontendStartup` to auto-run on startup. +1. Create a Code note with language "JSX" (preferred) or "JS frontend" (legacy only). +2. Add `#widget` label for widgets, or `#run=frontendStartup` for auto-run scripts. 3. For mobile, use `#run=mobileStartup` instead. ## Script types -| Type | Description | Required attribute | +| Type | Language | Required attribute | |---|---|---| -| Regular script | Runs with current app/note context | `#run=frontendStartup` (optional) | -| Custom widget | UI element in various positions | `#widget` | -| Launch bar widget | Button in the launch bar | `#widget` | -| Render note | Custom content inside a note | None (used via render relation) | +| Custom widget | JSX (preferred) | `#widget` | +| Regular script | JS frontend | `#run=frontendStartup` (optional) | +| Render note | JSX | None (used via `~renderNote` relation) | -## Script API (`api` global) +## Custom widgets (Preact JSX) — preferred -### Navigation & tabs -- `api.activateNote(notePath)` - navigate to a note -- `api.activateNewNote(notePath)` - navigate and wait for sync -- `api.openTabWithNote(notePath, activate?)` - open in new tab -- `api.openSplitWithNote(notePath, activate?)` - open in new split -- `api.getActiveContextNote()` - get currently active note -- `api.getActiveContextNotePath()` - get path of active note -- `api.setHoistedNoteId(noteId)` - hoist/unhoist note in current tab - -### Note access & search -- `api.getNote(noteId)` - get note by ID -- `api.getNotes(noteIds)` - bulk fetch notes -- `api.searchForNotes(searchString)` - search with full query syntax -- `api.searchForNote(searchString)` - search returning first result -- `api.reloadNotes(noteIds)` - refresh cache from backend - -### Calendar/date notes -- `api.getTodayNote()` - get/create today's note -- `api.getDayNote(date)` - get/create day note for date -- `api.getWeekNote(date)` / `api.getMonthNote(month)` / `api.getYearNote(year)` - -### Editor access -- `api.getActiveContextTextEditor()` - get CKEditor instance -- `api.getActiveContextCodeEditor()` - get CodeMirror instance -- `api.addTextToActiveContextEditor(text)` - insert text into active editor - -### Dialogs & notifications -- `api.showMessage(msg)` - show info toast -- `api.showError(msg)` - show error toast -- `api.showInfoDialog(msg)` - show info dialog -- `api.showConfirmDialog(msg)` - show confirm dialog (returns boolean) -- `api.showPromptDialog(msg)` - show prompt dialog (returns user input) - -### Links -- `api.createLink(notePath, { title?, showTooltip?, showNoteIcon? })` - create jQuery link element - -### Backend integration -- `api.runOnBackend(func, params)` - execute a function on the backend (sync) - -### Protection -- `api.protectNote(noteId, protect)` - protect/unprotect note -- `api.protectSubTree(noteId, protect)` - protect/unprotect subtree - -### UI interaction -- `api.triggerCommand(name, data)` - trigger a command -- `api.triggerEvent(name, data)` - trigger an event -- `api.bindGlobalShortcut(shortcut, handler, namespace?)` - add keyboard shortcut - -### Utilities -- `api.formatDateISO(date)` - format as YYYY-MM-DD -- `api.randomString(length)` - generate random string -- `api.dayjs` - day.js library -- `api.log(message)` - log to script log pane - -### Widget base classes -- `api.BasicWidget` - base widget class -- `api.NoteContextAwareWidget` - widget aware of note context changes -- `api.RightPanelWidget` - right sidebar widget - -## FNote object - -Available via `api.getNote()`, `api.getActiveContextNote()`, etc. - -### Properties -- `note.noteId`, `note.title`, `note.type`, `note.mime` -- `note.isProtected`, `note.isArchived` - -### Content -- `note.getContent()` - get note content -- `note.getJsonContent()` - parse content as JSON - -### Hierarchy -- `note.getParentNotes()` / `note.getChildNotes()` -- `note.hasChildren()`, `note.getSubtreeNoteIds()` - -### Attributes -- `note.getAttributes(type?, name?)` - get all attributes (including inherited) -- `note.getOwnedAttributes(type?, name?)` - get only owned attributes -- `note.hasAttribute(type, name)` - check for attribute - -## Custom widgets (legacy jQuery) - -```javascript -class MyWidget extends api.BasicWidget { - get position() { return 1; } - get parentWidget() { return "center-pane"; } - - doRender() { - this.$widget = $("
The time is: {time}
+This appears inside the note.
+ > + ); +} +``` + +## Script API + +In JSX, use `import { method } from "trilium:api"`. In JS frontend, use the `api` global. + +### Navigation & tabs +- `activateNote(notePath)` - navigate to a note +- `activateNewNote(notePath)` - navigate and wait for sync +- `openTabWithNote(notePath, activate?)` - open in new tab +- `openSplitWithNote(notePath, activate?)` - open in new split +- `getActiveContextNote()` - get currently active note +- `getActiveContextNotePath()` - get path of active note +- `setHoistedNoteId(noteId)` - hoist/unhoist note + +### Note access & search +- `getNote(noteId)` - get note by ID +- `getNotes(noteIds)` - bulk fetch notes +- `searchForNotes(searchString)` - search with full query syntax +- `searchForNote(searchString)` - search returning first result + +### Calendar/date notes +- `getTodayNote()` - get/create today's note +- `getDayNote(date)` / `getWeekNote(date)` / `getMonthNote(month)` / `getYearNote(year)` + +### Editor access +- `getActiveContextTextEditor()` - get CKEditor instance +- `getActiveContextCodeEditor()` - get CodeMirror instance +- `addTextToActiveContextEditor(text)` - insert text into active editor + +### Dialogs & notifications +- `showMessage(msg)` - info toast +- `showError(msg)` - error toast +- `showConfirmDialog(msg)` - confirm dialog (returns boolean) +- `showPromptDialog(msg)` - prompt dialog (returns user input) + +### Backend integration +- `runOnBackend(func, params)` - execute a function on the backend + +### UI interaction +- `triggerCommand(name, data)` - trigger a command +- `bindGlobalShortcut(shortcut, handler, namespace?)` - add keyboard shortcut + +### Utilities +- `formatDateISO(date)` - format as YYYY-MM-DD +- `randomString(length)` - generate random string +- `dayjs` - day.js library +- `log(message)` - log to script log pane + +## FNote object + +Available via `getNote()`, `getActiveContextNote()`, `useNoteContext()`, etc. + +### Properties +- `note.noteId`, `note.title`, `note.type`, `note.mime` +- `note.isProtected`, `note.isArchived` + +### Content +- `note.getContent()` - get note content +- `note.getJsonContent()` - parse content as JSON + +### Hierarchy +- `note.getParentNotes()` / `note.getChildNotes()` +- `note.hasChildren()`, `note.getSubtreeNoteIds()` + +### Attributes +- `note.getAttributes(type?, name?)` - all attributes (including inherited) +- `note.getOwnedAttributes(type?, name?)` - only owned attributes +- `note.hasAttribute(type, name)` - check for attribute + +## Legacy jQuery widgets (avoid if possible) + +Only use legacy widgets if you specifically need jQuery or cannot use JSX. + +```javascript +// Language: JS frontend, Label: #widget +class MyWidget extends api.BasicWidget { + get position() { return 1; } + get parentWidget() { return "center-pane"; } + + doRender() { + this.$widget = $("