Compare commits

...

64 Commits

Author SHA1 Message Date
Elian Doran
e6d728715f feat(geomap): support hiding labels 2026-02-12 19:47:24 +02:00
Elian Doran
54a52f0589 feat(geomap): support for custom tile URLs 2026-02-12 19:32:22 +02:00
Elian Doran
badfa23f86 refactor(geomap): delegate layer data handling to index 2026-02-12 19:12:56 +02:00
Elian Doran
b83eee9bdc Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-02-11 20:21:55 +02:00
Elian Doran
e41b2e8d31 fix(options/shortcuts): filter text box forces lower case 2026-02-11 20:21:52 +02:00
Elian Doran
d93cec2bfd feat(options/shortcuts): add no results 2026-02-11 20:19:53 +02:00
Elian Doran
9eb87a39cd chore(options/shortcuts): refactor filtering 2026-02-11 20:15:39 +02:00
Elian Doran
07818ec1df fix(options): unnecessary full-height 2026-02-11 20:11:46 +02:00
Elian Doran
d4052dbe37 feat(options/shortcuts): equal height 2026-02-11 20:04:09 +02:00
Elian Doran
656f5e0a7f feat(options/shortcuts): make header and footer sticky (closes #8675) 2026-02-11 20:02:37 +02:00
Elian Doran
0cc5e4dac3 chore(deps): update dependency @ckeditor/ckeditor5-dev-build-tools to v54.3.3 (#8609) 2026-02-11 07:51:46 +02:00
Elian Doran
8bbfff3cb2 fix(deps): update dependency i18next to v25.8.4 (#8611) 2026-02-11 07:51:31 +02:00
Elian Doran
33fae88cad chore(deps): update dependency stylelint to v17.2.0 (#8612) 2026-02-11 07:51:15 +02:00
Elian Doran
4feb23e9ca fix(deps): update dependency @preact/signals to v2.7.1 (#8619) 2026-02-11 07:50:04 +02:00
Elian Doran
c2b6b7ba72 chore(deps): update dependency esbuild to v0.27.3 (#8631) 2026-02-11 07:48:22 +02:00
Elian Doran
fb76aee258 chore(deps): update dependency @anthropic-ai/sdk to v0.74.0 (#8633) 2026-02-11 07:47:46 +02:00
Elian Doran
320b1829cc chore(deps): update dependency openai to v6.21.0 (#8634) 2026-02-11 07:47:16 +02:00
Elian Doran
601f0255a4 chore(deps): update dependency @playwright/test to v1.58.2 (#8642) 2026-02-11 07:46:46 +02:00
Elian Doran
b6cc2b227a chore(deps): update dependency wxt to v0.20.14 (#8643) 2026-02-11 07:46:36 +02:00
Elian Doran
1ae3be2fda fix(deps): update codemirror (#8644) 2026-02-11 07:44:55 +02:00
Elian Doran
5b4d35ea86 chore(deps): update dependency @redocly/cli to v2.17.0 (#8645) 2026-02-11 07:44:38 +02:00
Elian Doran
00735e6c8e chore(deps): update dependency axios to v1.13.5 (#8661) 2026-02-11 07:44:27 +02:00
Elian Doran
66a42a38c9 chore(deps): update dependency @smithy/middleware-retry to v4.4.31 (#8669) 2026-02-11 07:43:54 +02:00
Elian Doran
05af1fba80 chore(deps): update dependency rollup-plugin-webpack-stats to v2.1.11 (#8670) 2026-02-11 07:43:45 +02:00
Elian Doran
3b2dd0f5e9 chore(deps): update pnpm to v10.29.2 (#8671) 2026-02-11 07:43:33 +02:00
Elian Doran
1493a66a36 chore(deps): update dependency webdriverio to v9.24.0 (#8672) 2026-02-11 07:43:15 +02:00
Elian Doran
b4bf103fd8 chore(deps): update typescript-eslint monorepo to v8.55.0 (#8673) 2026-02-11 07:43:00 +02:00
renovate[bot]
94286becfd chore(deps): update typescript-eslint monorepo to v8.55.0 2026-02-11 01:04:05 +00:00
renovate[bot]
a68aade58c chore(deps): update dependency webdriverio to v9.24.0 2026-02-11 01:03:25 +00:00
renovate[bot]
014201edf4 chore(deps): update pnpm to v10.29.2 2026-02-11 01:02:09 +00:00
renovate[bot]
8ae6297148 chore(deps): update dependency rollup-plugin-webpack-stats to v2.1.11 2026-02-11 01:01:56 +00:00
renovate[bot]
5e0300aa8e chore(deps): update dependency @smithy/middleware-retry to v4.4.31 2026-02-11 01:01:18 +00:00
renovate[bot]
80a7e18413 chore(deps): update dependency openai to v6.21.0 2026-02-10 21:08:56 +00:00
Elian Doran
43be0a1a3f chore(desktop): disable dev tools for the print window 2026-02-10 17:29:00 +02:00
Elian Doran
5eb32744c3 feat(desktop): display print errors 2026-02-10 17:26:58 +02:00
Elian Doran
89d39f5f2b feat(desktop): add logs when printing 2026-02-10 17:12:28 +02:00
Elian Doran
1f4900dd1e fix(desktop): print failing on upgrade due to cache issues 2026-02-10 16:30:16 +02:00
renovate[bot]
1c561c1483 chore(deps): update dependency stylelint to v17.2.0 2026-02-10 11:44:18 +00:00
Adorian Doran
6baaf60b67 style/web view setup: update icon 2026-02-10 02:53:46 +02:00
Adorian Doran
dde73f6c2b style/attachments: tweak 2026-02-10 02:46:10 +02:00
Adorian Doran
f445a49b34 client/notes/web view: create a web view setup form 2026-02-10 02:45:43 +02:00
Adorian Doran
29016d1cf5 style/refactor: promote centered form as global style 2026-02-10 01:26:07 +02:00
Adorian Doran
c06435046b style/alert bars: use a global style, tweak spacing 2026-02-09 23:39:22 +02:00
Adorian Doran
134422802f style/protected session password request: improve layout and appearance 2026-02-09 23:14:32 +02:00
Adorian Doran
5e00d6a305 style/collapsible: use low profile style for the expand/collapse button 2026-02-09 20:34:58 +02:00
Adorian Doran
b5f0137d8e Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-02-09 20:33:32 +02:00
Adorian Doran
081d041cbc style/buttons: define a style for low profile buttons 2026-02-09 20:33:24 +02:00
Elian Doran
95e733a67c Merge branch 'main' of https://github.com/TriliumNext/Trilium 2026-02-09 20:22:43 +02:00
Elian Doran
a664057312 fix(website): missing RPM GPG key (closes #8618) 2026-02-09 20:22:41 +02:00
Elian Doran
5b1a2d93bf fix(tree): child note badge overlapping text (closes #8567) 2026-02-09 20:20:20 +02:00
Adorian Doran
0323f95828 style/status bar: do not wrap the action buttons text 2026-02-09 19:57:13 +02:00
Elian Doran
375838449f fix(geomap): z-index issues with toolbar and buttons (closes #8649) 2026-02-09 19:55:57 +02:00
Adorian Doran
4562de8c2c close #2137 2026-02-09 19:19:41 +02:00
Adorian Doran
68d21669e7 style/similar notes: fix font size variation according to similarity 2026-02-09 19:12:47 +02:00
renovate[bot]
625e0cf159 chore(deps): update dependency @redocly/cli to v2.17.0 2026-02-09 13:58:05 +00:00
renovate[bot]
551ef00c61 fix(deps): update dependency @preact/signals to v2.7.1 2026-02-09 10:46:41 +00:00
renovate[bot]
10518f6364 chore(deps): update dependency axios to v1.13.5 2026-02-09 00:39:09 +00:00
renovate[bot]
3c33b5b169 fix(deps): update codemirror 2026-02-08 13:39:10 +00:00
renovate[bot]
000c31b66c chore(deps): update dependency @anthropic-ai/sdk to v0.74.0 2026-02-07 20:46:58 +00:00
renovate[bot]
fd7780abb0 chore(deps): update dependency esbuild to v0.27.3 2026-02-07 11:53:22 +00:00
renovate[bot]
c8a981e8d6 chore(deps): update dependency wxt to v0.20.14 2026-02-07 00:33:00 +00:00
renovate[bot]
faac45784c chore(deps): update dependency @playwright/test to v1.58.2 2026-02-07 00:32:04 +00:00
renovate[bot]
f6b454cb9a fix(deps): update dependency i18next to v25.8.4 2026-02-05 13:44:21 +00:00
renovate[bot]
563463782c Update dependency @ckeditor/ckeditor5-dev-build-tools to v54.3.3 2026-02-04 01:51:41 +00:00
47 changed files with 1603 additions and 929 deletions

View File

@@ -9,9 +9,9 @@
"keywords": [],
"author": "Elian Doran <contact@eliandoran.me>",
"license": "AGPL-3.0-only",
"packageManager": "pnpm@10.29.1",
"packageManager": "pnpm@10.29.2",
"devDependencies": {
"@redocly/cli": "2.15.1",
"@redocly/cli": "2.17.0",
"archiver": "7.0.1",
"fs-extra": "11.3.3",
"react": "19.2.4",

View File

@@ -27,7 +27,7 @@
"@mermaid-js/layout-elk": "0.2.0",
"@mind-elixir/node-menu": "5.0.1",
"@popperjs/core": "2.11.8",
"@preact/signals": "2.6.2",
"@preact/signals": "2.7.1",
"@triliumnext/ckeditor5": "workspace:*",
"@triliumnext/codemirror": "workspace:*",
"@triliumnext/commons": "workspace:*",
@@ -44,7 +44,7 @@
"draggabilly": "3.0.0",
"force-graph": "1.51.1",
"globals": "17.3.0",
"i18next": "25.8.0",
"i18next": "25.8.4",
"i18next-http-backend": "3.0.2",
"jquery": "4.0.0",
"jquery.fancytree": "2.38.5",

View File

@@ -18,6 +18,10 @@ export type PrintReport = {
} | {
type: "collection";
ignoredNoteIds: string[];
} | {
type: "error";
message: string;
stack?: string;
};
async function main() {

View File

@@ -800,3 +800,18 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
background: var(--hover-item-background-color);
color: var(--hover-item-text-color);
}
/*
* Alert bars
*/
div.alert {
margin-bottom: 8px;
background: var(--alert-bar-background) !important;
border-radius: 8px;
font-size: .85em;
}
div.alert p + p {
margin-block: 1em 0;
}

View File

@@ -84,6 +84,22 @@ button.btn.btn-success kbd {
letter-spacing: 0.5pt;
}
/*
* Low profile buttons
*/
button.tn-low-profile {
appearance: none;
background: transparent;
border: 0;
border-radius: 8px;
color: inherit;
}
button.tn-low-profile:hover {
background-color: var(--icon-button-hover-background);
}
/*
* Icon buttons
*/
@@ -794,3 +810,35 @@ input[type="range"] {
scrollbar-width: unset;
}
}
/*
* Centered forms
*/
.tn-centered-form {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20vh;
}
.tn-centered-form .form-group {
text-align: center;
color: var(--muted-text-color);
}
.tn-centered-form .form-icon {
font-size: 140px;
color: var(--main-border-color);
}
.tn-centered-form .protected-session-password {
margin-inline: auto;
max-width: 350px;
text-align: center;
}
.tn-centered-form input,
.tn-centered-form button {
margin-top: 12px;
}

View File

@@ -265,13 +265,6 @@ body.desktop .options-section:not(.tn-no-card) {
margin-bottom: 6px;
}
.options-section .alert {
margin-bottom: 8px;
background: var(--alert-bar-background) !important;
border-radius: 8px;
font-size: .85em;
}
nav.options-section-tabs {
min-width: var(--options-card-min-width);
max-width: var(--options-card-max-width);

View File

@@ -1070,10 +1070,12 @@
"note_detail_render_help_1": "This help note is shown because this note of type Render HTML doesn't have required relation to function properly.",
"note_detail_render_help_2": "Render HTML note type is used for <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/scripts.html\">scripting</a>. In short, you have a HTML code note (optionally with some JavaScript) and this note will render it. To make it work, you need to define a <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/attributes.html\">relation</a> called \"renderNote\" pointing to the HTML note to render."
},
"web_view": {
"web_view": "Web View",
"embed_websites": "Note of type Web View allows you to embed websites into Trilium.",
"create_label": "To start, please create a label with a URL address you want to embed, e.g. #webViewSrc=\"https://www.google.com\""
"web_view_setup": {
"title": "Create a live view of a webpage directly into Trilium",
"url_placeholder": "Enter or paste the website address, for example https://triliumnotes.org",
"create_button": "Create Web View",
"invalid_url_title": "Invalid address",
"invalid_url_message": "Insert a valid web address, for example https://triliumnotes.org."
},
"backend_log": {
"refresh": "Refresh"
@@ -1589,7 +1591,8 @@
"description": "Description",
"reload_app": "Reload app to apply changes",
"set_all_to_default": "Set all shortcuts to the default",
"confirm_reset": "Do you really want to reset all keyboard shortcuts to the default?"
"confirm_reset": "Do you really want to reset all keyboard shortcuts to the default?",
"no_results": "No shortcuts found matching '{{filter}}'"
},
"spellcheck": {
"title": "Spell Check",
@@ -1795,6 +1798,8 @@
"printing": "Printing in progress...",
"printing_pdf": "Exporting to PDF in progress...",
"print_report_title": "Print report",
"print_report_error_title": "Failed to print",
"print_report_stack_trace": "Stack trace",
"print_report_collection_content_one": "{{count}} note in the collection could not be printed because they are not supported or they are protected.",
"print_report_collection_content_other": "{{count}} notes in the collection could not be printed because they are not supported or they are protected.",
"print_report_collection_details_button": "See details",
@@ -2099,7 +2104,8 @@
"raster": "Raster",
"vector_light": "Vector (Light)",
"vector_dark": "Vector (Dark)",
"show-scale": "Show scale"
"show-scale": "Show scale",
"show-labels": "Show marker names"
},
"table_context_menu": {
"delete_row": "Delete row"

View File

@@ -370,7 +370,33 @@ function showToast(type: "printing" | "exporting_pdf", progress: number = 0) {
}
function handlePrintReport(printReport?: PrintReport) {
if (printReport?.type === "collection" && printReport.ignoredNoteIds.length > 0) {
if (!printReport) return;
if (printReport.type === "error") {
toast.showPersistent({
id: "print-error",
icon: "bx bx-error-circle",
title: t("note_detail.print_report_error_title"),
message: printReport.message,
buttons: printReport.stack ? [
{
text: t("note_detail.print_report_collection_details_button"),
onClick(api) {
api.dismissToast();
dialog.info(<>
<p>{printReport.message}</p>
<details>
<summary>{t("note_detail.print_report_stack_trace")}</summary>
<pre style="font-size: 0.85em; overflow-x: auto;">{printReport.stack}</pre>
</details>
</>, {
title: t("note_detail.print_report_error_title")
});
}
}
] : undefined
});
} else if (printReport.type === "collection" && printReport.ignoredNoteIds.length > 0) {
toast.showPersistent({
id: "print-report",
icon: "bx bx-collection",

View File

@@ -7,7 +7,7 @@
> .collection-properties {
position: relative;
z-index: 2000;
z-index: 998;
}
}
@@ -22,7 +22,7 @@
.leaflet-top,
.leaflet-bottom {
z-index: 997;
z-index: 997 !important;
}
.geo-view.placing-note .geo-map-container {

View File

@@ -22,7 +22,7 @@ import { ViewModeProps } from "../interface";
import { createNewNote, moveMarker } from "./api";
import openContextMenu, { openMapContextMenu } from "./context_menu";
import Map from "./map";
import { DEFAULT_MAP_LAYER_NAME } from "./map_layer";
import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS, MapLayer } from "./map_layer";
import Marker, { GpxTrack } from "./marker";
const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659];
@@ -45,10 +45,11 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM
const [ state, setState ] = useState(State.Normal);
const [ coordinates, setCoordinates ] = useState(viewConfig?.view?.center);
const [ zoom, setZoom ] = useState(viewConfig?.view?.zoom);
const [ layerName ] = useNoteLabel(note, "map:style");
const [ hasScale ] = useNoteLabelBoolean(note, "map:scale");
const [ hideLabels ] = useNoteLabelBoolean(note, "map:hideLabels");
const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly");
const [ notes, setNotes ] = useState<FNote[]>([]);
const layerData = useLayerData(note);
const spacedUpdate = useSpacedUpdate(() => {
if (viewConfig) {
saveConfig(viewConfig);
@@ -152,7 +153,7 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM
apiRef={apiRef} containerRef={containerRef}
coordinates={coordinates}
zoom={zoom}
layerName={layerName ?? DEFAULT_MAP_LAYER_NAME}
layerData={layerData}
viewportChanged={(coordinates, zoom) => {
if (!viewConfig) viewConfig = {};
viewConfig.view = { center: coordinates, zoom };
@@ -162,13 +163,35 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM
onContextMenu={onContextMenu}
scale={hasScale}
>
{notes.map(note => <NoteWrapper note={note} isReadOnly={isReadOnly} />)}
{notes.map(note => <NoteWrapper note={note} isReadOnly={isReadOnly} hideLabels={hideLabels} />)}
</Map>}
<GeoMapTouchBar state={state} map={apiRef.current} />
</div>
);
}
function useLayerData(note: FNote) {
const [ layerName ] = useNoteLabel(note, "map:style");
// Memo is needed because it would generate unnecessary reloads due to layer change.
const layerData = useMemo(() => {
// Custom layers.
if (layerName?.startsWith("http")) {
return {
name: "Custom",
type: "raster",
url: layerName,
attribution: ""
} satisfies MapLayer;
}
// Built-in layers.
const layerData = MAP_LAYERS[layerName ?? ""] ?? MAP_LAYERS[DEFAULT_MAP_LAYER_NAME];
return layerData;
}, [ layerName ]);
return layerData;
}
function ToggleReadOnlyButton({ note }: { note: FNote }) {
const [ isReadOnly, setReadOnly ] = useNoteLabelBoolean(note, "readOnly");
@@ -179,22 +202,26 @@ function ToggleReadOnlyButton({ note }: { note: FNote }) {
/>;
}
function NoteWrapper({ note, isReadOnly }: { note: FNote, isReadOnly: boolean }) {
function NoteWrapper({ note, isReadOnly, hideLabels }: {
note: FNote,
isReadOnly: boolean,
hideLabels: boolean
}) {
const mime = useNoteProperty(note, "mime");
const [ location ] = useNoteLabel(note, LOCATION_ATTRIBUTE);
if (mime === "application/gpx+xml") {
return <NoteGpxTrack note={note} />;
return <NoteGpxTrack note={note} hideLabels={hideLabels} />;
}
if (location) {
const latLng = location?.split(",", 2).map((el) => parseFloat(el)) as [ number, number ] | undefined;
if (!latLng) return;
return <NoteMarker note={note} editable={!isReadOnly} latLng={latLng} />;
return <NoteMarker note={note} editable={!isReadOnly} latLng={latLng} hideLabels={hideLabels} />;
}
}
function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean, latLng: [number, number] }) {
function NoteMarker({ note, editable, latLng, hideLabels }: { note: FNote, editable: boolean, latLng: [number, number], hideLabels: boolean }) {
// React to changes
const [ color ] = useNoteLabel(note, "color");
const [ iconClass ] = useNoteLabel(note, "iconClass");
@@ -202,8 +229,9 @@ function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean
const title = useNoteProperty(note, "title");
const icon = useMemo(() => {
return buildIcon(note.getIcon(), note.getColorClass() ?? undefined, title, note.noteId, archived);
}, [ iconClass, color, title, note.noteId, archived]);
const titleOrNone = hideLabels ? undefined : title;
return buildIcon(note.getIcon(), note.getColorClass() ?? undefined, titleOrNone, note.noteId, archived);
}, [ iconClass, color, title, note.noteId, archived, hideLabels ]);
const onClick = useCallback(() => {
appContext.triggerCommand("openInPopup", { noteIdOrPath: note.noteId });
@@ -235,7 +263,7 @@ function NoteMarker({ note, editable, latLng }: { note: FNote, editable: boolean
/>;
}
function NoteGpxTrack({ note }: { note: FNote }) {
function NoteGpxTrack({ note, hideLabels }: { note: FNote, hideLabels?: boolean }) {
const [ xmlString, setXmlString ] = useState<string>();
const blob = useNoteBlob(note);
@@ -256,7 +284,7 @@ function NoteGpxTrack({ note }: { note: FNote }) {
const options = useMemo<GPXOptions>(() => ({
markers: {
startIcon: buildIcon(note.getIcon(), note.getColorClass(), note.title),
startIcon: buildIcon(note.getIcon(), note.getColorClass(), hideLabels ? undefined : note.title),
endIcon: buildIcon("bxs-flag-checkered"),
wptIcons: {
"": buildIcon("bx bx-pin")
@@ -265,7 +293,7 @@ function NoteGpxTrack({ note }: { note: FNote }) {
polyline_options: {
color: note.getLabelValue("color") ?? "blue"
}
}), [ color, iconClass ]);
}), [ color, iconClass, hideLabels ]);
return xmlString && <GpxTrack gpxXmlString={xmlString} options={options} />;
}

View File

@@ -1,7 +1,7 @@
import { useEffect, useImperativeHandle, useRef, useState } from "preact/hooks";
import L, { control, LatLng, Layer, LeafletMouseEvent } from "leaflet";
import "leaflet/dist/leaflet.css";
import { MAP_LAYERS } from "./map_layer";
import { MAP_LAYERS, type MapLayer } from "./map_layer";
import { ComponentChildren, createContext, RefObject } from "preact";
import { useElementSize, useSyncedRef } from "../../react/hooks";
@@ -12,7 +12,7 @@ interface MapProps {
containerRef?: RefObject<HTMLDivElement>;
coordinates: LatLng | [number, number];
zoom: number;
layerName: string;
layerData: MapLayer;
viewportChanged: (coordinates: LatLng, zoom: number) => void;
children: ComponentChildren;
onClick?: (e: LeafletMouseEvent) => void;
@@ -21,7 +21,7 @@ interface MapProps {
scale: boolean;
}
export default function Map({ coordinates, zoom, layerName, viewportChanged, children, onClick, onContextMenu, scale, apiRef, containerRef: _containerRef, onZoom }: MapProps) {
export default function Map({ coordinates, zoom, layerData, viewportChanged, children, onClick, onContextMenu, scale, apiRef, containerRef: _containerRef, onZoom }: MapProps) {
const mapRef = useRef<L.Map>(null);
const containerRef = useSyncedRef<HTMLDivElement>(_containerRef);
@@ -49,8 +49,6 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi
const [ layer, setLayer ] = useState<Layer>();
useEffect(() => {
async function load() {
const layerData = MAP_LAYERS[layerName];
if (layerData.type === "vector") {
const style = (typeof layerData.style === "string" ? layerData.style : await layerData.style());
await import("@maplibre/maplibre-gl-leaflet");
@@ -68,7 +66,7 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi
}
load();
}, [ layerName ]);
}, [ layerData ]);
// Attach layer to the map.
useEffect(() => {
@@ -139,7 +137,7 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi
return (
<div
ref={containerRef}
className={`geo-map-container ${MAP_LAYERS[layerName].isDarkTheme ? "dark" : ""}`}
className={`geo-map-container ${layerData.isDarkTheme ? "dark" : ""}`}
>
<ParentMap.Provider value={mapRef.current}>
{children}

View File

@@ -1,20 +1,17 @@
export interface MapLayer {
name: string;
isDarkTheme?: boolean;
}
interface VectorLayer extends MapLayer {
export type MapLayer = ({
type: "vector";
style: string | (() => Promise<{}>)
}
interface RasterLayer extends MapLayer {
} | {
type: "raster";
url: string;
attribution: string;
}
}) & {
// Common properties
name: string;
isDarkTheme?: boolean;
};
export const MAP_LAYERS: Record<string, VectorLayer | RasterLayer> = {
export const MAP_LAYERS: Record<string, MapLayer> = {
"openstreetmap": {
name: "OpenStreetMap",
type: "raster",

View File

@@ -37,6 +37,10 @@
&:hover {
background: var(--input-background-color);
}
.text {
white-space: nowrap;
}
}
.status-bar-dropdown-button {

View File

@@ -226,8 +226,8 @@ function CheckBoxPropertyView({ note, property }: { note: FNote, property: Check
<FormListToggleableItem
icon={property.icon}
title={property.label}
currentValue={value}
onChange={setValue}
currentValue={ property.reverseValue ? !value : value }
onChange={newValue => setValue(property.reverseValue ? !newValue : newValue)}
/>
);
}

View File

@@ -9,7 +9,6 @@
border-radius: 0.5em;
font-size: 0.7rem;
font-weight: normal;
float: right;
vertical-align: middle;
}

View File

@@ -1992,7 +1992,7 @@ function buildEnhanceTitle() {
if (isSubtreeHidden && count > 0) {
const $badge = $(`<span class="note-indicator-icon subtree-hidden-badge">${count}</span>`);
$badge.attr("title", t("note_tree.subtree-hidden-tooltip", { count }));
$span.find(".fancytree-title").append($badge);
$span.append($badge);
}
};
}

View File

@@ -43,7 +43,8 @@ export const TYPE_MAPPINGS: Record<ExtendedNoteType, NoteTypeMapping> = {
},
protectedSession: {
view: () => import("./type_widgets/ProtectedSession"),
className: "protected-session-password-component"
className: "protected-session-password-component",
isFullHeight: true
},
book: {
view: () => import("./type_widgets/Book"),

View File

@@ -3,10 +3,7 @@
line-height: 1em;
display: flex;
align-items: center;
appearance: none;
background: transparent;
border: 0;
color: inherit;
padding-inline-end: 12px;
.arrow {
font-size: 1.3em;

View File

@@ -57,7 +57,7 @@ export function ExternallyControlledCollapsible({ title, children, className, ex
"with-transition": transitionEnabled
})}>
<button
className="collapsible-title"
className="collapsible-title tn-low-profile"
onClick={() => setExpanded(!expanded)}
aria-expanded={expanded}
aria-controls={contentId}

View File

@@ -0,0 +1,4 @@
.similar-notes-widget > .similar-notes-wrapper {
/* The font size of the links with the highest similarity score */
font-size: 17px;
}

View File

@@ -1,3 +1,5 @@
import "./SimilarNotesTab.css";
import { SimilarNoteResponse } from "@triliumnext/commons";
import { useEffect, useState } from "preact/hooks";
@@ -33,7 +35,7 @@ export default function SimilarNotesTab({ note }: Pick<TabContext, "note">) {
notePath={notePath}
noTnLink
style={{
"font-size": 20 * (1 - 1 / (1 + score))
"font-size": (1 - 1 / (1 + score)) + "em"
}}
/>
))}

View File

@@ -20,6 +20,8 @@ export interface CheckBoxProperty {
label: string;
bindToLabel: FilterLabelsByType<boolean>;
icon?: string;
/** When true, the checkbox will be checked when the label value is false. Useful when the label represents a "hide" action, without exposing double negatives to the user. */
reverseValue?: boolean;
}
export interface ButtonProperty {
@@ -156,6 +158,13 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
icon: "bx bx-ruler",
type: "checkbox",
bindToLabel: "map:scale"
},
{
label: t("book_properties_config.show-labels"),
icon: "bx bx-label",
type: "checkbox",
bindToLabel: "map:hideLabels",
reverseValue: true
}
]
},

View File

@@ -6,7 +6,7 @@
.attachment-list .links-wrapper {
font-size: larger;
margin-bottom: 15px;
margin-block: 12px;
display: flex;
justify-content: space-between;
align-items: baseline;

View File

@@ -1,16 +1,7 @@
.type-contentWidget .note-detail {
height: 100%;
}
.note-detail-content-widget {
height: 100%;
}
.note-detail-content-widget-content {
padding: 15px;
height: 100%;
}
.note-detail.full-height .note-detail-content-widget-content {
padding: 0;
}
}

View File

@@ -1,9 +1,6 @@
.protected-session-password-component {
width: 300px;
margin: 30px auto auto;
}
.protected-session-password-component input,
.protected-session-password-component button {
margin-top: 12px;
display: flex;
margin-inline: 40px;
flex-direction: column;
justify-content: center;
}

View File

@@ -20,7 +20,9 @@ export default function ProtectedSession() {
}, [ passwordRef ]);
return (
<form class="protected-session-password-form" onSubmit={submitCallback}>
<form class="protected-session-password-form tn-centered-form" onSubmit={submitCallback}>
<span class="form-icon bx bx-key" />
<FormGroup name="protected-session-password-in-detail" label={t("protected_session.enter_password_instruction")}>
<FormTextBox
type="password"
@@ -37,4 +39,4 @@ export default function ProtectedSession() {
/>
</form>
)
}
}

View File

@@ -16,3 +16,20 @@
width: 100%;
height: 100%;
}
.web-view-setup-form {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
padding-inline: 40px;
.form-icon {
margin-bottom: 12px;
}
.form-group {
width: 100%;
max-width: 600px;
}
}

View File

@@ -1,9 +1,13 @@
import { useCallback, useState } from "preact/hooks";
import FNote from "../../entities/fnote";
import { t } from "../../services/i18n";
import utils from "../../services/utils";
import Alert from "../react/Alert";
import { useNoteLabel } from "../react/hooks";
import { TypeWidgetProps } from "./type_widget";
import "./WebView.css";
import FormGroup from "../react/FormGroup";
import toast from "../../services/toast";
import Button from "../react/Button";
const isElectron = utils.isElectron();
@@ -12,7 +16,7 @@ export default function WebView({ note }: TypeWidgetProps) {
return (webViewSrc
? <WebViewContent src={webViewSrc} />
: <WebViewHelp />
: <SetupWebView note={note} />
);
}
@@ -24,12 +28,41 @@ function WebViewContent({ src }: { src: string }) {
}
}
function WebViewHelp() {
return (
<Alert className="note-detail-web-view-help" type="warning">
<h4>{t("web_view.web_view")}</h4>
<p>{t("web_view.embed_websites")}</p>
<p>{t("web_view.create_label")}</p>
</Alert>
)
function SetupWebView({note}: {note: FNote}) {
const [srcLabel, setSrcLabel] = useNoteLabel(note, "webViewSrc");
const [src, setSrc] = useState("");
const submit = useCallback((url: string) => {
try {
// Validate URL
new URL(url);
} catch (ex) {
toast.showErrorTitleAndMessage(t("web_view_setup.invalid_url_title"),
t("web_view_setup.invalid_url_message"));
return;
}
setSrcLabel(url);
}, [note]);
return <div class="web-view-setup-form">
<form class="tn-centered-form" onSubmit={() => submit(src)}>
<span className="bx bx-globe-alt form-icon" />
<FormGroup name="web-view-src-detail" label={t("web_view_setup.title")}>
<input className="form-control"
type="text"
value={src}
placeholder={t("web_view_setup.url_placeholder")}
onChange={(e) => {setSrc((e.target as HTMLInputElement)?.value)}}
/>
</FormGroup>
<Button
text={t("web_view_setup.create_button")}
primary
keyboardShortcut="Enter"
/>
</form>
</div>
}

View File

@@ -0,0 +1,40 @@
.shortcuts-options-section {
> header {
position: sticky;
top: 0;
left: 0;
right: 0;
background: var(--main-background-color);
padding-block: 0.5em;
border-bottom: 1px solid var(--main-border-color);
}
> footer {
position: sticky;
bottom: 0;
left: 0;
right: 0;
background: var(--main-background-color);
padding-block: 0.5em;
border-top: 1px solid var(--main-border-color);
display: flex;
justify-content: space-between;
}
table {
width: 100%;
th {
width: 25%;
}
.separator {
background-color: var(--accented-background-color);
font-weight: bold;
&:first-of-type {
padding-top: 1em;
}
}
}
}

View File

@@ -2,7 +2,6 @@ import { ActionKeyboardShortcut, KeyboardShortcut, OptionNames } from "@triliumn
import { t } from "../../../services/i18n";
import { arrayEqual, reloadFrontendApp } from "../../../services/utils";
import Button from "../../react/Button";
import FormGroup from "../../react/FormGroup";
import FormText from "../../react/FormText";
import FormTextBox from "../../react/FormTextBox";
import RawHtml from "../../react/RawHtml";
@@ -12,6 +11,8 @@ import server from "../../../services/server";
import options from "../../../services/options";
import dialog from "../../../services/dialog";
import { useTriliumEvent } from "../../react/hooks";
import "./shortcuts.css";
import NoItems from "../../react/NoItems";
export default function ShortcutSettings() {
const [ keyboardShortcuts, setKeyboardShortcuts ] = useState<KeyboardShortcut[]>([]);
@@ -70,29 +71,29 @@ export default function ShortcutSettings() {
options.saveMany(optionsToSet);
}, [ keyboardShortcuts ]);
const filterLowerCase = filter?.toLowerCase() ?? "";
const filteredKeyboardShortcuts = filter ? keyboardShortcuts.filter((action) => filterKeyboardAction(action, filterLowerCase)) : keyboardShortcuts;
return (
<OptionsSection
className="shortcuts-options-section"
style={{ display: "flex", flexDirection: "column", height: "100%" }}
noCard
>
<FormText>
{t("shortcuts.multiple_shortcuts")}
{t("shortcuts.multiple_shortcuts")}{" "}
<RawHtml html={t("shortcuts.electron_documentation")} />
</FormText>
<FormGroup name="keyboard-shortcut-filter">
<header>
<FormTextBox
placeholder={t("shortcuts.type_text_to_filter")}
currentValue={filter} onChange={(value) => setFilter(value.toLowerCase())}
currentValue={filter} onChange={(value) => setFilter(value)}
/>
</FormGroup>
</header>
<div style={{overflow: "auto", flexGrow: 1, flexShrink: 1}}>
<KeyboardShortcutTable keyboardShortcuts={keyboardShortcuts} filter={filter} />
</div>
<KeyboardShortcutTable filteredKeyboardActions={filteredKeyboardShortcuts} filter={filter} />
<div style={{ display: "flex", justifyContent: "space-between", margin: "15px 15px 0 15px"}}>
<footer>
<Button
text={t("shortcuts.reload_app")}
onClick={reloadFrontendApp}
@@ -102,12 +103,17 @@ export default function ShortcutSettings() {
text={t("shortcuts.set_all_to_default")}
onClick={resetShortcuts}
/>
</div>
</footer>
</OptionsSection>
)
}
function filterKeyboardAction(action: ActionKeyboardShortcut, filter: string) {
function filterKeyboardAction(action: KeyboardShortcut, filter: string) {
// Hide separators when filtering is active.
if ("separator" in action) {
return !filter;
}
return action.actionName.toLowerCase().includes(filter) ||
(action.friendlyName && action.friendlyName.toLowerCase().includes(filter)) ||
(action.defaultShortcuts ?? []).some((shortcut) => shortcut.toLowerCase().includes(filter)) ||
@@ -115,7 +121,7 @@ function filterKeyboardAction(action: ActionKeyboardShortcut, filter: string) {
(action.description && action.description.toLowerCase().includes(filter));
}
function KeyboardShortcutTable({ filter, keyboardShortcuts }: { filter?: string, keyboardShortcuts: KeyboardShortcut[] }) {
function KeyboardShortcutTable({ filteredKeyboardActions, filter }: { filteredKeyboardActions: KeyboardShortcut[], filter: string | undefined }) {
return (
<table class="keyboard-shortcut-table" cellPadding="10">
<thead>
@@ -127,16 +133,17 @@ function KeyboardShortcutTable({ filter, keyboardShortcuts }: { filter?: string,
</tr>
</thead>
<tbody>
{keyboardShortcuts.map(action => (
{filteredKeyboardActions.length > 0
? filteredKeyboardActions.map(action => (
<tr>
{"separator" in action ? ( !filter &&
{"separator" in action ?
<td class="separator" colspan={4} style={{
backgroundColor: "var(--accented-background-color)",
fontWeight: "bold"
}}>
{action.separator}
</td>
) : ( (!filter || filterKeyboardAction(action, filter)) &&
: (
<>
<td>{action.friendlyName}</td>
<td>
@@ -147,7 +154,17 @@ function KeyboardShortcutTable({ filter, keyboardShortcuts }: { filter?: string,
</>
)}
</tr>
))}
))
: (
<tr>
<td colspan={4} class="text-center">
<NoItems
icon="bx bx-filter-alt"
text={t("shortcuts.no_results", { filter })}
/>
</td>
</tr>
)}
</tbody>
</table>
);

View File

@@ -95,7 +95,7 @@ export default defineConfig(() => ({
output: {
entryFileNames: (chunk) => {
// We enforce a hash in the main index file to avoid caching issues, this only works because we have the HTML entry point.
if (chunk.name === "index") {
if (chunk.name === "index" || chunk.name === "print") {
return "src/[name]-[hash].js";
}

View File

@@ -35,7 +35,7 @@
"sucrase": "3.35.1"
},
"devDependencies": {
"@anthropic-ai/sdk": "0.72.1",
"@anthropic-ai/sdk": "0.74.0",
"@braintree/sanitize-url": "7.1.2",
"@electron/remote": "2.1.3",
"@triliumnext/commons": "workspace:*",
@@ -70,7 +70,7 @@
"@types/xml2js": "0.4.14",
"archiver": "7.0.1",
"async-mutex": "0.5.0",
"axios": "1.13.4",
"axios": "1.13.5",
"bindings": "1.5.0",
"bootstrap": "5.3.8",
"chardet": "2.1.1",
@@ -99,7 +99,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "25.8.0",
"i18next": "25.8.4",
"i18next-fs-backend": "2.6.1",
"image-type": "6.0.0",
"ini": "6.0.0",
@@ -112,7 +112,7 @@
"multer": "2.0.2",
"normalize-strings": "1.1.1",
"ollama": "0.6.3",
"openai": "6.17.0",
"openai": "6.21.0",
"rand-token": "1.0.1",
"safe-compare": "1.1.4",
"sanitize-filename": "1.6.3",

View File

@@ -81,66 +81,82 @@ interface ExportAsPdfOpts {
}
electron.ipcMain.on("print-note", async (e, { notePath }: PrintOpts) => {
const { browserWindow, printReport } = await getBrowserWindowForPrinting(e, notePath, "printing");
browserWindow.webContents.print({}, (success, failureReason) => {
if (!success && failureReason !== "Print job canceled") {
electron.dialog.showErrorBox(t("pdf.unable-to-print"), failureReason);
}
e.sender.send("print-done", printReport);
browserWindow.destroy();
});
try {
const { browserWindow, printReport } = await getBrowserWindowForPrinting(e, notePath, "printing");
browserWindow.webContents.print({}, (success, failureReason) => {
if (!success && failureReason !== "Print job canceled") {
electron.dialog.showErrorBox(t("pdf.unable-to-print"), failureReason);
}
e.sender.send("print-done", printReport);
browserWindow.destroy();
});
} catch (err) {
e.sender.send("print-done", {
type: "error",
message: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined
});
}
});
electron.ipcMain.on("export-as-pdf", async (e, { title, notePath, landscape, pageSize }: ExportAsPdfOpts) => {
const { browserWindow, printReport } = await getBrowserWindowForPrinting(e, notePath, "exporting_pdf");
async function print() {
const filePath = electron.dialog.showSaveDialogSync(browserWindow, {
defaultPath: formatDownloadTitle(title, "file", "application/pdf"),
filters: [
{
name: t("pdf.export_filter"),
extensions: ["pdf"]
}
]
});
if (!filePath) return;
let buffer: Buffer;
try {
buffer = await browserWindow.webContents.printToPDF({
landscape,
pageSize,
generateDocumentOutline: true,
generateTaggedPDF: true,
printBackground: true,
displayHeaderFooter: true,
headerTemplate: `<div></div>`,
footerTemplate: `
<div class="pageNumber" style="width: 100%; text-align: center; font-size: 10pt;">
</div>
`
});
} catch (_e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
return;
}
try {
await fs.writeFile(filePath, buffer);
} catch (_e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
return;
}
electron.shell.openPath(filePath);
}
try {
await print();
} finally {
e.sender.send("print-done", printReport);
browserWindow.destroy();
const { browserWindow, printReport } = await getBrowserWindowForPrinting(e, notePath, "exporting_pdf");
async function print() {
const filePath = electron.dialog.showSaveDialogSync(browserWindow, {
defaultPath: formatDownloadTitle(title, "file", "application/pdf"),
filters: [
{
name: t("pdf.export_filter"),
extensions: ["pdf"]
}
]
});
if (!filePath) return;
let buffer: Buffer;
try {
buffer = await browserWindow.webContents.printToPDF({
landscape,
pageSize,
generateDocumentOutline: true,
generateTaggedPDF: true,
printBackground: true,
displayHeaderFooter: true,
headerTemplate: `<div></div>`,
footerTemplate: `
<div class="pageNumber" style="width: 100%; text-align: center; font-size: 10pt;">
</div>
`
});
} catch (_e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
return;
}
try {
await fs.writeFile(filePath, buffer);
} catch (_e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
return;
}
electron.shell.openPath(filePath);
}
try {
await print();
} finally {
e.sender.send("print-done", printReport);
browserWindow.destroy();
}
} catch (err) {
e.sender.send("print-done", {
type: "error",
message: err instanceof Error ? err.message : String(err),
stack: err instanceof Error ? err.stack : undefined
});
}
});
@@ -151,6 +167,7 @@ async function getBrowserWindowForPrinting(e: IpcMainEvent, notePath: string, ac
nodeIntegration: true,
contextIsolation: false,
offscreen: true,
devTools: false,
session: e.sender.session
},
});
@@ -158,13 +175,78 @@ async function getBrowserWindowForPrinting(e: IpcMainEvent, notePath: string, ac
const progressCallback = (_e, progress: number) => e.sender.send("print-progress", { progress, action });
ipcMain.on("print-progress", progressCallback);
await browserWindow.loadURL(`http://127.0.0.1:${port}/?print#${notePath}`);
const printReport = await browserWindow.webContents.executeJavaScript(`
new Promise(resolve => {
if (window._noteReady) return resolve(window._noteReady);
window.addEventListener("note-ready", (data) => resolve(data.detail));
});
`);
// Capture ALL console output (including errors) for debugging
browserWindow.webContents.on("console-message", (e, message, line, sourceId) => {
if (e.level === "debug") return;
if (e.level === "error") {
log.error(`[Print Window ${sourceId}:${line}] ${message}`);
return;
}
log.info(`[Print Window ${sourceId}:${line}] ${message}`);
});
try {
await browserWindow.loadURL(`http://127.0.0.1:${port}/?print#${notePath}`);
} catch (err) {
log.error(`Failed to load print window: ${err}`);
ipcMain.off("print-progress", progressCallback);
throw err;
}
// Set up error tracking and logging in the renderer process
await browserWindow.webContents.executeJavaScript(`
(function() {
window._printWindowErrors = [];
window.addEventListener("error", (e) => {
const errorMsg = "Uncaught error: " + e.message + " at " + e.filename + ":" + e.lineno + ":" + e.colno;
console.error(errorMsg);
if (e.error?.stack) console.error(e.error.stack);
window._printWindowErrors.push({
type: 'error',
message: errorMsg,
stack: e.error?.stack
});
});
window.addEventListener("unhandledrejection", (e) => {
const errorMsg = "Unhandled rejection: " + String(e.reason);
console.error(errorMsg);
if (e.reason?.stack) console.error(e.reason.stack);
window._printWindowErrors.push({
type: 'rejection',
message: errorMsg,
stack: e.reason?.stack
});
});
})();
`).catch(err => log.error(`Failed to set up error handlers in print window: ${err}`));
let printReport;
try {
printReport = await browserWindow.webContents.executeJavaScript(`
new Promise((resolve, reject) => {
if (window._noteReady) return resolve(window._noteReady);
// Check for errors periodically
const errorChecker = setInterval(() => {
if (window._printWindowErrors && window._printWindowErrors.length > 0) {
clearInterval(errorChecker);
const errors = window._printWindowErrors.map(e => e.message).join('; ');
reject(new Error("Print window errors: " + errors));
}
}, 100);
window.addEventListener("note-ready", (data) => {
clearInterval(errorChecker);
resolve(data.detail);
});
});
`);
} catch (err) {
log.error(`Print window promise failed for ${notePath}: ${err}`);
ipcMain.off("print-progress", progressCallback);
throw err;
}
ipcMain.off("print-progress", progressCallback);
return { browserWindow, printReport };
}

View File

@@ -13,10 +13,10 @@
"postinstall": "wxt prepare"
},
"keywords": [],
"packageManager": "pnpm@10.29.1",
"packageManager": "pnpm@10.29.2",
"devDependencies": {
"@wxt-dev/auto-icons": "1.1.0",
"wxt": "0.20.13"
"wxt": "0.20.14"
},
"dependencies": {
"cash-dom": "8.1.5"

View File

@@ -9,7 +9,7 @@
"preview": "pnpm build && vite preview"
},
"dependencies": {
"i18next": "25.8.0",
"i18next": "25.8.4",
"i18next-http-backend": "3.0.2",
"preact": "10.28.3",
"preact-iso": "2.11.1",

View File

@@ -46,7 +46,7 @@
"devDependencies": {
"@electron/rebuild": "4.0.3",
"@fast-csv/parse": "5.0.5",
"@playwright/test": "1.58.1",
"@playwright/test": "1.58.2",
"@triliumnext/server": "workspace:*",
"@types/express": "5.0.6",
"@types/js-yaml": "4.0.9",
@@ -57,7 +57,7 @@
"chalk": "5.6.2",
"cross-env": "10.1.0",
"dpdm": "4.0.1",
"esbuild": "0.27.2",
"esbuild": "0.27.3",
"eslint": "10.0.0",
"eslint-config-preact": "2.0.0",
"eslint-config-prettier": "10.1.8",
@@ -69,11 +69,11 @@
"js-yaml": "4.1.1",
"jsonc-eslint-parser": "2.4.2",
"react-refresh": "0.18.0",
"rollup-plugin-webpack-stats": "2.1.10",
"rollup-plugin-webpack-stats": "2.1.11",
"tslib": "2.8.1",
"tsx": "4.21.0",
"typescript": "5.9.3",
"typescript-eslint": "8.54.0",
"typescript-eslint": "8.55.0",
"upath": "2.0.1",
"vite": "7.3.1",
"vite-plugin-dts": "4.5.4",
@@ -93,7 +93,7 @@
"url": "https://github.com/TriliumNext/Trilium/issues"
},
"homepage": "https://triliumnotes.org",
"packageManager": "pnpm@10.29.1",
"packageManager": "pnpm@10.29.2",
"pnpm": {
"patchedDependencies": {
"@ckeditor/ckeditor5-mention": "patches/@ckeditor__ckeditor5-mention.patch",

View File

@@ -21,11 +21,11 @@
"ckeditor5-metadata.json"
],
"devDependencies": {
"@ckeditor/ckeditor5-dev-build-tools": "54.3.2",
"@ckeditor/ckeditor5-dev-build-tools": "54.3.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"@vitest/browser": "4.0.18",
"@vitest/coverage-istanbul": "4.0.18",
"ckeditor5": "47.4.0",
@@ -33,13 +33,13 @@
"eslint-config-ckeditor5": ">=9.1.0",
"http-server": "14.1.1",
"lint-staged": "16.2.7",
"stylelint": "17.1.0",
"stylelint": "17.2.0",
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.18",
"webdriverio": "9.23.3"
"webdriverio": "9.24.0"
},
"peerDependencies": {
"ckeditor5": "47.4.0"

View File

@@ -22,11 +22,11 @@
"ckeditor5-metadata.json"
],
"devDependencies": {
"@ckeditor/ckeditor5-dev-build-tools": "54.3.2",
"@ckeditor/ckeditor5-dev-build-tools": "54.3.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"@vitest/browser": "4.0.18",
"@vitest/coverage-istanbul": "4.0.18",
"ckeditor5": "47.4.0",
@@ -34,13 +34,13 @@
"eslint-config-ckeditor5": ">=9.1.0",
"http-server": "14.1.1",
"lint-staged": "16.2.7",
"stylelint": "17.1.0",
"stylelint": "17.2.0",
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.18",
"webdriverio": "9.23.3"
"webdriverio": "9.24.0"
},
"peerDependencies": {
"ckeditor5": "47.4.0"

View File

@@ -24,11 +24,11 @@
"ckeditor5-metadata.json"
],
"devDependencies": {
"@ckeditor/ckeditor5-dev-build-tools": "54.3.2",
"@ckeditor/ckeditor5-dev-build-tools": "54.3.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"@vitest/browser": "4.0.18",
"@vitest/coverage-istanbul": "4.0.18",
"ckeditor5": "47.4.0",
@@ -36,13 +36,13 @@
"eslint-config-ckeditor5": ">=9.1.0",
"http-server": "14.1.1",
"lint-staged": "16.2.7",
"stylelint": "17.1.0",
"stylelint": "17.2.0",
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.18",
"webdriverio": "9.23.3"
"webdriverio": "9.24.0"
},
"peerDependencies": {
"ckeditor5": "47.4.0"

View File

@@ -24,11 +24,11 @@
"ckeditor5-metadata.json"
],
"devDependencies": {
"@ckeditor/ckeditor5-dev-build-tools": "54.3.2",
"@ckeditor/ckeditor5-dev-build-tools": "54.3.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"@vitest/browser": "4.0.18",
"@vitest/coverage-istanbul": "4.0.18",
"ckeditor5": "47.4.0",
@@ -36,13 +36,13 @@
"eslint-config-ckeditor5": ">=9.1.0",
"http-server": "14.1.1",
"lint-staged": "16.2.7",
"stylelint": "17.1.0",
"stylelint": "17.2.0",
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.18",
"webdriverio": "9.23.3"
"webdriverio": "9.24.0"
},
"peerDependencies": {
"ckeditor5": "47.4.0"

View File

@@ -24,11 +24,11 @@
"ckeditor5-metadata.json"
],
"devDependencies": {
"@ckeditor/ckeditor5-dev-build-tools": "54.3.2",
"@ckeditor/ckeditor5-dev-build-tools": "54.3.3",
"@ckeditor/ckeditor5-inspector": ">=4.1.0",
"@ckeditor/ckeditor5-package-tools": "5.0.1",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"@vitest/browser": "4.0.18",
"@vitest/coverage-istanbul": "4.0.18",
"ckeditor5": "47.4.0",
@@ -36,13 +36,13 @@
"eslint-config-ckeditor5": ">=9.1.0",
"http-server": "14.1.1",
"lint-staged": "16.2.7",
"stylelint": "17.1.0",
"stylelint": "17.2.0",
"stylelint-config-ckeditor5": ">=9.1.0",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vite-plugin-svgo": "2.0.0",
"vitest": "4.0.18",
"webdriverio": "9.23.3"
"webdriverio": "9.24.0"
},
"peerDependencies": {
"ckeditor5": "47.4.0"

View File

@@ -16,7 +16,7 @@
"ckeditor5-premium-features": "47.4.0"
},
"devDependencies": {
"@smithy/middleware-retry": "4.4.30",
"@smithy/middleware-retry": "4.4.31",
"@types/jquery": "3.5.33"
}
}

View File

@@ -5,7 +5,7 @@
"type": "module",
"main": "./src/index.ts",
"dependencies": {
"@codemirror/commands": "6.10.1",
"@codemirror/commands": "6.10.2",
"@codemirror/lang-css": "6.3.1",
"@codemirror/lang-html": "6.4.11",
"@codemirror/lang-javascript": "6.2.4",
@@ -16,7 +16,7 @@
"@codemirror/lang-xml": "6.1.0",
"@codemirror/legacy-modes": "6.5.2",
"@codemirror/search": "6.6.0",
"@codemirror/view": "6.39.12",
"@codemirror/view": "6.39.13",
"@fsegurai/codemirror-theme-abcdef": "6.2.3",
"@fsegurai/codemirror-theme-abyss": "6.2.3",
"@fsegurai/codemirror-theme-android-studio": "6.2.3",

View File

@@ -48,6 +48,7 @@ type Labels = {
"calendar:initialDate": string;
"map:style": string;
"map:scale": boolean;
"map:hideLabels": boolean;
"board:groupBy": string;
maxNestingDepth: number;
includeArchived: boolean;

View File

@@ -31,10 +31,10 @@
"devDependencies": {
"@digitak/esrun": "3.2.26",
"@triliumnext/ckeditor5": "workspace:*",
"@typescript-eslint/eslint-plugin": "8.54.0",
"@typescript-eslint/parser": "8.54.0",
"@typescript-eslint/eslint-plugin": "8.55.0",
"@typescript-eslint/parser": "8.55.0",
"dotenv": "17.2.3",
"esbuild": "0.27.2",
"esbuild": "0.27.3",
"eslint": "10.0.0",
"highlight.js": "11.11.1",
"typescript": "5.9.3"

1789
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff