diff --git a/.nvmrc b/.nvmrc index cf2efde811..f94d3c2ea9 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24.13.0 \ No newline at end of file +24.13.1 \ No newline at end of file diff --git a/apps/build-docs/package.json b/apps/build-docs/package.json index f259de6c4c..76f479c960 100644 --- a/apps/build-docs/package.json +++ b/apps/build-docs/package.json @@ -9,14 +9,14 @@ "keywords": [], "author": "Elian Doran ", "license": "AGPL-3.0-only", - "packageManager": "pnpm@10.29.1", + "packageManager": "pnpm@10.30.0", "devDependencies": { - "@redocly/cli": "2.15.1", + "@redocly/cli": "2.19.1", "archiver": "7.0.1", "fs-extra": "11.3.3", "react": "19.2.4", "react-dom": "19.2.4", - "typedoc": "0.28.16", + "typedoc": "0.28.17", "typedoc-plugin-missing-exports": "4.1.2" } } diff --git a/apps/client/package.json b/apps/client/package.json index 4f3e3e0275..1441e9799a 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -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.8.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.11", "i18next-http-backend": "3.0.2", "jquery": "4.0.0", "jquery.fancytree": "2.38.5", @@ -54,14 +54,14 @@ "leaflet": "1.9.4", "leaflet-gpx": "2.2.0", "mark.js": "8.11.1", - "marked": "17.0.1", - "mermaid": "11.12.2", - "mind-elixir": "5.8.0", + "marked": "17.0.3", + "mermaid": "11.12.3", + "mind-elixir": "5.8.3", "normalize.css": "8.0.1", "panzoom": "9.4.3", "preact": "10.28.3", "react-i18next": "16.5.4", - "react-window": "2.2.6", + "react-window": "2.2.7", "reveal.js": "5.2.1", "svg-pan-zoom": "3.6.2", "tabulator-tables": "6.3.1", @@ -69,7 +69,7 @@ }, "devDependencies": { "@ckeditor/ckeditor5-inspector": "5.0.0", - "@prefresh/vite": "2.4.11", + "@prefresh/vite": "2.4.12", "@types/bootstrap": "5.2.10", "@types/jquery": "3.5.33", "@types/leaflet": "1.9.21", @@ -78,7 +78,7 @@ "@types/reveal.js": "5.2.2", "@types/tabulator-tables": "6.3.1", "copy-webpack-plugin": "13.0.1", - "happy-dom": "20.5.0", + "happy-dom": "20.6.3", "lightningcss": "1.31.1", "script-loader": "0.7.2", "vite-plugin-static-copy": "3.2.0" diff --git a/apps/client/src/entities/fnote.ts b/apps/client/src/entities/fnote.ts index f161d7adb1..2b515f2412 100644 --- a/apps/client/src/entities/fnote.ts +++ b/apps/client/src/entities/fnote.ts @@ -700,6 +700,15 @@ export default class FNote { return this.hasAttribute(LABEL, name); } + /** + * Returns `true` if the note has a label with the given name (same as {@link hasOwnedLabel}), or it has a label with the `disabled:` prefix (for example due to a safe import). + * @param name the name of the label to look for. + * @returns `true` if the label exists, or its version with the `disabled:` prefix. + */ + hasLabelOrDisabled(name: string) { + return this.hasLabel(name) || this.hasLabel(`disabled:${name}`); + } + /** * @param name - label name * @returns true if label exists (including inherited) and does not have "false" value. diff --git a/apps/client/src/layouts/mobile_layout.tsx b/apps/client/src/layouts/mobile_layout.tsx index 8b162bced3..3fc5422b0a 100644 --- a/apps/client/src/layouts/mobile_layout.tsx +++ b/apps/client/src/layouts/mobile_layout.tsx @@ -23,10 +23,7 @@ import NoteTreeWidget from "../widgets/note_tree.js"; import NoteWrapperWidget from "../widgets/note_wrapper.js"; import NoteDetail from "../widgets/NoteDetail.jsx"; import QuickSearchWidget from "../widgets/quick_search.js"; -import { useNoteContext } from "../widgets/react/hooks.jsx"; -import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx"; -import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx"; -import SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx"; +import ScrollPadding from "../widgets/scroll_padding"; import SearchResult from "../widgets/search_result.jsx"; import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx"; import { applyModals } from "./layout_commons.js"; @@ -78,7 +75,7 @@ export default class MobileLayout { .child() .child() .child() - .child() + .child() ) .child() .child(new FindWidget()) @@ -102,13 +99,3 @@ export default class MobileLayout { return rootContainer; } } - -function FilePropertiesWrapper() { - const { note, ntxId } = useNoteContext(); - - return ( -
- {note?.type === "file" && } -
- ); -} diff --git a/apps/client/src/print.tsx b/apps/client/src/print.tsx index 96461db2dc..dc7817d9b5 100644 --- a/apps/client/src/print.tsx +++ b/apps/client/src/print.tsx @@ -18,6 +18,10 @@ export type PrintReport = { } | { type: "collection"; ignoredNoteIds: string[]; +} | { + type: "error"; + message: string; + stack?: string; }; async function main() { diff --git a/apps/client/src/services/attributes.ts b/apps/client/src/services/attributes.ts index 2bff933244..77558c9464 100644 --- a/apps/client/src/services/attributes.ts +++ b/apps/client/src/services/attributes.ts @@ -168,6 +168,49 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin return false; } +/** + * Toggles whether a dangerous attribute is enabled or not. When an attribute is disabled, its name is prefixed with `disabled:`. + * + * Note that this work for non-dangerous attributes as well. + * + * If there are multiple attributes with the same name, all of them will be toggled at the same time. + * + * @param note the note whose attribute to change. + * @param type the type of dangerous attribute (label or relation). + * @param name the name of the dangerous attribute. + * @param willEnable whether to enable or disable the attribute. + * @returns a promise that will resolve when the request to the server completes. + */ +async function toggleDangerousAttribute(note: FNote, type: "label" | "relation", name: string, willEnable: boolean) { + const attrs = [ + ...note.getOwnedAttributes(type, name), + ...note.getOwnedAttributes(type, `disabled:${name}`) + ]; + + for (const attr of attrs) { + const baseName = getNameWithoutDangerousPrefix(attr.name); + const newName = willEnable ? baseName : `disabled:${baseName}`; + if (newName === attr.name) continue; + + // We are adding and removing afterwards to avoid a flicker (because for a moment there would be no active content attribute anymore) because the operations are done in sequence and not atomically. + if (attr.type === "label") { + await setLabel(note.noteId, newName, attr.value); + } else { + await setRelation(note.noteId, newName, attr.value); + } + await removeAttributeById(note.noteId, attr.attributeId); + } +} + +/** + * Returns the name of an attribute without the `disabled:` prefix, or the same name if it's not disabled. + * @param name the name of an attribute. + * @returns the name without the `disabled:` prefix. + */ +function getNameWithoutDangerousPrefix(name: string) { + return name.startsWith("disabled:") ? name.substring(9) : name; +} + export default { addLabel, setLabel, @@ -177,5 +220,7 @@ export default { removeAttributeById, removeOwnedLabelByName, removeOwnedRelationByName, - isAffecting + isAffecting, + toggleDangerousAttribute, + getNameWithoutDangerousPrefix }; diff --git a/apps/client/src/services/bundle.ts b/apps/client/src/services/bundle.ts index d33ba76a0a..7cee01812b 100644 --- a/apps/client/src/services/bundle.ts +++ b/apps/client/src/services/bundle.ts @@ -2,7 +2,6 @@ import { h, VNode } from "preact"; import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js"; import RightPanelWidget from "../widgets/right_panel_widget.js"; -import froca from "./froca.js"; import type { Entity } from "./frontend_script_api.js"; import { WidgetDefinitionWithType } from "./frontend_script_api_preact.js"; import { t } from "./i18n.js"; @@ -38,15 +37,18 @@ async function getAndExecuteBundle(noteId: string, originEntity = null, script = export type ParentName = "left-pane" | "center-pane" | "note-detail-pane" | "right-pane"; -export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery) { +export async function executeBundleWithoutErrorHandling(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery) { const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, $container); + return await function () { + return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`); + }.call(apiContext); +} +export async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $container?: JQuery) { try { - return await function () { - return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`); - }.call(apiContext); - } catch (e: any) { - showErrorForScriptNote(bundle.noteId, t("toast.bundle-error.message", { message: e.message })); + return await executeBundleWithoutErrorHandling(bundle, originEntity, $container); + } catch (e: unknown) { + showErrorForScriptNote(bundle.noteId, t("toast.bundle-error.message", { message: getErrorMessage(e) })); logError("Widget initialization failed: ", e); } } diff --git a/apps/client/src/services/content_renderer.ts b/apps/client/src/services/content_renderer.ts index aca5d3efe3..148d59acd0 100644 --- a/apps/client/src/services/content_renderer.ts +++ b/apps/client/src/services/content_renderer.ts @@ -15,7 +15,7 @@ import protectedSessionService from "./protected_session.js"; import protectedSessionHolder from "./protected_session_holder.js"; import renderService from "./render.js"; import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js"; -import utils from "./utils.js"; +import utils, { getErrorMessage } from "./utils.js"; let idCounter = 1; @@ -62,7 +62,10 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo } else if (type === "render" && entity instanceof FNote) { const $content = $("
"); - await renderService.render(entity, $content); + await renderService.render(entity, $content, (e) => { + const $error = $("
").addClass("admonition caution").text(typeof e === "string" ? e : getErrorMessage(e)); + $content.empty().append($error); + }); $renderedContent.append($content); } else if (type === "doc" && "noteId" in entity) { diff --git a/apps/client/src/services/render.ts b/apps/client/src/services/render.ts deleted file mode 100644 index adfd8a4949..0000000000 --- a/apps/client/src/services/render.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { h, VNode } from "preact"; - -import type FNote from "../entities/fnote.js"; -import { renderReactWidgetAtElement } from "../widgets/react/react_utils.jsx"; -import bundleService, { type Bundle } from "./bundle.js"; -import froca from "./froca.js"; -import server from "./server.js"; - -async function render(note: FNote, $el: JQuery) { - const relations = note.getRelations("renderNote"); - const renderNoteIds = relations.map((rel) => rel.value).filter((noteId) => noteId); - - $el.empty().toggle(renderNoteIds.length > 0); - - for (const renderNoteId of renderNoteIds) { - const bundle = await server.post(`script/bundle/${renderNoteId}`); - - const $scriptContainer = $("
"); - $el.append($scriptContainer); - - $scriptContainer.append(bundle.html); - - // async so that scripts cannot block trilium execution - bundleService.executeBundle(bundle, note, $scriptContainer).then(result => { - // Render JSX - if (bundle.html === "") { - renderIfJsx(bundle, result, $el); - } - }); - } - - return renderNoteIds.length > 0; -} - -async function renderIfJsx(bundle: Bundle, result: unknown, $el: JQuery) { - // Ensure the root script note is actually a JSX. - const rootScriptNoteId = await froca.getNote(bundle.noteId); - if (rootScriptNoteId?.mime !== "text/jsx") return; - - // Ensure the output is a valid el. - if (typeof result !== "function") return; - - // Obtain the parent component. - const closestComponent = glob.getComponentByEl($el.closest(".component")[0]); - if (!closestComponent) return; - - // Render the element. - const el = h(result as () => VNode, {}); - renderReactWidgetAtElement(closestComponent, el, $el[0]); -} - -export default { - render -}; diff --git a/apps/client/src/services/render.tsx b/apps/client/src/services/render.tsx new file mode 100644 index 0000000000..682efa8871 --- /dev/null +++ b/apps/client/src/services/render.tsx @@ -0,0 +1,86 @@ +import { Component, h, VNode } from "preact"; + +import type FNote from "../entities/fnote.js"; +import { renderReactWidgetAtElement } from "../widgets/react/react_utils.jsx"; +import { type Bundle, executeBundleWithoutErrorHandling } from "./bundle.js"; +import froca from "./froca.js"; +import server from "./server.js"; + +type ErrorHandler = (e: unknown) => void; + +async function render(note: FNote, $el: JQuery, onError?: ErrorHandler) { + const relations = note.getRelations("renderNote"); + const renderNoteIds = relations.map((rel) => rel.value).filter((noteId) => noteId); + + $el.empty().toggle(renderNoteIds.length > 0); + + try { + for (const renderNoteId of renderNoteIds) { + const bundle = await server.postWithSilentInternalServerError(`script/bundle/${renderNoteId}`); + + const $scriptContainer = $("
"); + $el.append($scriptContainer); + + $scriptContainer.append(bundle.html); + + // async so that scripts cannot block trilium execution + executeBundleWithoutErrorHandling(bundle, note, $scriptContainer) + .catch(onError) + .then(result => { + // Render JSX + if (bundle.html === "") { + renderIfJsx(bundle, result, $el, onError).catch(onError); + } + }); + } + + return renderNoteIds.length > 0; + } catch (e) { + if (typeof e === "string" && e.startsWith("{") && e.endsWith("}")) { + try { + onError?.(JSON.parse(e)); + } catch (e) { + onError?.(e); + } + } else { + onError?.(e); + } + } +} + +async function renderIfJsx(bundle: Bundle, result: unknown, $el: JQuery, onError?: ErrorHandler) { + // Ensure the root script note is actually a JSX. + const rootScriptNoteId = await froca.getNote(bundle.noteId); + if (rootScriptNoteId?.mime !== "text/jsx") return; + + // Ensure the output is a valid el. + if (typeof result !== "function") return; + + // Obtain the parent component. + const closestComponent = glob.getComponentByEl($el.closest(".component")[0]); + if (!closestComponent) return; + + // Render the element. + const UserErrorBoundary = class UserErrorBoundary extends Component { + constructor(props: object) { + super(props); + this.state = { error: null }; + } + + componentDidCatch(error: unknown) { + onError?.(error); + this.setState({ error }); + } + + render() { + if ("error" in this.state && this.state?.error) return null; + return this.props.children; + } + }; + const el = h(UserErrorBoundary, {}, h(result as () => VNode, {})); + renderReactWidgetAtElement(closestComponent, el, $el[0]); +} + +export default { + render +}; diff --git a/apps/client/src/services/server.ts b/apps/client/src/services/server.ts index 381c58a3cf..fb1e598ec2 100644 --- a/apps/client/src/services/server.ts +++ b/apps/client/src/services/server.ts @@ -73,6 +73,10 @@ async function post(url: string, data?: unknown, componentId?: string) { return await call("POST", url, componentId, { data }); } +async function postWithSilentInternalServerError(url: string, data?: unknown, componentId?: string) { + return await call("POST", url, componentId, { data, silentInternalServerError: true }); +} + async function put(url: string, data?: unknown, componentId?: string) { return await call("PUT", url, componentId, { data }); } @@ -111,6 +115,7 @@ let maxKnownEntityChangeId = 0; interface CallOptions { data?: unknown; silentNotFound?: boolean; + silentInternalServerError?: boolean; // If `true`, the value will be returned as a string instead of a JavaScript object if JSON, XMLDocument if XML, etc. raw?: boolean; } @@ -143,7 +148,7 @@ async function call(method: string, url: string, componentId?: string, option }); })) as any; } else { - resp = await ajax(url, method, data, headers, !!options.silentNotFound, options.raw); + resp = await ajax(url, method, data, headers, options); } const maxEntityChangeIdStr = resp.headers["trilium-max-entity-change-id"]; @@ -155,10 +160,7 @@ async function call(method: string, url: string, componentId?: string, option return resp.body as T; } -/** - * @param raw if `true`, the value will be returned as a string instead of a JavaScript object if JSON, XMLDocument if XML, etc. - */ -function ajax(url: string, method: string, data: unknown, headers: Headers, silentNotFound: boolean, raw?: boolean): Promise { +function ajax(url: string, method: string, data: unknown, headers: Headers, opts: CallOptions): Promise { return new Promise((res, rej) => { const options: JQueryAjaxSettings = { url: window.glob.baseApiUrl + url, @@ -190,7 +192,9 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile // don't report requests that are rejected by the browser, usually when the user is refreshing or going to a different page. rej("rejected by browser"); return; - } else if (silentNotFound && jqXhr.status === 404) { + } else if (opts.silentNotFound && jqXhr.status === 404) { + // report nothing + } else if (opts.silentInternalServerError && jqXhr.status === 500) { // report nothing } else { await reportError(method, url, jqXhr.status, jqXhr.responseText); @@ -200,7 +204,7 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile } }; - if (raw) { + if (opts.raw) { options.dataType = "text"; } @@ -299,6 +303,7 @@ export default { get, getWithSilentNotFound, post, + postWithSilentInternalServerError, put, patch, remove, diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index acfdf6da40..8950f3fd3f 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -153,6 +153,11 @@ textarea, background: var(--input-background-color); } +.form-control:disabled { + background-color: var(--input-background-color); + opacity: 0.6; +} + .form-control:focus { color: var(--input-text-color); background: var(--input-background-color); @@ -942,6 +947,7 @@ table.promoted-attributes-in-tooltip th { color: var(--muted-text-color); opacity: 0.6; line-height: 1; + word-wrap: break-word; } .aa-dropdown-menu .aa-suggestion p { @@ -1336,15 +1342,12 @@ body.desktop .dropdown-submenu > .dropdown-menu { max-width: 300px; } -.dropdown-submenu.dropstart > .dropdown-menu { +.dropdown-submenu.dropstart > .dropdown-menu, +body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { inset-inline-start: auto; inset-inline-end: calc(100% - 2px); } -body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { - inset-inline-start: calc(-100% + 10px); -} - .right-dropdown-widget { flex-shrink: 0; } @@ -1584,7 +1587,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { position: absolute; top: 0; inset-inline-start: 0; - bottom: 0; + height: 100dvh; width: 85vw; padding-top: env(safe-area-inset-top); transition: transform 250ms ease-in-out; @@ -1648,13 +1651,27 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu { word-break: break-all; } - body.mobile .jump-to-note-dialog .modal-content { - overflow-y: auto; - } + body.mobile .jump-to-note-dialog { + .modal-header { + padding-bottom: 0.75rem !important; + } - body.mobile .jump-to-note-dialog .modal-dialog .aa-dropdown-menu { - max-height: unset; - overflow: auto; + .modal-content { + padding-bottom: 0 !important; + } + + .modal-body { + overflow-y: auto; + } + + .aa-dropdown-menu { + max-height: unset; + overflow: auto; + } + + .aa-suggestion { + padding-inline: 0; + } } body.mobile .modal-dialog .dropdown-menu { diff --git a/apps/client/src/stylesheets/theme-next-dark.css b/apps/client/src/stylesheets/theme-next-dark.css index f8fb305726..dfdc209040 100644 --- a/apps/client/src/stylesheets/theme-next-dark.css +++ b/apps/client/src/stylesheets/theme-next-dark.css @@ -210,6 +210,7 @@ --badge-share-background-color: #4d4d4d; --badge-clipped-note-background-color: #295773; --badge-execute-background-color: #604180; + --badge-active-content-background-color: rgb(12, 68, 70); --note-icon-background-color: #444444; --note-icon-color: #d4d4d4; @@ -238,9 +239,9 @@ --bottom-panel-background-color: #11111180; --bottom-panel-title-bar-background-color: #3F3F3F80; - + --status-bar-border-color: var(--main-border-color); - + --scrollbar-thumb-color: #fdfdfd5c; --scrollbar-thumb-hover-color: #ffffff7d; --scrollbar-background-color: transparent; @@ -290,6 +291,15 @@ --ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75); --ck-editor-toolbar-dropdown-button-open-background: #ffffff14; + --note-list-view-icon-color: var(--left-pane-icon-color); + --note-list-view-large-icon-background: var(--note-icon-background-color); + --note-list-view-large-icon-color: var(--note-icon-color); + --note-list-view-search-result-highlight-background: transparent; + --note-list-view-search-result-highlight-color: var(--quick-search-result-highlight-color); + --note-list-view-content-background: rgba(0, 0, 0, .2); + --note-list-view-content-search-result-highlight-background: var(--quick-search-result-highlight-color); + --note-list-view-content-search-result-highlight-color: black; + --calendar-coll-event-background-saturation: 25%; --calendar-coll-event-background-lightness: 20%; --calendar-coll-event-background-color: #3c3c3c; @@ -303,7 +313,8 @@ * Dark color scheme tweaks */ -#left-pane .fancytree-node.tinted { +#left-pane .fancytree-node.tinted, +.nested-note-list-item.use-note-color { --custom-color: var(--dark-theme-custom-color); /* The background color of the active item in the note tree. @@ -337,12 +348,24 @@ body .todo-list input[type="checkbox"]:not(:checked):before { --promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%); } +.modal.tab-bar-modal .tabs .tab-card.with-hue { + background-color: hsl(var(--bg-hue), 8.8%, 11.2%); + border-color: hsl(var(--bg-hue), 9.4%, 25.1%); +} + +.modal.tab-bar-modal .tabs .tab-card.active.with-hue { + background-color: hsl(var(--bg-hue), 8.8%, 16.2%); + border-color: hsl(var(--bg-hue), 9.4%, 25.1%); +} + + .use-note-color { --custom-color: var(--dark-theme-custom-color); } .note-split.with-hue, -.quick-edit-dialog-wrapper.with-hue { +.quick-edit-dialog-wrapper.with-hue, +.nested-note-list-item.with-hue { --note-icon-custom-background-color: hsl(var(--custom-color-hue), 15.8%, 30.9%); --note-icon-custom-color: hsl(var(--custom-color-hue), 100%, 76.5%); --note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 28.3%, 36.7%); @@ -351,4 +374,4 @@ body .todo-list input[type="checkbox"]:not(:checked):before { .note-split.with-hue *::selection, .quick-edit-dialog-wrapper.with-hue *::selection { --selection-background-color: hsl(var(--custom-color-hue), 49.2%, 35%); -} \ No newline at end of file +} diff --git a/apps/client/src/stylesheets/theme-next-light.css b/apps/client/src/stylesheets/theme-next-light.css index 2d7862ae00..4b6b37718c 100644 --- a/apps/client/src/stylesheets/theme-next-light.css +++ b/apps/client/src/stylesheets/theme-next-light.css @@ -202,6 +202,7 @@ --badge-share-background-color: #6b6b6b; --badge-clipped-note-background-color: #2284c0; --badge-execute-background-color: #7b47af; + --badge-active-content-background-color: rgb(27, 164, 168); --note-icon-background-color: #4f4f4f; --note-icon-color: white; @@ -288,6 +289,15 @@ --ck-editor-toolbar-button-on-shadow: none; --ck-editor-toolbar-dropdown-button-open-background: #0000000f; + --note-list-view-icon-color: var(--left-pane-icon-color); + --note-list-view-large-icon-background: var(--note-icon-background-color); + --note-list-view-large-icon-color: var(--note-icon-color); + --note-list-view-search-result-highlight-background: transparent; + --note-list-view-search-result-highlight-color: var(--quick-search-result-highlight-color); + --note-list-view-content-background: #b1b1b133; + --note-list-view-content-search-result-highlight-background: var(--quick-search-result-highlight-color); + --note-list-view-content-search-result-highlight-color: white; + --calendar-coll-event-background-lightness: 95%; --calendar-coll-event-background-saturation: 80%; --calendar-coll-event-background-color: #eaeaea; @@ -297,7 +307,8 @@ --calendar-coll-today-background-color: #00000006; } -#left-pane .fancytree-node.tinted { +#left-pane .fancytree-node.tinted, +.nested-note-list-item.use-note-color { --custom-color: var(--light-theme-custom-color); /* The background color of the active item in the note tree. @@ -312,8 +323,19 @@ --promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%); } +.modal.tab-bar-modal .tabs .tab-card.with-hue { + background-color: hsl(var(--bg-hue), 56%, 96%); + border-color: hsl(var(--bg-hue), 33%, 41%); +} + +.modal.tab-bar-modal .tabs .tab-card.active.with-hue { + background-color: hsl(var(--bg-hue), 86%, 96%); + border-color: hsl(var(--bg-hue), 33%, 41%); +} + .note-split.with-hue, -.quick-edit-dialog-wrapper.with-hue { +.quick-edit-dialog-wrapper.with-hue, +.nested-note-list-item.with-hue { --note-icon-custom-background-color: hsl(var(--custom-color-hue), 44.5%, 43.1%); --note-icon-custom-color: hsl(var(--custom-color-hue), 91.3%, 91%); --note-icon-hover-custom-background-color: hsl(var(--custom-color-hue), 55.1%, 50.2%); @@ -322,4 +344,4 @@ .note-split.with-hue *::selection, .quick-edit-dialog-wrapper.with-hue *::selection { --selection-background-color: hsl(var(--custom-color-hue), 60%, 90%); -} \ No newline at end of file +} diff --git a/apps/client/src/stylesheets/theme-next/base.css b/apps/client/src/stylesheets/theme-next/base.css index 69f77569db..9e39b2f002 100644 --- a/apps/client/src/stylesheets/theme-next/base.css +++ b/apps/client/src/stylesheets/theme-next/base.css @@ -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; +} \ No newline at end of file diff --git a/apps/client/src/stylesheets/theme-next/forms.css b/apps/client/src/stylesheets/theme-next/forms.css index 12f361c2f2..cbe5f2cda0 100644 --- a/apps/client/src/stylesheets/theme-next/forms.css +++ b/apps/client/src/stylesheets/theme-next/forms.css @@ -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 */ @@ -129,6 +145,10 @@ button.btn.btn-success kbd { font-size: calc(var(--icon-button-size) * var(--icon-button-icon-ratio)); } +:root .icon-action.disabled::before { + opacity: .5; +} + :root .icon-action:not(.global-menu-button):hover, :root .icon-action:not(.global-menu-button).show, :root .tn-tool-button:hover, @@ -794,3 +814,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-group, +.tn-centered-form button { + margin-top: 12px; +} diff --git a/apps/client/src/stylesheets/theme-next/pages.css b/apps/client/src/stylesheets/theme-next/pages.css index a5041cd553..42a831bae7 100644 --- a/apps/client/src/stylesheets/theme-next/pages.css +++ b/apps/client/src/stylesheets/theme-next/pages.css @@ -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); diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index 0df9d6686a..1ac2f13e77 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -751,12 +751,14 @@ body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-i } } -#left-pane .fancytree-expander { +#left-pane .fancytree-expander, +.nested-note-list-item .note-expander { opacity: 0.65; transition: opacity 150ms ease-in; } -#left-pane .fancytree-expander:hover { +#left-pane .fancytree-expander:hover, +.nested-note-list-item .note-expander:hover { opacity: 1; transition: opacity 300ms ease-out; } diff --git a/apps/client/src/translations/ar/translation.json b/apps/client/src/translations/ar/translation.json index a4a83179e9..1321d6ebe1 100644 --- a/apps/client/src/translations/ar/translation.json +++ b/apps/client/src/translations/ar/translation.json @@ -1180,9 +1180,6 @@ "note_not_found": "الملاحظة {{noteId}} غير موجودة!", "cannot_match_transform": "تعذر مطابقة التحويل: {{transform}}" }, - "web_view": { - "web_view": "عرض الويب" - }, "consistency_checks": { "title": "فحوصات التناسق" }, diff --git a/apps/client/src/translations/cn/translation.json b/apps/client/src/translations/cn/translation.json index 25012a366f..58ac0f748a 100644 --- a/apps/client/src/translations/cn/translation.json +++ b/apps/client/src/translations/cn/translation.json @@ -1008,7 +1008,7 @@ "no_attachments": "此笔记没有附件。" }, "book": { - "no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 wiki 了解详情。", + "no_children_help": "此集合没有任何子笔记,因此没有内容显示。", "drag_locked_title": "锁定编辑", "drag_locked_message": "无法拖拽,因为集合已被锁定编辑。" }, @@ -1064,15 +1064,6 @@ "default_new_note_title": "新笔记", "click_on_canvas_to_place_new_note": "点击画布以放置新笔记" }, - "render": { - "note_detail_render_help_1": "之所以显示此帮助说明,是因为这个类型为渲染 HTML 的笔记没有正常工作所需的关系。", - "note_detail_render_help_2": "渲染 HTML 笔记类型用于编写脚本。简而言之,您有一份 HTML 代码笔记(可包含一些 JavaScript),然后这个笔记会把页面渲染出来。要使其正常工作,您需要定义一个名为 \"renderNote\" 的关系指向要渲染的 HTML 笔记。" - }, - "web_view": { - "web_view": "网页视图", - "embed_websites": "网页视图类型的笔记允许您将网站嵌入到 Trilium 中。", - "create_label": "首先,请创建一个带有您要嵌入的 URL 地址的标签,例如 #webViewSrc=\"https://www.bing.com\"" - }, "backend_log": { "refresh": "刷新" }, @@ -1421,7 +1412,8 @@ "description": "描述", "reload_app": "重载应用以应用更改", "set_all_to_default": "将所有快捷键重置为默认值", - "confirm_reset": "您确定要将所有键盘快捷键重置为默认值吗?" + "confirm_reset": "您确定要将所有键盘快捷键重置为默认值吗?", + "no_results": "未找到与“{{filter}}”匹配的快捷方式" }, "spellcheck": { "title": "拼写检查", @@ -1622,7 +1614,9 @@ "print_report_title": "打印报告", "print_report_collection_content_other": "集合中的 {{count}} 篇笔记无法打印,因为它们不受支持或受到保护。", "print_report_collection_details_button": "查看详情", - "print_report_collection_details_ignored_notes": "忽略的笔记" + "print_report_collection_details_ignored_notes": "忽略的笔记", + "print_report_error_title": "打印失败", + "print_report_stack_trace": "堆栈跟踪" }, "note_title": { "placeholder": "请输入笔记标题...", @@ -2075,7 +2069,8 @@ "raster": "栅格", "vector_light": "矢量(浅色)", "vector_dark": "矢量(深色)", - "show-scale": "显示比例尺" + "show-scale": "显示比例尺", + "show-labels": "显示标记名称" }, "table_context_menu": { "delete_row": "删除行" @@ -2154,7 +2149,6 @@ "app-restart-required": "(需重启程序以应用更改)" }, "pagination": { - "page_title": "第 {{startIndex}} 页 - 第 {{endIndex}} 页", "total_notes": "{{count}} 篇笔记" }, "collections": { @@ -2268,5 +2262,49 @@ }, "bookmark_buttons": { "bookmarks": "书签" + }, + "web_view_setup": { + "title": "直接在 Trilium 中创建网页的实时视图", + "url_placeholder": "输入或粘贴网站地址,例如 https://triliumnotes.org", + "create_button": "创建网页视图", + "invalid_url_title": "无效的地址", + "invalid_url_message": "请输入有效的网址,例如 https://triliumnotes.org。", + "disabled_description": "此网页视图来自外部来源。为保护您免受网络钓鱼或恶意内容侵害,该视图不会自动加载。若您信任该来源,可手动启用加载功能。", + "disabled_button_enable": "启用网页视图" + }, + "render": { + "setup_title": "在此笔记中显示自定义 HTML 或 Preact JSX", + "setup_create_sample_preact": "使用 Preact 建立范例笔记", + "setup_create_sample_html": "使用 HTML 建立范例笔记", + "setup_sample_created": "已建立一个范例笔记作为子笔记。", + "disabled_description": "此渲染笔记来自外部来源。为保护您免受恶意内容侵害,该功能默认处于禁用状态。启用前请确保您信任该来源。", + "disabled_button_enable": "启用渲染笔记" + }, + "active_content_badges": { + "type_icon_pack": "图标包", + "type_backend_script": "后端脚本", + "type_frontend_script": "前端脚本", + "type_widget": "小部件", + "type_app_css": "自定义 CSS", + "type_render_note": "渲染笔记", + "type_web_view": "网页视图", + "type_app_theme": "自定义主题", + "toggle_tooltip_enable_tooltip": "点击以启用此 {{type}}。", + "toggle_tooltip_disable_tooltip": "点击以禁用此 {{type}}。", + "menu_docs": "打开文档", + "menu_execute_now": "立即执行脚本", + "menu_run": "自动执行", + "menu_run_disabled": "手动", + "menu_run_backend_startup": "当后端启动时", + "menu_run_hourly": "每小时", + "menu_run_daily": "每日", + "menu_run_frontend_startup": "当桌面前端启动时", + "menu_run_mobile_startup": "当移动前端启动时", + "menu_change_to_widget": "更改为小部件", + "menu_change_to_frontend_script": "更改为前端脚本", + "menu_theme_base": "主题基底" + }, + "setup_form": { + "more_info": "了解更多" } } diff --git a/apps/client/src/translations/de/translation.json b/apps/client/src/translations/de/translation.json index a70e627705..9b8abcad8e 100644 --- a/apps/client/src/translations/de/translation.json +++ b/apps/client/src/translations/de/translation.json @@ -1,6 +1,6 @@ { "about": { - "title": "Über Trilium Notizen", + "title": "Über Trilium Notes", "homepage": "Startseite:", "app_version": "App-Version:", "db_version": "DB-Version:", @@ -662,7 +662,8 @@ "show-cheatsheet": "Cheatsheet anzeigen", "toggle-zen-mode": "Zen Modus", "new-version-available": "Neues Update verfügbar", - "download-update": "Version {{latestVersion}} herunterladen" + "download-update": "Version {{latestVersion}} herunterladen", + "search_notes": "Notizen durchsuchen" }, "sync_status": { "unknown": "

Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.

Klicke, um eine Synchronisierung jetzt auszulösen.

", @@ -758,7 +759,8 @@ "error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden", "error_unrecognized_command": "Unbekannter Befehl {{command}}", "note_revisions": "Notiz Revisionen", - "backlinks": "Rücklinks" + "backlinks": "Rücklinks", + "content_language_switcher": "Inhaltssprache: {{language}}" }, "note_icon": { "change_note_icon": "Notiz-Icon ändern", @@ -910,7 +912,8 @@ "unknown_search_option": "Unbekannte Suchoption {{searchOptionName}}", "search_note_saved": "Suchnotiz wurde in {{-notePathTitle}} gespeichert", "actions_executed": "Aktionen wurden ausgeführt.", - "view_options": "Optionen anzeigen:" + "view_options": "Optionen anzeigen:", + "option": "Option" }, "similar_notes": { "title": "Ähnliche Notizen", @@ -1004,7 +1007,7 @@ "no_attachments": "Diese Notiz enthält keine Anhänge." }, "book": { - "no_children_help": "Diese Notiz mit dem Notiztyp Buch besitzt keine Unternotizen, deshalb ist nichts zum Anzeigen vorhanden. Siehe Wiki für mehr Details.", + "no_children_help": "Diese Sammlung enthält keineUnternotizen, daher gibt es nichts anzuzeigen.", "drag_locked_title": "Für Bearbeitung gesperrt", "drag_locked_message": "Das Ziehen ist nicht möglich, da die Sammlung für die Bearbeitung gesperrt ist." }, @@ -1060,15 +1063,6 @@ "default_new_note_title": "neue Notiz", "click_on_canvas_to_place_new_note": "Klicke auf den Canvas, um eine neue Notiz zu platzieren" }, - "render": { - "note_detail_render_help_1": "Diese Hilfesnotiz wird angezeigt, da diese Notiz vom Typ „HTML rendern“ nicht über die erforderliche Beziehung verfügt, um ordnungsgemäß zu funktionieren.", - "note_detail_render_help_2": "Render-HTML-Notiztyp wird benutzt für scripting. Kurzgesagt, du hast ein HTML-Code-Notiz (optional mit JavaScript) und diese Notiz rendert es. Damit es funktioniert, musst du eine a Beziehung namens \"renderNote\" zeigend auf die HTML-Notiz zum rendern definieren." - }, - "web_view": { - "web_view": "Webansicht", - "embed_websites": "Notiz vom Typ Web View ermöglicht das Einbetten von Websites in Trilium.", - "create_label": "Um zu beginnen, erstelle bitte ein Label mit einer URL-Adresse, die eingebettet werden soll, z. B. #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Aktualisieren" }, @@ -1384,7 +1378,8 @@ "description": "Beschreibung", "reload_app": "Lade die App neu, um die Änderungen zu übernehmen", "set_all_to_default": "Setze alle Verknüpfungen auf die Standardeinstellungen", - "confirm_reset": "Möchtest du wirklich alle Tastaturkürzel auf die Standardeinstellungen zurücksetzen?" + "confirm_reset": "Möchtest du wirklich alle Tastaturkürzel auf die Standardeinstellungen zurücksetzen?", + "no_results": "Keine Tastenkürzel für '{{filter}}' gefunden" }, "spellcheck": { "title": "Rechtschreibprüfung", @@ -1588,7 +1583,9 @@ "print_report_collection_details_button": "Details anzeigen", "print_report_collection_details_ignored_notes": "Ignorierte Notizen", "print_report_collection_content_one": "{{count}} Notiz in der Sammlung konnte nicht gedruckt werden, weil sie nicht unterstützt oder geschützt ist.", - "print_report_collection_content_other": "{{count}} Notizen in der Sammlung konnten nicht gedruckt werden, weil sie nicht unterstützt oder geschützt sind." + "print_report_collection_content_other": "{{count}} Notizen in der Sammlung konnten nicht gedruckt werden, weil sie nicht unterstützt oder geschützt sind.", + "print_report_error_title": "Druck fehlgeschlagen", + "print_report_stack_trace": "Stapelzurückverfolgung" }, "note_title": { "placeholder": "Titel der Notiz hier eingeben…", @@ -2089,7 +2086,8 @@ "raster": "Raster", "vector_light": "Vektor (Hell)", "vector_dark": "Vektor (Dunkel)", - "show-scale": "Zeige Skalierung" + "show-scale": "Zeige Skalierung", + "show-labels": "Zeige Markierungsnamen" }, "table_context_menu": { "delete_row": "Zeile entfernen" @@ -2156,7 +2154,6 @@ "percentage": "%" }, "pagination": { - "page_title": "Seite {{startIndex}} von {{endIndex}}", "total_notes": "{{count}} Notizen" }, "collections": { @@ -2277,5 +2274,52 @@ "title_one": "{{count}} Tab", "title_other": "{{count}} Tabs", "more_options": "Weitere Optionen" + }, + "bookmark_buttons": { + "bookmarks": "Lesezeichen" + }, + "web_view_setup": { + "title": "Erstelle eine Live-Ansicht einer Webseite direkt in Trilium", + "url_placeholder": "Gib oder füge die Adresse der Webseite ein, zum Beispiel https://triliumnotes.org", + "create_button": "Erstelle Web Ansicht", + "invalid_url_title": "Ungültige Adresse", + "invalid_url_message": "Füge eine valide Webadresse ein, zum Beispiel https://triliumnotes.org.", + "disabled_description": "Diese Webansicht wurde von einer externen Quelle importiert. Um Sie vor Phishing oder schädlichen Inhalten zu schützen, wird sie nicht automatisch geladen. Sie können sie aktivieren, wenn Sie der Quelle vertrauen.", + "disabled_button_enable": "Webansicht aktivieren" + }, + "render": { + "setup_create_sample_html": "Eine Beispielnotiz mit HTML erstellen", + "setup_create_sample_preact": "Eine Beispielnotiz mit Preact erstellen", + "setup_title": "Benutzerdefiniertes HTML oder Preact JSX in dieser Notiz anzeigen", + "setup_sample_created": "Eine Beispielnotiz wurde als untergeordnete Notiz erstellt.", + "disabled_description": "Diese Rendering-Notizen stammen aus einer externen Quelle. Um Sie vor schädlichen Inhalten zu schützen, ist diese Funktion standardmäßig deaktiviert. Stellen Sie sicher, dass Sie der Quelle vertrauen, bevor Sie sie aktivieren.", + "disabled_button_enable": "Rendering-Notiz aktivieren" + }, + "active_content_badges": { + "type_icon_pack": "Icon-Paket", + "type_backend_script": "Backend-Skript", + "type_frontend_script": "Frontend-Skript", + "type_widget": "Widget", + "type_app_css": "Benutzerdefiniertes CSS", + "type_render_note": "Rendering-Notiz", + "type_web_view": "Webansicht", + "type_app_theme": "Benutzerdefiniertes Thema", + "toggle_tooltip_enable_tooltip": "Klicken, um diesen {{type}} zu aktivieren.", + "toggle_tooltip_disable_tooltip": "Klicken, um diesen {{type}} zu deaktivieren.", + "menu_docs": "Dokumentation öffnen", + "menu_execute_now": "Skript jetzt ausführen", + "menu_run": "Automatisch ausführen", + "menu_run_disabled": "Manuell", + "menu_run_backend_startup": "Wenn das Backend startet", + "menu_run_hourly": "Stündlich", + "menu_run_daily": "Täglich", + "menu_run_frontend_startup": "Wenn das Desktop-Frontend startet", + "menu_run_mobile_startup": "Wenn das mobile Frontend startet", + "menu_change_to_widget": "Zum Widget wechseln", + "menu_change_to_frontend_script": "Zum Frontend-Skript wechseln", + "menu_theme_base": "Themenbasis" + }, + "setup_form": { + "more_info": "Mehr erfahren" } } diff --git a/apps/client/src/translations/el/translation.json b/apps/client/src/translations/el/translation.json index cd1355575d..7512b9e705 100644 --- a/apps/client/src/translations/el/translation.json +++ b/apps/client/src/translations/el/translation.json @@ -13,6 +13,61 @@ "critical-error": { "title": "Κρίσιμο σφάλμα", "message": "Συνέβη κάποιο κρίσιμο σφάλμα, το οποίο δεν επιτρέπει στην εφαρμογή χρήστη να ξεκινήσει:\n\n{{message}}\n\nΤο πιθανότερο είναι να προκλήθηκε από κάποιο script που απέτυχε απρόοπτα. Δοκιμάστε να ξεκινήσετε την εφαρμογή σε ασφαλή λειτουργία για να λύσετε το πρόβλημα." - } + }, + "widget-error": { + "title": "Δεν ήταν δυνατή η αρχικοποίηση του widget", + "message-custom": "Προσαρμοσμένο widget της σημείωσης με ID \"{{id}}\", με τίτλο \"{{title}}\", δεν ήταν δυνατό να αρχικοποιηθεί λόγω:\n\n{{message}}", + "message-unknown": "Άγνωστο widget δεν ήταν δυνατό να αρχικοποιηθεί λόγω:\n\n{{message}}" + }, + "bundle-error": { + "title": "Δεν ήταν δυνατή η φόρτωση προσαρμοσμένου script", + "message": "Το script δεν ήταν δυνατό να εκτελεστεί λόγω:\n\n{{message}}" + }, + "widget-list-error": { + "title": "Δεν ήταν δυνατή η λήψη της λίστας των widgets από τον server" + }, + "widget-render-error": { + "title": "Δεν ήταν δυνατή η απόδοση προσαρμοσμένου React widget" + }, + "widget-missing-parent": "Το προσαρμοσμένο widget δεν έχει ορισμένη την υποχρεωτική ιδιότητα '{{property}}'.\n\nΕάν το script προορίζεται για εκτέλεση χωρίς UI element, χρησιμοποιήστε '#run=frontendStartup' αντί για αυτό.", + "open-script-note": "Άνοιγμα σημείωσης script", + "scripting-error": "Σφάλμα προσαρμοσμένου script: {{title}}" + }, + "bookmark_buttons": { + "bookmarks": "Σελιδοδείκτες" + }, + "add_link": { + "add_link": "Προσθήκη συνδέσμου", + "help_on_links": "Βοήθεια για συνδέσμους", + "note": "Σημείωση", + "search_note": "Αναζήτηση σημείωσης με βάση το όνομά της", + "link_title_mirrors": "Ο τίτλος του συνδέσμου αντικατοπτρίζει τον τρέχοντα τίτλο της σημείωσης", + "link_title_arbitrary": "Ο τίτλος του συνδέσμου μπορεί να τροποποιηθεί ελεύθερα", + "link_title": "Τίτλος συνδέσμου", + "button_add_link": "Προσθήκη συνδέσμου" + }, + "branch_prefix": { + "edit_branch_prefix": "Επεξεργασία προθέματος κλάδου", + "edit_branch_prefix_multiple": "Επεξεργασία προθέματος κλάδου για {{count}} κλάδους", + "help_on_tree_prefix": "Βοήθεια για πρόθεμα δέντρου", + "prefix": "Πρόθεμα: ", + "save": "Αποθήκευση", + "branch_prefix_saved": "Το πρόθεμα κλάδου αποθηκεύτηκε.", + "branch_prefix_saved_multiple": "Το πρόθεμα κλάδου αποθηκεύτηκε για {{count}} κλάδους.", + "affected_branches": "Επηρεαζόμενοι κλάδοι ({{count}}):" + }, + "bulk_actions": { + "bulk_actions": "Μαζικές ενέργειες", + "affected_notes": "Επηρεαζόμενες σημειώσεις", + "include_descendants": "Συμπερίληψη απογόνων των επιλεγμένων σημειώσεων", + "available_actions": "Διαθέσιμες ενέργειες", + "chosen_actions": "Επιλεγμένες ενέργειες", + "execute_bulk_actions": "Εκτέλεση μαζικών ενεργειών", + "bulk_actions_executed": "Οι μαζικές ενέργειες εκτελέστηκαν επιτυχώς.", + "none_yet": "Καμία ακόμη… προσθέστε μια ενέργεια επιλέγοντας μία από τις διαθέσιμες παραπάνω.", + "labels": "Ετικέτες", + "relations": "Συσχετίσεις", + "notes": "Σημειώσεις", + "other": "Λοιπά" } } diff --git a/apps/client/src/translations/en/translation.json b/apps/client/src/translations/en/translation.json index 9f33fd8c35..377a287183 100644 --- a/apps/client/src/translations/en/translation.json +++ b/apps/client/src/translations/en/translation.json @@ -1010,7 +1010,7 @@ "no_attachments": "This note has no attachments." }, "book": { - "no_children_help": "This collection doesn't have any child notes so there's nothing to display. See wiki for details.", + "no_children_help": "This collection doesn't have any child notes so there's nothing to display.", "drag_locked_title": "Locked for editing", "drag_locked_message": "Dragging not allowed since the collection is locked for editing." }, @@ -1067,13 +1067,21 @@ "click_on_canvas_to_place_new_note": "Click on canvas to place new note" }, "render": { - "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 scripting. 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 relation called \"renderNote\" pointing to the HTML note to render." + "setup_title": "Display custom HTML or Preact JSX inside this note", + "setup_create_sample_preact": "Create sample note with Preact", + "setup_create_sample_html": "Create sample note with HTML", + "setup_sample_created": "A sample note was created as a child note.", + "disabled_description": "This render notes comes from an external source. To protect you from malicious content, it is not enabled by default. Make sure you trust the source before enabling it.", + "disabled_button_enable": "Enable render note" }, - "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.", + "disabled_description": "This web view was imported from an external source. To help protect you from phishing or malicious content, it isn’t loading automatically. You can enable it if you trust the source.", + "disabled_button_enable": "Enable web view" }, "backend_log": { "refresh": "Refresh" @@ -1589,7 +1597,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 +1804,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 +2110,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" @@ -2178,8 +2190,9 @@ "percentage": "%" }, "pagination": { - "page_title": "Page of {{startIndex}} - {{endIndex}}", - "total_notes": "{{count}} notes" + "total_notes": "{{count}} notes", + "prev_page": "Previous page", + "next_page": "Next page" }, "collections": { "rendering_error": "Unable to show content due to an error." @@ -2283,5 +2296,32 @@ }, "bookmark_buttons": { "bookmarks": "Bookmarks" + }, + "active_content_badges": { + "type_icon_pack": "Icon pack", + "type_backend_script": "Backend script", + "type_frontend_script": "Frontend script", + "type_widget": "Widget", + "type_app_css": "Custom CSS", + "type_render_note": "Render note", + "type_web_view": "Web view", + "type_app_theme": "Custom theme", + "toggle_tooltip_enable_tooltip": "Click to enable this {{type}}.", + "toggle_tooltip_disable_tooltip": "Click to disable this {{type}}.", + "menu_docs": "Open documentation", + "menu_execute_now": "Execute script now", + "menu_run": "Run automatically", + "menu_run_disabled": "Manually", + "menu_run_backend_startup": "When the backend starts up", + "menu_run_hourly": "Hourly", + "menu_run_daily": "Daily", + "menu_run_frontend_startup": "When the desktop frontend starts up", + "menu_run_mobile_startup": "When the mobile frontend starts up", + "menu_change_to_widget": "Change to widget", + "menu_change_to_frontend_script": "Change to frontend script", + "menu_theme_base": "Theme base" + }, + "setup_form": { + "more_info": "Learn more" } } diff --git a/apps/client/src/translations/es/translation.json b/apps/client/src/translations/es/translation.json index ccad034294..7dbbd15447 100644 --- a/apps/client/src/translations/es/translation.json +++ b/apps/client/src/translations/es/translation.json @@ -662,7 +662,8 @@ "show-cheatsheet": "Mostrar hoja de trucos", "toggle-zen-mode": "Modo Zen", "new-version-available": "Nueva actualización disponible", - "download-update": "Obtener versión {{latestVersion}}" + "download-update": "Obtener versión {{latestVersion}}", + "search_notes": "Buscar notas" }, "zen_mode": { "button_exit": "Salir del modo Zen" @@ -762,7 +763,8 @@ "error_cannot_get_branch_id": "No se puede obtener el branchID del notePath '{{notePath}}'", "error_unrecognized_command": "Comando no reconocido {{command}}", "note_revisions": "Revisiones de notas", - "backlinks": "Vínculos de retroceso" + "backlinks": "Vínculos de retroceso", + "content_language_switcher": "Idioma de contenido: {{language}}" }, "note_icon": { "change_note_icon": "Cambiar icono de nota", @@ -915,7 +917,8 @@ "unknown_search_option": "Opción de búsqueda desconocida {{searchOptionName}}", "search_note_saved": "La nota de búsqueda se ha guardado en {{- notePathTitle}}", "actions_executed": "Las acciones han sido ejecutadas.", - "view_options": "Ver opciones:" + "view_options": "Ver opciones:", + "option": "opción" }, "similar_notes": { "title": "Notas similares", @@ -1065,15 +1068,6 @@ "default_new_note_title": "nueva nota", "click_on_canvas_to_place_new_note": "Haga clic en el lienzo para colocar una nueva nota" }, - "render": { - "note_detail_render_help_1": "Esta nota de ayuda se muestra porque esta nota de tipo Renderizar HTML no tiene la relación requerida para funcionar correctamente.", - "note_detail_render_help_2": "El tipo de nota Render HTML es usado para scripting. De forma resumida, tiene una nota con código HTML (opcionalmente con algo de JavaScript) y esta nota la renderizará. Para que funcione, es necesario definir una relación llamada \"renderNote\" apuntando a la nota HTML nota a renderizar." - }, - "web_view": { - "web_view": "Vista web", - "embed_websites": "La nota de tipo Web View le permite insertar sitios web en Trilium.", - "create_label": "Para comenzar, por favor cree una etiqueta con una dirección URL que desee empotrar, e.g. #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Refrescar" }, @@ -1574,7 +1568,8 @@ "description": "Descripción", "reload_app": "Vuelva a cargar la aplicación para aplicar los cambios", "set_all_to_default": "Establecer todos los accesos directos al valor predeterminado", - "confirm_reset": "¿Realmente desea restablecer todos los atajos de teclado a sus valores predeterminados?" + "confirm_reset": "¿Realmente desea restablecer todos los atajos de teclado a sus valores predeterminados?", + "no_results": "No se encontraron atajos que coincidan con '{{filter}} '" }, "spellcheck": { "title": "Revisión ortográfica", @@ -1781,7 +1776,9 @@ "print_report_collection_content_other": "{{count}} notas en la colección no se pueden imprimir porque no son compatibles o están protegidas.", "print_report_title": "Imprimir informe", "print_report_collection_details_button": "Ver detalles", - "print_report_collection_details_ignored_notes": "Notas ignoradas" + "print_report_collection_details_ignored_notes": "Notas ignoradas", + "print_report_stack_trace": "Rastreo de pila", + "print_report_error_title": "Fallo al imprimir" }, "note_title": { "placeholder": "escriba el título de la nota aquí...", @@ -2161,8 +2158,7 @@ "percentage": "%" }, "pagination": { - "total_notes": "{{count}} notas", - "page_title": "Página de {{startIndex}} - {{endIndex}}" + "total_notes": "{{count}} notas" }, "presentation_view": { "edit-slide": "Editar este slide", @@ -2292,5 +2288,52 @@ "title_many": "{{count}} pestañas", "title_other": "{{count}} pestañas", "more_options": "Más opciones" + }, + "bookmark_buttons": { + "bookmarks": "Marcadores" + }, + "web_view_setup": { + "title": "Crear una vista en vivo de una página web directamente en Trilium", + "url_placeholder": "Ingresar o pegar la dirección del sitio web, por ejemplo https://triliumnotes.org", + "create_button": "Crear Vista Web", + "invalid_url_title": "Dirección inválida", + "invalid_url_message": "Ingrese una dirección web válida, por ejemplo https://triliumnotes.org.", + "disabled_description": "Esta vista web fue importada de una fuente externa. Para ayudarlo a protegerse del phishing o el contenido malicioso, no se está cargando automáticamente. Puede activarlo si confía en la fuente.", + "disabled_button_enable": "Habilita vista web" + }, + "render": { + "setup_title": "Mostrar HTML personalizado o Preact JSX dentro de esta nota", + "setup_create_sample_preact": "Crear nota de muestra con Preact", + "setup_create_sample_html": "Crear nota de muestra con HTML", + "setup_sample_created": "Se creó una nota de muestra como subnota.", + "disabled_description": "Esta nota de renderización proviene de una fuente externa. Para protegerlo de contenido malicioso, no está habilitado por defecto. Asegúrese de confiar en la fuente antes de habilitarla.", + "disabled_button_enable": "Habilitar nota de renderización" + }, + "active_content_badges": { + "type_icon_pack": "Paquete de iconos", + "type_backend_script": "Script de backend", + "type_frontend_script": "Script de frontend", + "type_widget": "Widget", + "type_app_css": "CSS personalizado", + "type_render_note": "Nota de renderización", + "type_web_view": "Vista web", + "type_app_theme": "Tema personalizado", + "toggle_tooltip_enable_tooltip": "Haga clic para habilitar este {{type}}.", + "toggle_tooltip_disable_tooltip": "Haga clic para deshabilitar este {{type}}.", + "menu_docs": "Abrir documentación", + "menu_execute_now": "Ejecutar script ahora", + "menu_run": "Ejecutar automáticamente", + "menu_run_disabled": "Manualmente", + "menu_run_backend_startup": "Cuando el backend inicia", + "menu_run_hourly": "Cada hora", + "menu_run_daily": "Diariamente", + "menu_run_frontend_startup": "Cuando el frontend de escritorio inicia", + "menu_run_mobile_startup": "Cuando el frontend móvil inicia", + "menu_change_to_widget": "Cambiar a widget", + "menu_change_to_frontend_script": "Cambiar a script de frontend", + "menu_theme_base": "Tema base" + }, + "setup_form": { + "more_info": "Para saber más" } } diff --git a/apps/client/src/translations/fr/translation.json b/apps/client/src/translations/fr/translation.json index 2900c5de56..69b4eee16a 100644 --- a/apps/client/src/translations/fr/translation.json +++ b/apps/client/src/translations/fr/translation.json @@ -1053,15 +1053,6 @@ "default_new_note_title": "nouvelle note", "click_on_canvas_to_place_new_note": "Cliquez sur le canevas pour placer une nouvelle note" }, - "render": { - "note_detail_render_help_1": "Cette note d'aide s'affiche car cette note de type Rendu HTML n'a pas la relation requise pour fonctionner correctement.", - "note_detail_render_help_2": "Le type de note Rendu HTML est utilisé pour les scripts. En résumé, vous disposez d'une note de code HTML (éventuellement contenant JavaScript) et cette note affichera le rendu. Pour que cela fonctionne, vous devez définir une relation appelée \"renderNote\" pointant vers la note HTML à rendre." - }, - "web_view": { - "web_view": "Affichage Web", - "embed_websites": "Les notes de type Affichage Web vous permet d'intégrer des sites Web dans Trilium.", - "create_label": "Pour commencer, veuillez créer un label avec l'adresse URL que vous souhaitez intégrer, par ex. #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Rafraîchir" }, @@ -2058,7 +2049,6 @@ "percentage": "%" }, "pagination": { - "page_title": "Page de {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} notes" }, "collections": { diff --git a/apps/client/src/translations/ga/translation.json b/apps/client/src/translations/ga/translation.json index 4d1ccf8f0d..5592c8f3a9 100644 --- a/apps/client/src/translations/ga/translation.json +++ b/apps/client/src/translations/ga/translation.json @@ -27,7 +27,8 @@ "show-cheatsheet": "Taispeáin Bileog leideanna", "toggle-zen-mode": "Mód Zen", "new-version-available": "Nuashonrú Nua ar Fáil", - "download-update": "Faigh Leagan {{latestVersion}}" + "download-update": "Faigh Leagan {{latestVersion}}", + "search_notes": "Cuardaigh nótaí" }, "about": { "title": "Maidir le Trilium Notes", @@ -441,7 +442,7 @@ "share_index": "liostálfaidh nóta leis an lipéad seo fréamhacha uile nótaí comhroinnte", "display_relations": "Ainmneacha caidrimh scartha le camóga ar cheart iad a thaispeáint. Beidh na cinn eile go léir i bhfolach.", "hide_relations": "Ainmneacha caidrimh scartha le camóga ar cheart iad a cheilt. Taispeánfar na cinn eile go léir.", - "title_template": "Teideal réamhshocraithe nótaí a cruthaíodh mar leanaí den nóta seo. Déantar an luach a mheas mar theaghrán JavaScript\n agus dá bhrí sin is féidir é a shaibhriú le hábhar dinimiciúil trí na hathróga now agus parentNote insteallta. Samplaí:\n\n
    \n
  • Saothair liteartha ${parentNote.getLabelValue('authorName')}
  • \n
  • Log le haghaidh ${now.format('YYYY-MM-DD HH:mm:ss')}
  • \n
\n\nFéach vicí le sonraí, doiciméid API le haghaidh parentNote agus now le haghaidh sonraí.", + "title_template": "teideal réamhshocraithe nótaí a cruthaíodh mar leanaí den nóta seo. Déantar an luach a mheas mar theaghrán JavaScript \n agus dá bhrí sin is féidir é a shaibhriú le hábhar dinimiciúil trí na hathróga now agus parentNote insteallta. Samplaí:\n \n
    \n
  • Saothair liteartha ${parentNote.getLabelValue('authorName')}
  • \n
  • Log le haghaidh ${now.format('YYYY-MM-DD HH:mm:ss')}
  • \n
\n \n Féach vicí le sonraí, doiciméid API le haghaidh parentNote agus now le haghaidh sonraí.", "template": "Beidh an nóta seo le feiceáil i roghnú na dteimpléad atá ar fáil agus nóta nua á chruthú", "toc": "Cuirfidh #toc#toc=show iallach ar an gClár Ábhair a bheith le feiceáil, cuirfidh #toc=hide iallach air é a cheilt. Mura bhfuil an lipéad ann, breathnaítear ar an socrú domhanda", "color": "sainmhíníonn dath an nóta sa chrann nótaí, snaisc srl. Úsáid aon luach datha CSS bailí cosúil le 'dearg' nó #a13d5f", @@ -764,7 +765,8 @@ "note_revisions": "Athbhreithnithe nóta", "error_cannot_get_branch_id": "Ní féidir aitheantas brainse a fháil do NotePad '{{notePath}}'", "error_unrecognized_command": "Ordú gan aitheantas {{command}}", - "backlinks": "Naisc ar ais" + "backlinks": "Naisc ar ais", + "content_language_switcher": "Teanga an ábhair: {{language}}" }, "note_icon": { "change_note_icon": "Deilbhín nóta athraithe", @@ -919,7 +921,8 @@ "unknown_search_option": "Rogha cuardaigh anaithnid {{searchOptionName}}", "search_note_saved": "Tá an nóta cuardaigh sábháilte i {{- notePathTitle}}", "actions_executed": "Tá gníomhartha curtha i gcrích.", - "view_options": "Roghanna féachana:" + "view_options": "Roghanna féachana:", + "option": "rogha" }, "similar_notes": { "title": "Nótaí Comhchosúla", @@ -1013,7 +1016,7 @@ "no_attachments": "Níl aon cheangaltáin leis an nóta seo." }, "book": { - "no_children_help": "Níl aon nótaí faoi mhíbhuntáiste sa bhailiúchán seo mar sin níl aon rud le taispeáint. Féach ar an vicí le haghaidh tuilleadh sonraí.", + "no_children_help": "Níl aon nótaí faoi mhíbhuntáiste sa bhailiúchán seo mar sin níl aon rud le taispeáint.", "drag_locked_title": "Glasáilte le haghaidh eagarthóireachta", "drag_locked_message": "Ní cheadaítear tarraingt ós rud é go bhfuil an bailiúchán faoi ghlas le haghaidh eagarthóireachta." }, @@ -1069,15 +1072,6 @@ "default_new_note_title": "nóta nua", "click_on_canvas_to_place_new_note": "Cliceáil ar chanbhás chun nóta nua a chur" }, - "render": { - "note_detail_render_help_1": "Taispeántar an nóta cabhrach seo mar nach bhfuil aon ghaol riachtanach ag an nóta seo den chineál Render HTML le go bhfeidhmeoidh sé i gceart.", - "note_detail_render_help_2": "Úsáidtear cineál nóta HTML rindreála le haghaidh scriptithe. Go hachomair, tá nóta cóid HTML agat (le roinnt JavaScript más féidir) agus déanfaidh an nóta seo é a rindreáil. Chun go n-oibreoidh sé, ní mór duit gaol ar a dtugtar \"renderNote\" a shainiú ag pointeáil chuig an nóta HTML atá le rindreáil." - }, - "web_view": { - "web_view": "Radharc Gréasáin", - "embed_websites": "Nóta den chineál Gréasáin a ligeann duit suíomhanna gréasáin a leabú i Trilium.", - "create_label": "Chun tús a chur leis, cruthaigh lipéad le seoladh URL ar mhaith leat a leabú, m.sh. #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Athnuachan" }, @@ -1592,7 +1586,8 @@ "description": "Cur síos", "reload_app": "Athlódáil an aip chun na hathruithe a chur i bhfeidhm", "set_all_to_default": "Socraigh gach aicearra go dtí an réamhshocrú", - "confirm_reset": "An bhfuil tú cinnte gur mhaith leat na haicearraí méarchláir go léir a athshocrú go dtí an rogha réamhshocraithe?" + "confirm_reset": "An bhfuil tú cinnte gur mhaith leat na haicearraí méarchláir go léir a athshocrú go dtí an rogha réamhshocraithe?", + "no_results": "Níor aimsíodh aon aicearraí a mheaitseálann '{{filter}}'" }, "spellcheck": { "title": "Seiceáil Litrithe", @@ -1810,7 +1805,9 @@ "print_report_collection_content_many": "Níorbh fhéidir {{count}} nótaí sa bhailiúchán a phriontáil mar nach dtacaítear leo nó mar go bhfuil siad faoi chosaint.", "print_report_collection_content_other": "Níorbh fhéidir {{count}} nótaí sa bhailiúchán a phriontáil mar nach dtacaítear leo nó mar go bhfuil siad faoi chosaint.", "print_report_collection_details_button": "Féach sonraí", - "print_report_collection_details_ignored_notes": "Nótaí neamhairdithe" + "print_report_collection_details_ignored_notes": "Nótaí neamhairdithe", + "print_report_error_title": "Theip ar phriontáil", + "print_report_stack_trace": "Rian cruachta" }, "note_title": { "placeholder": "clóscríobh teideal an nóta anseo...", @@ -2111,7 +2108,8 @@ "raster": "Raster", "vector_light": "Veicteoir (Solas)", "vector_dark": "Veicteoir (Dorcha)", - "show-scale": "Taispeáin scála" + "show-scale": "Taispeáin scála", + "show-labels": "Taispeáin ainmneacha marcóirí" }, "table_context_menu": { "delete_row": "Scrios an tsraith" @@ -2190,8 +2188,9 @@ "percentage": "%" }, "pagination": { - "page_title": "Leathanach de {{startIndex}} - {{endIndex}}", - "total_notes": "{{count}} nótaí" + "total_notes": "{{count}} nótaí", + "prev_page": "Leathanach roimhe seo", + "next_page": "An chéad leathanach eile" }, "collections": { "rendering_error": "Ní féidir ábhar a thaispeáint mar gheall ar earráid." @@ -2322,5 +2321,52 @@ "title_many": "{{count}} cluaisíní", "title_other": "{{count}} cluaisíní", "more_options": "Tuilleadh roghanna" + }, + "bookmark_buttons": { + "bookmarks": "Leabharmharcanna" + }, + "web_view_setup": { + "title": "Cruthaigh radharc beo de leathanach gréasáin go díreach isteach i Trilium", + "url_placeholder": "Cuir isteach nó greamaigh seoladh an tsuímh ghréasáin, mar shampla https://triliumnotes.org", + "create_button": "Cruthaigh Radharc Gréasáin", + "invalid_url_title": "Seoladh neamhbhailí", + "invalid_url_message": "Cuir isteach seoladh gréasáin bailí, mar shampla https://triliumnotes.org.", + "disabled_description": "Iompórtáladh an radharc gréasáin seo ó fhoinse sheachtrach. Chun cabhrú leat a chosaint ar ábhar fioscaireachta nó mailíseach, níl sé ag lódáil go huathoibríoch. Is féidir leat é a chumasú má tá muinín agat as an bhfoinse.", + "disabled_button_enable": "Cumasaigh radharc gréasáin" + }, + "render": { + "setup_title": "Taispeáin HTML saincheaptha nó Preact JSX taobh istigh den nóta seo", + "setup_create_sample_preact": "Cruthaigh nóta samplach le Preact", + "setup_create_sample_html": "Cruthaigh nóta samplach le HTML", + "setup_sample_created": "Cruthaíodh nóta samplach mar nóta linbh.", + "disabled_description": "Tagann na nótaí rindreála seo ó fhoinse sheachtrach. Chun tú a chosaint ar ábhar mailíseach, níl sé cumasaithe de réir réamhshocraithe. Déan cinnte go bhfuil muinín agat as an bhfoinse sula gcumasaíonn tú é.", + "disabled_button_enable": "Cumasaigh nóta rindreála" + }, + "active_content_badges": { + "type_icon_pack": "Pacáiste deilbhín", + "type_backend_script": "Script chúltaca", + "type_frontend_script": "Script tosaigh", + "type_widget": "Giuirléid", + "type_app_css": "CSS saincheaptha", + "type_render_note": "Nóta rindreála", + "type_web_view": "Radharc gréasáin", + "type_app_theme": "Téama saincheaptha", + "toggle_tooltip_enable_tooltip": "Cliceáil chun an {{type}} seo a chumasú.", + "toggle_tooltip_disable_tooltip": "Cliceáil chun an {{type}} seo a dhíchumasú.", + "menu_docs": "Doiciméadú oscailte", + "menu_execute_now": "Rith an script anois", + "menu_run": "Rith go huathoibríoch", + "menu_run_disabled": "De láimh", + "menu_run_backend_startup": "Nuair a thosaíonn an cúltaca", + "menu_run_hourly": "Gach uair an chloig", + "menu_run_daily": "Laethúil", + "menu_run_frontend_startup": "Nuair a thosaíonn tosaigh an deisce", + "menu_run_mobile_startup": "Nuair a thosaíonn an taobhlíne soghluaiste", + "menu_change_to_widget": "Athraigh go giuirléid", + "menu_change_to_frontend_script": "Athraigh chuig an script tosaigh", + "menu_theme_base": "Bunús téama" + }, + "setup_form": { + "more_info": "Foghlaim níos mó" } } diff --git a/apps/client/src/translations/id/translation.json b/apps/client/src/translations/id/translation.json index 930eecf5e5..157f406053 100644 --- a/apps/client/src/translations/id/translation.json +++ b/apps/client/src/translations/id/translation.json @@ -50,7 +50,8 @@ "save": "Simpan", "branch_prefix_saved": "Prefiks cabang telah disimpan.", "branch_prefix_saved_multiple": "Prefix cabang telah disimpan pada {{count}} cabang.", - "affected_branches": "Cabang terdampak ({{count}}):" + "affected_branches": "Cabang terdampak ({{count}}):", + "edit_branch_prefix": "Sunting awalan cabang" }, "bulk_actions": { "bulk_actions": "Aksi borongan", @@ -61,14 +62,18 @@ "execute_bulk_actions": "Eksekusi aksi borongan", "bulk_actions_executed": "Aksi borongan telah di eksekusi dengan sukses.", "none_yet": "Belum ada... tambahkan aksi dengan memilih salah satu dari aksi di atas.", - "labels": "Label-label" + "labels": "Label-label", + "relations": "Hubungan", + "notes": "Catatan", + "other": "Lainnya" }, "confirm": { "cancel": "Batal", "ok": "Oke", "are_you_sure_remove_note": "Apakah anda yakin mau membuang catatan \"{{title}}\" dari peta relasi? ", "if_you_dont_check": "Jika Anda tidak mencentang ini, catatan hanya akan dihapus dari peta relasi.", - "also_delete_note": "Hapus juga catatannya" + "also_delete_note": "Hapus juga catatannya", + "confirmation": "Konfirmasi" }, "delete_notes": { "delete_notes_preview": "Hapus pratinjau catatan", @@ -77,9 +82,19 @@ "erase_notes_description": "Penghapusan normal hanya menandai catatan sebagai dihapus dan dapat dipulihkan (melalui dialog versi revisi) dalam jangka waktu tertentu. Mencentang opsi ini akan menghapus catatan secara permanen seketika dan catatan tidak akan bisa dipulihkan kembali.", "erase_notes_warning": "Hapus catatan secara permanen (tidak bisa dikembalikan), termasuk semua duplikat. Aksi akan memaksa aplikasi untuk mengulang kembali.", "notes_to_be_deleted": "Catatan-catatan berikut akan dihapuskan ({{notesCount}})", - "no_note_to_delete": "Tidak ada Catatan yang akan dihapus (hanya duplikat)." + "no_note_to_delete": "Tidak ada Catatan yang akan dihapus (hanya duplikat).", + "broken_relations_to_be_deleted": "Hubungan berikut akan diputus dan dihapus ({{ relationCount}})" }, "clone_to": { - "clone_notes_to": "Duplikat catatan ke…" + "clone_notes_to": "Duplikat catatan ke…", + "help_on_links": "Bantuan pada tautan", + "notes_to_clone": "Catatan untuk kloning", + "target_parent_note": "Sasaran catatan utama", + "search_for_note_by_its_name": "cari catatan berdasarkan namanya", + "cloned_note_prefix_title": "Catatan yang dikloning akan ditampilkan diruntutan catatan dengan awalan yang diberikan", + "prefix_optional": "Awalan (opsional)", + "clone_to_selected_note": "Salin ke catatan yang dipilih", + "no_path_to_clone_to": "Tidak ada jalur untuk digandakan.", + "note_cloned": "Catatan \"{{clonedTitle}}\" telah digandakan ke dalam \"{{targetTitle}}\"" } } diff --git a/apps/client/src/translations/it/translation.json b/apps/client/src/translations/it/translation.json index 89e44794c1..f24d449fcb 100644 --- a/apps/client/src/translations/it/translation.json +++ b/apps/client/src/translations/it/translation.json @@ -167,8 +167,8 @@ "desktop-application": "Applicazione Desktop", "native-title-bar": "Barra del titolo nativa", "native-title-bar-description": "Su Windows e macOS, disattivare la barra del titolo nativa rende l'applicazione più compatta. Su Linux, attivarla si integra meglio con il resto del sistema.", - "background-effects": "Abilita effetti di sfondo (solo Windows 11)", - "background-effects-description": "L'effetto Mica aggiunge uno sfondo sfocato ed elegante alle finestre delle app, creando profondità e un aspetto moderno. La \"Barra del titolo nativa\" deve essere disattivata.", + "background-effects": "Abilita effetti di sfondo", + "background-effects-description": "Aggiunge uno sfondo sfocato ed elegante alle finestre dell'app, creando profondità e un look moderno. La \"barra del titolo nativa\" deve essere disabilitata.", "restart-app-button": "Riavviare l'applicazione per visualizzare le modifiche" }, "note_autocomplete": { @@ -186,7 +186,8 @@ "geo-map": { "create-child-note-title": "Crea una nota figlia e aggiungila alla mappa", "create-child-note-instruction": "Clicca sulla mappa per creare una nuova nota qui o premi Escape per uscire.", - "unable-to-load-map": "Impossibile caricare la mappa." + "unable-to-load-map": "Impossibile caricare la mappa.", + "create-child-note-text": "Aggiungi indicatore" }, "geo-map-context": { "open-location": "Apri la posizione", @@ -368,7 +369,8 @@ "description": "Descrizione", "reload_app": "Ricarica l'app per applicare le modifiche", "set_all_to_default": "Imposta tutte le scorciatoie sui valori predefiniti", - "confirm_reset": "Vuoi davvero ripristinare tutte le scorciatoie da tastiera ai valori predefiniti?" + "confirm_reset": "Vuoi davvero ripristinare tutte le scorciatoie da tastiera ai valori predefiniti?", + "no_results": "Nessuna scorciatoia trovata corrispondente '{{filter}}'" }, "shared_switch": { "toggle-on-title": "Condividi la nota", @@ -422,7 +424,8 @@ "unknown_search_option": "Opzione di ricerca sconosciuta {{searchOptionName}}", "search_note_saved": "La nota di ricerca è stata salvata in {{- notePathTitle}}", "actions_executed": "Le azioni sono state eseguite.", - "view_options": "Opzioni di visualizzazione:" + "view_options": "Opzioni di visualizzazione:", + "option": "opzione" }, "modal": { "close": "Chiudi", @@ -1241,7 +1244,8 @@ "show-cheatsheet": "Mostra il foglietto illustrativo", "toggle-zen-mode": "Modalità Zen", "new-version-available": "Nuovo aggiornamento disponibile", - "download-update": "Ottieni la versione {{latestVersion}}" + "download-update": "Ottieni la versione {{latestVersion}}", + "search_notes": "Cerca note" }, "zen_mode": { "button_exit": "Esci dalla modalità Zen" @@ -1324,7 +1328,7 @@ "button_title": "Esporta diagramma come SVG" }, "relation_map_buttons": { - "create_child_note_title": "Crea una nuova nota secondaria e aggiungila a questa mappa delle relazioni", + "create_child_note_title": "Crea una nota secondaria e aggiungila alla mappa", "reset_pan_zoom_title": "Ripristina panoramica e zoom alle coordinate e all'ingrandimento iniziali", "zoom_in_title": "Ingrandisci", "zoom_out_title": "Rimpicciolisci" @@ -1340,7 +1344,9 @@ "delete_this_note": "Elimina questa nota", "note_revisions": "Revisioni delle note", "error_cannot_get_branch_id": "Impossibile ottenere branchId per notePath '{{notePath}}'", - "error_unrecognized_command": "Comando non riconosciuto {{command}}" + "error_unrecognized_command": "Comando non riconosciuto {{command}}", + "backlinks": "Backlinks", + "content_language_switcher": "Lingua dei contenuti: {{language}}" }, "note_icon": { "change_note_icon": "Cambia icona nota", @@ -1521,7 +1527,7 @@ "no_attachments": "Questa nota non ha allegati." }, "book": { - "no_children_help": "Questa raccolta non ha note secondarie, quindi non c'è nulla da visualizzare. Consulta la wiki per i dettagli.", + "no_children_help": "Questa raccolta non ha note secondarie, quindi non c'è nulla da visualizzare.", "drag_locked_title": "Bloccato per la modifica", "drag_locked_message": "Trascinamento non consentito poiché la raccolta è bloccata per la modifica." }, @@ -1577,15 +1583,6 @@ "default_new_note_title": "nuova nota", "click_on_canvas_to_place_new_note": "Clicca sulla tela per inserire una nuova nota" }, - "render": { - "note_detail_render_help_1": "Questa nota di aiuto viene visualizzata perché questa nota di tipo Render HTML non ha la relazione richiesta per funzionare correttamente.", - "note_detail_render_help_2": "Il tipo di nota HTML Render viene utilizzato per lo scripting. In breve, si ottiene una nota in codice HTML (opzionalmente con un po' di JavaScript) che verrà visualizzata. Per farla funzionare, è necessario definire una relazione denominata \"renderNote\" che punti alla nota HTML da visualizzare." - }, - "web_view": { - "web_view": "Visualizzazione Web", - "embed_websites": "La nota di tipo Web View consente di incorporare siti web in Trilium.", - "create_label": "Per iniziare, crea un'etichetta con l'indirizzo URL che desideri incorporare, ad esempio #webViewSrc=\"https://www.google.com\"" - }, "vacuum_database": { "title": "Pulizia del database", "description": "Questa operazione ricostruirà il database, generando in genere un file di dimensioni inferiori. In realtà, nessun dato verrà modificato.", @@ -1923,7 +1920,9 @@ "print_report_collection_content_many": "{{count}} le note nella raccolta non possono essere stampate perché non sono supportate o sono protette.", "print_report_collection_content_other": "{{count}} le note nella raccolta non possono essere stampate perché non sono supportate o sono protette.", "print_report_collection_details_button": "Vedi dettagli", - "print_report_collection_details_ignored_notes": "Note ignorate" + "print_report_collection_details_ignored_notes": "Note ignorate", + "print_report_error_title": "Impossibile stampare", + "print_report_stack_trace": "Traccia dello stack" }, "note_title": { "placeholder": "scrivi qui il titolo della nota...", @@ -2110,7 +2109,8 @@ "raster": "Trama", "vector_light": "Vettore (Luce)", "vector_dark": "Vettore (scuro)", - "show-scale": "Mostra scala" + "show-scale": "Mostra scala", + "show-labels": "Mostra nomi dei marcatori" }, "table_context_menu": { "delete_row": "Elimina riga" @@ -2143,9 +2143,9 @@ "next_theme_message": "Al momento stai utilizzando il tema legacy. Vuoi provare il nuovo tema?", "next_theme_button": "Prova il nuovo tema", "background_effects_title": "Gli effetti di sfondo sono ora stabili", - "background_effects_message": "Sui dispositivi Windows, gli effetti di sfondo sono ora completamente stabili. Gli effetti di sfondo aggiungono un tocco di colore all'interfaccia utente sfocando lo sfondo retrostante. Questa tecnica è utilizzata anche in altre applicazioni come Esplora risorse di Windows.", + "background_effects_message": "Su dispositivi Windows e macOS, gli effetti di sfondo sono ora stabili. Gli effetti di sfondo aggiungono un tocco di colore all'interfaccia utente sfocando lo sfondo dietro di essa.", "background_effects_button": "Abilita gli effetti di sfondo", - "dismiss": "Congedare", + "dismiss": "Chiudi", "new_layout_title": "Nuovo layout", "new_layout_message": "Abbiamo introdotto un layout modernizzato per Trilium. La barra multifunzione è stata rimossa e integrata perfettamente nell'interfaccia principale, con una nuova barra di stato e sezioni espandibili (come gli attributi promossi) che assumono le funzioni chiave.\n\nIl nuovo layout è abilitato di default e può essere temporaneamente disabilitato tramite Opzioni → Aspetto.", "new_layout_button": "Maggiori informazioni" @@ -2164,7 +2164,6 @@ "percentage": "%" }, "pagination": { - "page_title": "Pagina di {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} note" }, "collections": { @@ -2281,5 +2280,61 @@ "pages_other": "{{count}} pagine", "pages_alt": "Pagina {{pageNumber}}", "pages_loading": "Caricamento in corso..." + }, + "web_view_setup": { + "title": "Crea una visualizzazione live di una pagina web direttamente in Trilium", + "url_placeholder": "Inserisci o incolla l'indirizzo del sito web, ad esempio https://triliumnotes.org", + "create_button": "Crea vista Web", + "invalid_url_title": "Indirizzo non valido", + "invalid_url_message": "Inserisci un indirizzo web valido, ad esempio https://triliumnotes.org.", + "disabled_description": "Questa visualizzazione web è stata importata da una fonte esterna. Per proteggerti dal phishing o da contenuti dannosi, non viene caricata automaticamente. Puoi abilitarla se ritieni che la fonte sia affidabile.", + "disabled_button_enable": "Abilita visualizzazione web" + }, + "platform_indicator": { + "available_on": "Disponibile su {{platform}}" + }, + "mobile_tab_switcher": { + "title_one": "Scheda {{count}}", + "title_many": "Schede {{count}}", + "title_other": "Schede {{count}}", + "more_options": "Altre opzioni" + }, + "bookmark_buttons": { + "bookmarks": "Segnalibri" + }, + "render": { + "setup_title": "Visualizza HTML personalizzato o Preact JSX all'interno di questa nota", + "setup_create_sample_preact": "Crea una nota di esempio con Preact", + "setup_create_sample_html": "Crea una nota di esempio con HTML", + "setup_sample_created": "È stata creata una nota di esempio come nota secondaria.", + "disabled_description": "Queste note di rendering provengono da una fonte esterna. Per proteggerti da contenuti dannosi, non sono abilitate per impostazione predefinita. Assicurati di fidarti della fonte prima di abilitarle.", + "disabled_button_enable": "Abilita nota di rendering" + }, + "active_content_badges": { + "type_icon_pack": "Pacchetto icone", + "type_backend_script": "Script di backend", + "type_frontend_script": "Script frontend", + "type_widget": "Widget", + "type_app_css": "CSS personalizzato", + "type_render_note": "Nota di rendering", + "type_web_view": "Visualizzazione web", + "type_app_theme": "Tema personalizzato", + "toggle_tooltip_enable_tooltip": "Clicca per abilitare questa funzione {{type}}.", + "toggle_tooltip_disable_tooltip": "Clicca per disattivare questa funzione {{type}}.", + "menu_docs": "Documentazione aperta", + "menu_execute_now": "Esegui lo script ora", + "menu_run": "Esegui automaticamente", + "menu_run_disabled": "Manualmente", + "menu_run_backend_startup": "Quando il backend si avvia", + "menu_run_hourly": "Ogni ora", + "menu_run_daily": "Giornaliero", + "menu_run_frontend_startup": "Quando si avvia il frontend desktop", + "menu_run_mobile_startup": "Quando si avvia il frontend mobile", + "menu_change_to_widget": "Passa al widget", + "menu_change_to_frontend_script": "Modifica allo script frontend", + "menu_theme_base": "Tema base" + }, + "setup_form": { + "more_info": "Per saperne di più" } } diff --git a/apps/client/src/translations/ja/translation.json b/apps/client/src/translations/ja/translation.json index 4b8d34b5a5..618166ad00 100644 --- a/apps/client/src/translations/ja/translation.json +++ b/apps/client/src/translations/ja/translation.json @@ -249,7 +249,8 @@ "reload_app": "リロードして変更を適用する", "set_all_to_default": "すべてのショートカットをデフォルトに戻す", "confirm_reset": "キーボードショートカットをすべてデフォルトにリセットしますか?", - "keyboard_shortcuts": "キーボードショートカット" + "keyboard_shortcuts": "キーボードショートカット", + "no_results": "'{{filter}}' に一致するショートカットが見つかりません" }, "confirm": { "confirmation": "確認", @@ -826,11 +827,6 @@ "error_no_path": "移動するパスがありません。", "move_success_message": "選択したノートは以下に移動されました " }, - "web_view": { - "web_view": "Web ビュー", - "embed_websites": "Web ビュータイプでは、web サイトを Trilium に埋め込むことができます。", - "create_label": "まず始めに、埋め込みたいURLアドレスのラベルを作成してください。例: #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "リフレッシュ" }, @@ -1864,10 +1860,6 @@ "protecting-title": "保護の状態", "unprotecting-title": "保護解除の状態" }, - "render": { - "note_detail_render_help_1": "このヘルプノートが表示されるのは、このノートの「HTML のレンダリング」タイプには、正常に機能するために必要なリレーションがないためです。", - "note_detail_render_help_2": "レンダリングHTMLノートタイプは、スクリプティングに使用されます。簡単に言うと、HTMLコードノート(オプションでJavaScriptを含む)があり、このノートがそれをレンダリングします。これを動作させるには、レンダリングするHTMLノートを指す「renderNote」というリレーションを定義する必要があります。" - }, "consistency_checks": { "find_and_fix_button": "一貫性の問題を見つけて修正する", "finding_and_fixing_message": "一貫性の問題を見つけて修正中…", @@ -1959,7 +1951,9 @@ "print_report_title": "レポートを印刷", "print_report_collection_content_other": "コレクション内の {{count}} 件のノートは、サポートされていないか保護されているため、印刷できませんでした。", "print_report_collection_details_button": "詳細を見る", - "print_report_collection_details_ignored_notes": "無視されたノート" + "print_report_collection_details_ignored_notes": "無視されたノート", + "print_report_error_title": "印刷に失敗しました", + "print_report_stack_trace": "スタックトレース" }, "watched_file_update_status": { "ignore_this_change": "この変更を無視する", @@ -2042,7 +2036,8 @@ "show-scale": "スケールを表示", "raster": "Raster", "vector_light": "Vector(ライト)", - "vector_dark": "Vector (ダーク)" + "vector_dark": "Vector (ダーク)", + "show-labels": "マーカー名を表示" }, "call_to_action": { "next_theme_title": "新しいTriliumテーマをお試しください", @@ -2070,8 +2065,9 @@ "percentage": "%" }, "pagination": { - "page_title": "{{startIndex}} - {{endIndex}} ページ", - "total_notes": "{{count}} ノート" + "total_notes": "{{count}} ノート", + "prev_page": "前のページ", + "next_page": "次のページ" }, "collections": { "rendering_error": "エラーのためコンテンツを表示できません。" @@ -2099,7 +2095,7 @@ "no_attachments": "このノートには添付ファイルはありません。" }, "book": { - "no_children_help": "このコレクションには子ノートがないため、表示するものがありません。詳細はwikiをご覧ください。", + "no_children_help": "このコレクションには子ノートがないため、表示するものがありません。", "drag_locked_title": "編集をロック中", "drag_locked_message": "コレクションは編集がロックされているため、ドラッグは許可されていません。" }, @@ -2268,5 +2264,49 @@ }, "bookmark_buttons": { "bookmarks": "ブックマーク" + }, + "web_view_setup": { + "title": "Trilium に直接 Web ページのライブビューを作成", + "url_placeholder": "Web サイトのアドレスを入力または貼り付けて下さい。 例: https://triliumnotes.org", + "create_button": "Web ビューを作成", + "invalid_url_title": "無効なアドレス", + "invalid_url_message": "有効な Web アドレスを入力してください。 例: https://triliumnotes.org", + "disabled_description": "この Web ビューは外部ソースからインポートされました。フィッシングや悪意のあるコンテンツから保護するため、自動的には読み込まれません。ソースを信頼できる場合は、有効にすることができます。", + "disabled_button_enable": "Web ビューを有効" + }, + "render": { + "setup_title": "このノート内にカスタム HTML または Preact JSX を表示", + "setup_create_sample_preact": "Preact でサンプルノートを作成", + "setup_create_sample_html": "HTML でサンプルノートを作成", + "setup_sample_created": "子ノートとしてサンプルノートが作成されました。", + "disabled_description": "このレンダリングノートは外部ソースから提供されています。悪意のあるコンテンツからユーザーを保護するため、デフォルトでは有効になっていません。有効にする前に、ソースが信頼できるかどうかをご確認ください。", + "disabled_button_enable": "レンダリングノートを有効" + }, + "active_content_badges": { + "type_icon_pack": "アイコンパック", + "type_backend_script": "バックエンドスクリプト", + "type_frontend_script": "フロントエンドスクリプト", + "type_widget": "ウィジェット", + "type_app_css": "カスタム CSS", + "type_render_note": "レンダリングノート", + "type_web_view": "Web ビュー", + "type_app_theme": "カスタムテーマ", + "toggle_tooltip_enable_tooltip": "この {{type}} を有効にするにはクリックしてください。", + "toggle_tooltip_disable_tooltip": "この {{type}} を無効にするにはクリックしてください。", + "menu_docs": "ドキュメントを開く", + "menu_execute_now": "今すぐスクリプトを実行", + "menu_run": "自動で実行", + "menu_run_disabled": "手動で実行", + "menu_run_backend_startup": "バックエンドの起動時", + "menu_run_hourly": "毎時", + "menu_run_daily": "毎日", + "menu_run_frontend_startup": "デスクトップ フロントエンドの起動時", + "menu_run_mobile_startup": "モバイル フロントエンドの起動時", + "menu_change_to_widget": "ウィジェットの変更", + "menu_change_to_frontend_script": "フロントエンドスクリプトの変更", + "menu_theme_base": "テーマベース" + }, + "setup_form": { + "more_info": "さらに詳しく" } } diff --git a/apps/client/src/translations/ko/translation.json b/apps/client/src/translations/ko/translation.json index aefb75c6ef..72fe62576f 100644 --- a/apps/client/src/translations/ko/translation.json +++ b/apps/client/src/translations/ko/translation.json @@ -21,8 +21,17 @@ }, "bundle-error": { "title": "사용자 정의 스크립트를 불러오는데 실패했습니다", - "message": "ID가 \"{{id}}\"고, 제목이 \"{{title}}\"인 노트에서 스크립트가 실행되지 못했습니다:\n\n{{message}}" - } + "message": "다음 이유로 인해 스크립트가 실행되지 못했습니다:\n\n{{message}}" + }, + "widget-list-error": { + "title": "서버에서 위젯 목록을 가져오는 데 실패했습니다" + }, + "widget-render-error": { + "title": "사용자 정의 React 위젯을 렌더링하는 데 실패했습니다" + }, + "widget-missing-parent": "사용자 정의 위젯에 필수 속성 '{{property}}'가 정의되어 있지 않습니다.\n\n이 스크립트를 UI 요소 없이 실행하려면 '#run=frontendStartup'을 대신 사용하십시오.", + "open-script-note": "스크립트 노트 열기", + "scripting-error": "사용자 지정 스크립트 오류: {{title}}" }, "add_link": { "add_link": "링크 추가", @@ -41,7 +50,8 @@ "prefix": "접두사: ", "branch_prefix_saved": "브랜치 접두사가 저장되었습니다.", "edit_branch_prefix_multiple": "{{count}}개의 지점 접두사 편집", - "branch_prefix_saved_multiple": "{{count}}개의 지점에 대해 지점 접두사가 저장되었습니다." + "branch_prefix_saved_multiple": "{{count}}개의 지점에 대해 지점 접두사가 저장되었습니다.", + "affected_branches": "영향을 받는 브랜치 수 ({{count}}):" }, "bulk_actions": { "bulk_actions": "대량 작업", @@ -64,10 +74,44 @@ "first-week-contains-first-day": "첫 번째 주에는 올해의 첫날이 포함됩니다" }, "clone_to": { - "clone_notes_to": "~로 노트 복제", + "clone_notes_to": "노트 클론하기...", "help_on_links": "링크에 대한 도움말", "notes_to_clone": "노트 클론 생성", "target_parent_note": "부모 노트 타겟", - "search_for_note_by_its_name": "이름으로 노트 검색하기" + "search_for_note_by_its_name": "이름으로 노트 검색하기", + "no_path_to_clone_to": "클론할 경로가 존재하지 않습니다.", + "note_cloned": "노트 \"{{clonedTitle}}\"이(가) \"{{targetTitle}}\"로 클론되었습니다", + "cloned_note_prefix_title": "클론된 노트는 지정된 접두사와 함께 노트 트리에 표시됩니다" + }, + "confirm": { + "confirmation": "확인", + "cancel": "취소", + "ok": "OK", + "are_you_sure_remove_note": "관계 맵에서 \"{{title}}\" 노트를 정말로 제거하시겠습니까? " + }, + "delete_notes": { + "erase_notes_description": "일반(소프트) 삭제는 메모를 삭제된 것으로 표시하는 것일 뿐이며, 일정 시간 동안 (최근 변경 내용 대화 상자에서) 복구할 수 있습니다. 이 옵션을 선택하면 메모가 즉시 삭제되며 복구할 수 없습니다.", + "erase_notes_warning": "모든 복제본을 포함하여 메모를 영구적으로 삭제합니다(이 작업은 되돌릴 수 없습니다). 애플리케이션이 다시 시작됩니다.", + "notes_to_be_deleted": "다음 노트가 삭제됩니다 ({{notesCount}})", + "no_note_to_delete": "삭제되는 노트가 없습니다 (클론만 삭제됩니다).", + "broken_relations_to_be_deleted": "다음 관계가 끊어지고 삭제됩니다({{ relationCount}})", + "cancel": "취소", + "ok": "OK", + "deleted_relation_text": "삭제 예정인 노트 {{- note}} (은)는 {{- source}}에서 시작된 관계 {{- relation}}에 의해 참조되고 있습니다." + }, + "export": { + "export_note_title": "노트 내보내기", + "export_type_single": "이 노트에만 해당(후손 노트를 포함하지 않음)", + "export": "내보내기", + "choose_export_type": "내보내기 타입을 선택해 주세요", + "export_status": "상태 내보내기", + "export_in_progress": "내보내기 진행 중: {{progressCount}}", + "export_finished_successfully": "내보내기를 성공적으로 완료했습니다.", + "format_pdf": "PDF - 인쇄 또는 공유용", + "share-format": "웹 게시용 HTML - 공유 노트에 사용되는 것과 동일한 테마를 사용하지만 정적 웹사이트로 게시할 수 있습니다." + }, + "help": { + "title": "치트 시트", + "editShortcuts": "키보드 단축키 편집" } } diff --git a/apps/client/src/translations/pl/translation.json b/apps/client/src/translations/pl/translation.json index 17f32fc602..2c690b0370 100644 --- a/apps/client/src/translations/pl/translation.json +++ b/apps/client/src/translations/pl/translation.json @@ -21,7 +21,7 @@ }, "bundle-error": { "title": "Nie udało się załadować niestandardowego skryptu", - "message": "Skrypt z notatki o ID \"{{id}}\", zatytułowany \"{{title}}\", nie mógł zostać wykonany z powodu:\n\n{{message}}" + "message": "Skrypt nie mógł zostać wykonany z powodu:\n\n{{message}}" }, "widget-list-error": { "title": "Nie udało się pobrać listy widżetów z serwera" @@ -29,8 +29,9 @@ "widget-render-error": { "title": "Nie udało się wyrenderować niestandardowego widżetu React" }, - "widget-missing-parent": "Niestandardowy widżet nie ma zdefiniowanej obowiązkowej właściwości „{{property}}”.", - "open-script-note": "Otwórz notatkę ze skryptem" + "widget-missing-parent": "Niestandardowy widżet nie ma zdefiniowanej obowiązkowej właściwości „{{property}}”.\nJeśli skrypt ma działać bez interfejsu użytkownika (UI) wyłącz go: '#run=frontendStartup'.", + "open-script-note": "Otwórz notatkę ze skryptem", + "scripting-error": "Błąd skryptu użytkownika: {{title}}" }, "add_link": { "add_link": "Dodaj link", @@ -191,7 +192,8 @@ "expand_tooltip": "Rozwija bezpośrednie elementy podrzędne tej kolekcji (o jeden poziom). Aby uzyskać więcej opcji, naciśnij strzałkę po prawej.", "expand_first_level": "Rozwiń bezpośrednie elementy podrzędne", "expand_nth_level": "Rozwiń {{depth}} poziomów", - "expand_all_levels": "Rozwiń wszystkie poziomy" + "expand_all_levels": "Rozwiń wszystkie poziomy", + "hide_child_notes": "Ukryj notatki podrzędne w derzwie" }, "board_view": { "move-to": "Przenieś do", @@ -240,7 +242,7 @@ "background_effects_title": "Efekty tła są teraz stabilne", "dismiss": "Odrzuć", "background_effects_button": "Włącz efekty tła", - "background_effects_message": "Na urządzeniach z systemem Windows efekty tła są teraz w pełni stabilne. Efekty tła dodają odrobinę koloru do interfejsu użytkownika poprzez rozmycie tła za nim. Ta technika jest również stosowana w innych aplikacjach, takich jak Eksplorator Windows.", + "background_effects_message": "Na urządzeniach z systemem Windows i macOS efekty tła są stabilne. Efekty tła dodają odrobinę koloru do interfejsu użytkownika poprzez rozmycie tła za nim.", "new_layout_title": "Nowy układ", "new_layout_message": "Wprowadziliśmy zmodernizowany układ interfejsu dla Trilium. Wstążka została usunięta i płynnie zintegrowana z głównym interfejsem, a jej kluczowe funkcje przejęły nowy pasek stanu i rozwijane sekcje (takie jak promowane atrybuty).\n\nNowy układ jest domyślnie włączony i można go tymczasowo wyłączyć w Ustawienia → Wygląd.", "new_layout_button": "Szczegóły" @@ -259,7 +261,6 @@ "percentage": "%" }, "pagination": { - "page_title": "Strona {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} notatek" }, "collections": { @@ -520,7 +521,8 @@ "action": "akcja", "search_button": "Szukaj", "search_execute": "Szukaj i wykonaj akcje", - "view_options": "Ustawienia widoku:" + "view_options": "Ustawienia widoku:", + "option": "opcja" }, "similar_notes": { "title": "Podobne notatki", @@ -602,8 +604,8 @@ "desktop-application": "Aplikacja desktopowa", "native-title-bar": "Natywny pasek tytułu", "native-title-bar-description": "Dla Windows i macOS, wyłączenie natywnego paska tytułu sprawia, że aplikacja wygląda bardziej kompaktowo. Na Linuxie, włączenie natywnego paska tytułu lepiej integruje się z resztą systemu.", - "background-effects": "Włącz efekty tła (tylko Windows 11)", - "background-effects-description": "Efekt Mica dodaje rozmyte, stylowe tło do okien aplikacji, tworząc głębię i nowoczesny wygląd. \"Natywny pasek tytułu\" musi być wyłączony.", + "background-effects": "Włącz efekty tła", + "background-effects-description": "Dodaje rozmyte, stylowe tło do okien aplikacji, tworząc głębię i nowoczesny wygląd. \"Natywny pasek tytułu\" musi być wyłączony.", "restart-app-button": "Zrestartuj aplikację, aby zobaczyć zmiany", "zoom-factor": "Współczynnik powiększenia" }, @@ -1182,7 +1184,8 @@ "show-cheatsheet": "Pokaż ściągawkę", "toggle-zen-mode": "Tryb Zen", "new-version-available": "Dostępna nowa aktualizacja", - "download-update": "Pobierz wersję {{latestVersion}}" + "download-update": "Pobierz wersję {{latestVersion}}", + "search_notes": "Przeszukaj notatki" }, "zen_mode": { "button_exit": "Wyjdź z trybu Zen" @@ -1265,7 +1268,7 @@ "button_title": "Eksportuj diagram jako SVG" }, "relation_map_buttons": { - "create_child_note_title": "Utwórz nową notatkę podrzędną i dodaj ją do tej mapy relacji", + "create_child_note_title": "Utwórz notatkę podrzędną i dodaj ją do mapy", "reset_pan_zoom_title": "Zresetuj przesunięcie i powiększenie do początkowych współrzędnych i powiększenia", "zoom_in_title": "Powiększ", "zoom_out_title": "Pomniejsz" @@ -1281,12 +1284,23 @@ "delete_this_note": "Usuń tę notatkę", "note_revisions": "Wersje notatki", "error_cannot_get_branch_id": "Nie można pobrać branchId dla ścieżki notatki '{{notePath}}'", - "error_unrecognized_command": "Nierozpoznane polecenie {{command}}" + "error_unrecognized_command": "Nierozpoznane polecenie {{command}}", + "backlinks": "Linki zwrotne", + "content_language_switcher": "Język treści: {{language}}" }, "note_icon": { "change_note_icon": "Zmień ikonę notatki", "search": "Szukaj:", - "reset-default": "Przywróć domyślną ikonę" + "reset-default": "Przywróć domyślną ikonę", + "search_placeholder_one": "Znaleziono {{number}} ikonę w {{count}} pakietach", + "search_placeholder_few": "Znaleziono {{number}} ikon w {{count}} pakietach", + "search_placeholder_many": "Znaleziono {{number}} ikon w {{count}} pakietach", + "search_placeholder_filtered": "Wyszukaj {{number}} ikon w {{name}}", + "filter": "Filtr", + "filter-none": "Wszystkie ikony", + "filter-default": "Domyślne ikony", + "icon_tooltip": "{{name}}\npakiet ikon: {{iconPack}}", + "no_results": "Nie znaleziono ikon." }, "basic_properties": { "note_type": "Typ notatki", @@ -1417,15 +1431,6 @@ "default_new_note_title": "nowa notatka", "click_on_canvas_to_place_new_note": "Kliknij na płótnie, aby umieścić nową notatkę" }, - "render": { - "note_detail_render_help_1": "Ta notatka pomocy jest wyświetlana, ponieważ ta notatka typu Render HTML nie ma wymaganej relacji do poprawnego działania.", - "note_detail_render_help_2": "Typ notatki Render HTML jest używany do skryptowania. W skrócie, masz notatkę kodu HTML (opcjonalnie z JavaScript) i ta notatka ją wyrenderuje. Aby to zadziałało, musisz zdefiniować relację o nazwie \"renderNote\" wskazującą na notatkę HTML do wyrenderowania." - }, - "web_view": { - "web_view": "Widok WWW", - "embed_websites": "Notatka typu Widok WWW pozwala na osadzanie stron internetowych w Trilium.", - "create_label": "Aby rozpocząć, utwórz etykietę z adresem URL, który chcesz osadzić, np. #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Odśwież" }, @@ -1826,7 +1831,7 @@ "will_be_deleted_in": "Ten załącznik zostanie automatycznie usunięty za {{time}}", "will_be_deleted_soon": "Ten załącznik zostanie wkrótce automatycznie usunięty", "deletion_reason": ", ponieważ załącznik nie jest podlinkowany w treści notatki. Aby zapobiec usunięciu, dodaj link do załącznika z powrotem do treści lub przekonwertuj załącznik na notatkę.", - "role_and_size": "Rola: {{role}}, Rozmiar: {{size}}", + "role_and_size": "Rola: {{role}}, Rozmiar: {{size}}, MIME: {{- mimeType}}", "link_copied": "Link do załącznika skopiowany do schowka.", "unrecognized_role": "Nierozpoznana rola załącznika '{{role}}'." }, @@ -1880,7 +1885,10 @@ "apply-bulk-actions": "Zastosuj akcje masowe", "converted-to-attachments": "{{count}} notatek zostało przekonwertowanych na załączniki.", "convert-to-attachment-confirm": "Czy na pewno chcesz przekonwertować wybrane notatki na załączniki ich notatek nadrzędnych? Ta operacja dotyczy tylko notatek Obrazów, inne notatki zostaną pominięte.", - "open-in-popup": "Szybka edycja" + "open-in-popup": "Szybka edycja", + "open-in-a-new-window": "Otwórz w nowym oknie", + "hide-subtree": "Ukryj gałąź", + "show-subtree": "Rozwiń gałąź" }, "shared_info": { "shared_publicly": "Ta notatka jest udostępniona publicznie pod adresem {{- link}}.", @@ -1971,7 +1979,17 @@ "create-child-note": "Utwórz notatkę podrzędną", "unhoist": "Cofnij zawężenie", "toggle-sidebar": "Przełącz pasek boczny", - "dropping-not-allowed": "Upuszczanie notatek w tej lokalizacji jest niedozwolone." + "dropping-not-allowed": "Upuszczanie notatek w tej lokalizacji jest niedozwolone.", + "clone-indicator-tooltip": "Ta notatka ma {{- count}} notatek nadrzędnych: {{- parents}}", + "clone-indicator-tooltip-single": "Ta notatka jest sklonowana (1 dodatkowa notatka nadrzędna: {{- parent}})", + "shared-indicator-tooltip": "Ta notatka jest udostępniona publicznie", + "shared-indicator-tooltip-with-url": "Ta notatka jest udostępniana publicznie jako: {{- url}}", + "subtree-hidden-tooltip_one": "{{count}} notatka podrzędna ukryta w drzewie", + "subtree-hidden-tooltip_few": "{{count}} notatek podrzędnych ukrytych w drzewie", + "subtree-hidden-tooltip_many": "{{count}} notatek podrzędnych ukrytych w drzewie", + "subtree-hidden-moved-title": "Dodano do {{title}}", + "subtree-hidden-moved-description-collection": "Ta kolekcja ukrywa swoje notatki podrzędne w drzewie.", + "subtree-hidden-moved-description-other": "Notatki podrzędne są ukryte w drzewie tej notatki." }, "title_bar_buttons": { "window-on-top": "Utrzymuj okno na wierzchu" @@ -1979,7 +1997,13 @@ "note_detail": { "could_not_find_typewidget": "Nie można znaleźć widżetu typu dla typu '{{type}}'", "printing": "Drukowanie w toku...", - "printing_pdf": "Eksportowanie do PDF w toku..." + "printing_pdf": "Eksportowanie do PDF w toku...", + "print_report_title": "Wydrukuj raport", + "print_report_collection_content_one": "Nie można wydrukować {{count}} notatki w kolekcji, ponieważ nie jest ona obsługiwana lub jest chroniona.", + "print_report_collection_content_few": "Nie można wydrukować {{count}} notatek w kolekcji, ponieważ nie są one obsługiwane lub są chronione.", + "print_report_collection_content_many": "Nie można wydrukować {{count}} notatek w kolekcji, ponieważ nie są one obsługiwane lub są chronione.", + "print_report_collection_details_button": "Zobacz szczegóły", + "print_report_collection_details_ignored_notes": "Zignorowane notatki" }, "note_title": { "placeholder": "wpisz tytuł notatki tutaj...", @@ -1989,7 +2013,8 @@ "note_type_switcher_others": "Inny typ notatki", "note_type_switcher_templates": "Szablon", "note_type_switcher_collection": "Kolekcja", - "edited_notes": "Edytowane notatki" + "edited_notes": "Notatki edytowane dzisiaj", + "promoted_attributes": "Sugerowane atrybuty" }, "search_result": { "no_notes_found": "Nie znaleziono notatek dla podanych parametrów wyszukiwania.", @@ -1999,7 +2024,11 @@ "configure_launchbar": "Konfiguruj pasek szybkiego dostępu" }, "sql_result": { - "no_rows": "Dla tego zapytania nie zwrócono żadnych wierszy" + "no_rows": "Dla tego zapytania nie zwrócono żadnych wierszy", + "not_executed": "Zapytanie nie zostało jeszcze wykonane.", + "failed": "Wykonanie zapytania SQL nie powiodło się", + "statement_result": "Wynik wyrażenia", + "execute_now": "Wykonaj teraz" }, "sql_table_schemas": { "tables": "Tabele" @@ -2116,7 +2145,8 @@ "geo-map": { "create-child-note-title": "Utwórz nową notatkę podrzędną i dodaj ją do mapy", "create-child-note-instruction": "Kliknij na mapie, aby utworzyć nową notatkę w tej lokalizacji lub naciśnij Escape, aby anulować.", - "unable-to-load-map": "Nie można załadować mapy." + "unable-to-load-map": "Nie można załadować mapy.", + "create-child-note-text": "Dodaj zaznaczenie" }, "geo-map-context": { "open-location": "Otwórz lokalizację", @@ -2183,7 +2213,14 @@ "execute_sql_description": "Ta notatka jest notatką SQL. Kliknij, aby wykonać zapytanie SQL.", "shared_copy_to_clipboard": "Kopiuj link do schowka", "shared_open_in_browser": "Otwórz link w przeglądarce", - "shared_unshare": "Usuń udostępnienie" + "shared_unshare": "Usuń udostępnienie", + "save_status_saved": "Zapisane", + "save_status_saving": "Zapisywanie...", + "save_status_unsaved": "Niezapisane", + "save_status_error": "Zapis nie powiódł się", + "save_status_saving_tooltip": "Zmiany zostały zapisane.", + "save_status_unsaved_tooltip": "Są niezapisane zmiany. Zostaną one zapisane automatycznie za chwilę.", + "save_status_error_tooltip": "Wystąpił błąd podczas zapisywania notatki. Spróbuj skopiować treść notatki w inne miejsce i ponownie załadować aplikację." }, "status_bar": { "language_title": "Zmień język treści", @@ -2226,5 +2263,30 @@ "empty_button": "Ukryj panel", "toggle": "Pokaż/ukryj prawy panel", "custom_widget_go_to_source": "Przejdź do kodu źródłowego" + }, + "pdf": { + "attachments_one": "{{count}} załącznik", + "attachments_few": "{{count}} załączniki", + "attachments_many": "{{count}} załączników", + "layers_one": "{{count}} warstwa", + "layers_few": "{{count}} warstw", + "layers_many": "{{count}} warstw", + "pages_one": "{{count}} strona", + "pages_few": "{{count}} stron", + "pages_many": "{{count}} stron", + "pages_alt": "Strona {{pageNumber}}", + "pages_loading": "Wczytuję..." + }, + "platform_indicator": { + "available_on": "Dostępne na {{platform}}" + }, + "mobile_tab_switcher": { + "title_one": "{{count}} zakładka", + "title_few": "{{count}} zakładki", + "title_many": "{{count}} zakładek", + "more_options": "Więcej opcji" + }, + "bookmark_buttons": { + "bookmarks": "Zakładki" } } diff --git a/apps/client/src/translations/pt/translation.json b/apps/client/src/translations/pt/translation.json index cd03411ceb..7975182509 100644 --- a/apps/client/src/translations/pt/translation.json +++ b/apps/client/src/translations/pt/translation.json @@ -1064,15 +1064,6 @@ "default_new_note_title": "nova nota", "click_on_canvas_to_place_new_note": "Clique no quadro para incluir uma nova nota" }, - "render": { - "note_detail_render_help_1": "Esta nota de ajuda é mostrada porque esta nota do tipo Renderizar HTML não possui a relação necessária para funcionar corretamente.", - "note_detail_render_help_2": "O tipo de nota Renderizar HTML é usado para automação. Em suma, tem uma nota de código HTML (opcionalmente com algum JavaScript) e esta nota irá renderizá-la. Para fazê-lo funcionar, deve definir uma relação chamada \"renderNote\" que aponta para a nota HTML a ser renderizada." - }, - "web_view": { - "web_view": "Web View", - "embed_websites": "Nota do tipo Visualização Web permite que incorpore sites no Trilium.", - "create_label": "Para começar, crie uma etiqueta com um endereço URL que deseja incorporar, por exemplo, #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Recarregar" }, @@ -2174,7 +2165,6 @@ "delete_note": "Apagar nota..." }, "pagination": { - "page_title": "Página {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} notas" }, "collections": { diff --git a/apps/client/src/translations/pt_br/translation.json b/apps/client/src/translations/pt_br/translation.json index cb628d931e..2c57dab23b 100644 --- a/apps/client/src/translations/pt_br/translation.json +++ b/apps/client/src/translations/pt_br/translation.json @@ -1271,11 +1271,6 @@ "start_dragging_relations": "Comece arrastando as relações daqui e solte-as em outra nota.", "cannot_match_transform": "Não foi possível combinar a transformação: {{transform}}" }, - "web_view": { - "web_view": "Web View", - "embed_websites": "Nota do tipo Visualização Web permite que você incorpore sites dentro do Trilium.", - "create_label": "Para começar, crie uma etiqueta com um endereço URL que deseja incorporar, por exemplo, #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Recarregar" }, @@ -1996,10 +1991,6 @@ "drag_locked_title": "Bloqueado para edição", "drag_locked_message": "Arrastar não é permitido pois a coleção está bloqueada para edição." }, - "render": { - "note_detail_render_help_1": "Esta nota de ajuda é mostrada porque esta nota do tipo Renderizar HTML não possui a relação necessária para funcionar corretamente.", - "note_detail_render_help_2": "O tipo de nota Renderizar HTML é usado para automação. Em suma, você tem uma nota de código HTML (opcionalmente com algum JavaScript) e esta nota irá renderizá-la. Para fazê-lo funcionar, você precisa definir uma relação chamada \"renderNote\" apontando para a nota HTML a ser renderizada." - }, "etapi": { "title": "ETAPI", "description": "ETAPI é uma API REST usada para acessar a instância do Trilium programaticamente, sem interface gráfica.", @@ -2124,7 +2115,6 @@ "shared_locally": "Esta nota é compartilhada localmente em {{- link}}." }, "pagination": { - "page_title": "Página de {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} notas" }, "collections": { diff --git a/apps/client/src/translations/ro/translation.json b/apps/client/src/translations/ro/translation.json index 843f90a03e..e955dab73b 100644 --- a/apps/client/src/translations/ro/translation.json +++ b/apps/client/src/translations/ro/translation.json @@ -1094,10 +1094,6 @@ "rename_relation_from": "Redenumește relația din", "to": "În" }, - "render": { - "note_detail_render_help_1": "Această notă informativă este afișată deoarece această notiță de tip „Randare HTML” nu are relația necesară pentru a funcționa corespunzător.", - "note_detail_render_help_2": "Notița de tipul „Render HTML” este utilizată pentru scriptare. Pe scurt, se folosește o notiță de tip cod HTML (opțional cu niște JavaScript) și această notiță o va randa. Pentru a funcționa, trebuie definită o relație denumită „renderNote” ce indică notița HTML de randat." - }, "revisions": { "confirm_delete": "Doriți ștergerea acestei revizii?", "confirm_delete_all": "Doriți ștergerea tuturor reviziilor acestei notițe?", @@ -1376,11 +1372,6 @@ "enable_vim_keybindings": "Permite utilizarea combinațiilor de taste în stil Vim pentru notițele de tip cod (fără modul ex)", "use_vim_keybindings_in_code_notes": "Combinații de taste Vim" }, - "web_view": { - "create_label": "Pentru a începe, creați o etichetă cu adresa URL de încorporat, e.g. #webViewSrc=\"https://www.google.com\"", - "embed_websites": "Notițele de tip „Vizualizare web” permit încorporarea site-urilor web în Trilium.", - "web_view": "Vizualizare web" - }, "wrap_lines": { "enable_line_wrap": "Activează trecerea automată pe rândul următor (poate necesita o reîncărcare a interfeței pentru a avea efect)", "wrap_lines_in_code_notes": "Trecerea automată pe rândul următor în notițe de cod" @@ -2160,7 +2151,6 @@ "percentage": "%" }, "pagination": { - "page_title": "Pagina pentru {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} notițe" }, "collections": { diff --git a/apps/client/src/translations/ru/translation.json b/apps/client/src/translations/ru/translation.json index ec5ec50166..aa495eb287 100644 --- a/apps/client/src/translations/ru/translation.json +++ b/apps/client/src/translations/ru/translation.json @@ -668,7 +668,8 @@ "geo-map": { "unable-to-load-map": "Не удалось загрузить карту.", "create-child-note-instruction": "Щелкните по карте, чтобы создать новую заметку в этом месте, или нажмите Escape, чтобы закрыть ее.", - "create-child-note-title": "Создать новую дочернюю заметку и добавить ее на карту" + "create-child-note-title": "Создать новую дочернюю заметку и добавить ее на карту", + "create-child-note-text": "Добавить маркер" }, "note_tooltip": { "quick-edit": "Быстрое редактирование", @@ -685,8 +686,8 @@ "electron_integration": { "zoom-factor": "Коэффициент масштабирования", "restart-app-button": "Применить изменения и перезапустить приложение", - "background-effects-description": "Эффект Mica добавляет размытый, стильный фон окнам приложений, создавая глубину и современный вид. Опция \"Системная строка заголовка\" должна быть отключена.", - "background-effects": "Включить фоновые эффекты (только Windows 11)", + "background-effects-description": "Добавляет размытый, стильный фон окнам приложений, создавая глубину и современный вид. Опция \"Системная строка заголовка\" должна быть отключена.", + "background-effects": "Включить фоновые эффекты", "native-title-bar-description": "В Windows и macOS отключение системной строки заголовка делает приложение более компактным. В Linux включение системной строки заголовка улучшает интеграцию с остальной частью системы.", "native-title-bar": "Системная панель заголовка", "desktop-application": "Десктопное приложение" @@ -776,7 +777,11 @@ "refresh-saved-search-results": "Обновить сохраненные результаты поиска", "automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве.", "toggle-sidebar": "Переключить боковую панель", - "dropping-not-allowed": "Перетаскивание заметок в эту область не разрешено." + "dropping-not-allowed": "Перетаскивание заметок в эту область не разрешено.", + "shared-indicator-tooltip": "Эта заметка опубликована", + "shared-indicator-tooltip-with-url": "Эта заметка доступно публично по адресу: {{- url}}", + "subtree-hidden-moved-description-other": "В дереве, к которому относится эта заметка, скрыты дочерние заметки.", + "subtree-hidden-moved-description-collection": "Эта коллекция скрывает свои дочерние заметки в дереве." }, "quick-search": { "no-results": "Результаты не найдены", @@ -856,7 +861,10 @@ "convert-to-attachment-confirm": "Вы уверены, что хотите преобразовать выбранные заметки во вложения их родительских заметок? Эта операция применяется только к заметкам в виде изображений; другие заметки будут пропущены.", "converted-to-attachments": "{{count}} заметок были преобразованы во вложения.", "archive": "Архивировать", - "unarchive": "Разархивировать" + "unarchive": "Разархивировать", + "open-in-a-new-window": "Открыть в новом окне", + "hide-subtree": "Скрыть поддерево", + "show-subtree": "Показать поддерево" }, "info": { "closeButton": "Закрыть", @@ -1000,7 +1008,8 @@ "switch_to_mobile_version": "Перейти на мобильную версию", "switch_to_desktop_version": "Переключиться на версию для ПК", "new-version-available": "Доступно обновление", - "download-update": "Обновить до {{latestVersion}}" + "download-update": "Обновить до {{latestVersion}}", + "search_notes": "Поиск заметок" }, "zpetne_odkazy": { "relation": "отношение", @@ -1047,7 +1056,8 @@ "expand_all_levels": "Развернуть все вложенные уровни", "expand_nth_level": "Развернуть уровни: {{depth}} шт.", "expand_first_level": "Развернуть прямые дочерние уровни", - "expand_tooltip": "Разщвернуть дочерние элементы этой коллекции (на один уровень вложенности). Для получения дополнительных параметров нажмите стрелку справа." + "expand_tooltip": "Разщвернуть дочерние элементы этой коллекции (на один уровень вложенности). Для получения дополнительных параметров нажмите стрелку справа.", + "hide_child_notes": "Скрыть дочерние заметки в дереве" }, "edited_notes": { "deleted": "(удалено)", @@ -1692,7 +1702,7 @@ "zoom_in_title": "Увеличить масштаб", "zoom_out_title": "Уменьшить масштаб", "reset_pan_zoom_title": "Сбросить панорамирование и масштабирование", - "create_child_note_title": "Создать новую дочернюю заметку и добавить ее в эту карту связей" + "create_child_note_title": "Создать дочернюю заметку и добавить ее в карту" }, "code_auto_read_only_size": { "unit": "символов", @@ -1845,7 +1855,8 @@ "error_cannot_get_branch_id": "Невозможно получить branchId для notePath '{{notePath}}'", "delete_this_note": "Удалить эту заметку", "insert_child_note": "Вставить дочернюю заметку", - "note_revisions": "История изменений" + "note_revisions": "История изменений", + "content_language_switcher": "Язык содержимого: {{language}}" }, "svg_export_button": { "button_title": "Экспортировать диаграмму как SVG" @@ -1900,7 +1911,7 @@ "dismiss": "Отклонить", "background_effects_button": "Включить эффекты фона", "next_theme_button": "Попробовать новую тему", - "background_effects_message": "На устройствах Windows фоновые эффекты теперь полностью стабильны. Они добавляют цвет в пользовательский интерфейс, размывая фон за ним. Этот приём также используется в других приложениях, например, в проводнике Windows.", + "background_effects_message": "На устройствах с ОС Windows или macOS, фоновые эффекты теперь полностью стабильны. Они добавляют цвета в пользовательский интерфейс, размывая фон за ним.", "background_effects_title": "Фоновые эффекты теперь стабильны", "next_theme_title": "Попробуйте новую тему Trilium", "new_layout_button": "Подробнее", @@ -1988,11 +1999,6 @@ "attachment_deleted": "Это вложение было удалено.", "you_can_also_open": ", вы также можете открыть " }, - "web_view": { - "web_view": "Веб-страница", - "create_label": "Для начала создайте метку с URL-адресом, который вы хотите встроить, например, #webViewSrc=\"https://www.google.com\"", - "embed_websites": "Заметки типа \"Веб-страница\" позволяет встраивать веб-сайты в Trilium." - }, "ribbon": { "widgets": "Виджеты ленты", "promoted_attributes_message": "Вкладка \"Продвигаемые атрибуты\" будет автоматически открыта, если таковые атрибуты установлены у заметки", @@ -2075,10 +2081,6 @@ "help-button": { "title": "Открыть соответствующую страницу справки" }, - "render": { - "note_detail_render_help_2": "Тип заметки «Рендер HTML» используется для скриптинга. Если коротко, у вас есть заметка с HTML-кодом (возможно, с добавлением JavaScript), и эта заметка её отобразит. Для этого необходимо определить отношение с именем «renderNote», указывающее на HTML-заметку для отрисовки.", - "note_detail_render_help_1": "Эта справочная заметка отображается, поскольку эта справка типа Render HTML не имеет необходимой связи для правильной работы." - }, "file": { "too_big": "В целях повышения производительности в режиме предварительного просмотра отображаются только первые {{maxNumChars}} символов файла. Загрузите файл и откройте его во внешнем браузере, чтобы увидеть всё содержимое.", "file_preview_not_available": "Предварительный просмотр файла недоступен для этого файла." @@ -2094,7 +2096,11 @@ "ui": "Пользовательский интерфейс" }, "sql_result": { - "no_rows": "По этому запросу не возвращено ни одной строки" + "no_rows": "По этому запросу не возвращено ни одной строки", + "not_executed": "Запрос еще не выполнен.", + "failed": "Выполнение SQL-запроса завершилось с ошибкой", + "statement_result": "Результат заявления", + "execute_now": "Выполнить сейчас" }, "editable_code": { "placeholder": "Введите содержимое для заметки с кодом..." @@ -2144,8 +2150,7 @@ "rendering_error": "Невозможно отобразить содержимое из-за ошибки." }, "pagination": { - "total_notes": "{{count}} заметок", - "page_title": "Страница {{startIndex}} - {{endIndex}}" + "total_notes": "{{count}} заметок" }, "status_bar": { "attributes_one": "{{count}} атрибут", @@ -2189,7 +2194,14 @@ "read_only_auto_description": "Эта заметка была автоматически переведена в режим только для чтения по соображениям производительности. Это автоматическое ограничение можно изменить в настройках.\n\nНажмите, чтобы временно отредактировать её.", "read_only_auto": "Автоматический режим \"только для чтения\"", "read_only_explicit_description": "Эта заметка была вручную установлена в режим «только для чтения».\nНажмите, чтобы временно отредактировать её.", - "read_only_explicit": "Только для чтения" + "read_only_explicit": "Только для чтения", + "save_status_saving": "Сохранение...", + "save_status_saved": "Сохранение", + "save_status_unsaved": "Не сохранено", + "save_status_error": "Ошибка сохранения", + "save_status_saving_tooltip": "Изменения сохраняются.", + "save_status_unsaved_tooltip": "Есть несохраненные изменения. Они будут сохранены автоматически через некоторое время.", + "save_status_error_tooltip": "Произошла ошибка при сохранении заметки. Если возможно, попробуйте скопировать содержимое заметки в другое место и перезагрузить приложение." }, "breadcrumb": { "hoisted_badge_title": "Снять фокус", @@ -2243,5 +2255,30 @@ }, "attributes_panel": { "title": "Атрибуты заметки" + }, + "bookmark_buttons": { + "bookmarks": "Закладки" + }, + "mobile_tab_switcher": { + "more_options": "Показать больше", + "title_one": "{{count}} вкладка", + "title_few": "{{count}} вкладки", + "title_many": "{{count}} вкладок" + }, + "pdf": { + "pages_loading": "Загрузка...", + "pages_alt": "Страница {{pageNumber}}", + "pages_one": "{{count}} страница", + "pages_few": "{{count}} страницы", + "pages_many": "{{count}} страниц", + "layers_one": "{{count}} слой", + "layers_few": "{{count}} слоя", + "layers_many": "{{count}} слоев", + "attachments_one": "{{count}} вложение", + "attachments_few": "{{count}} вложения", + "attachments_many": "{{count}} вложений" + }, + "platform_indicator": { + "available_on": "Доступно для {{platform}}" } } diff --git a/apps/client/src/translations/tw/translation.json b/apps/client/src/translations/tw/translation.json index 150aa6d3d1..39d2f73d60 100644 --- a/apps/client/src/translations/tw/translation.json +++ b/apps/client/src/translations/tw/translation.json @@ -662,7 +662,8 @@ "show-cheatsheet": "顯示快捷鍵說明", "toggle-zen-mode": "禪模式", "new-version-available": "發現新更新", - "download-update": "取得版本 {{latestVersion}}" + "download-update": "取得版本 {{latestVersion}}", + "search_notes": "搜尋筆記" }, "sync_status": { "unknown": "

同步狀態將在下一次同步嘗試開始後顯示。

點擊以立即觸發同步。

", @@ -758,7 +759,8 @@ "error_cannot_get_branch_id": "無法獲取 notePath '{{notePath}}' 的 branchId", "error_unrecognized_command": "無法識別的命令 {{command}}", "note_revisions": "筆記歷史版本", - "backlinks": "反向連結" + "backlinks": "反向連結", + "content_language_switcher": "內文語言:{{language}}" }, "note_icon": { "change_note_icon": "更改筆記圖標", @@ -910,7 +912,8 @@ "unknown_search_option": "未知的搜尋選項 {{searchOptionName}}", "search_note_saved": "搜尋筆記已儲存至 {{- notePathTitle}}", "actions_executed": "已執行操作。", - "view_options": "查看選項:" + "view_options": "查看選項:", + "option": "選項" }, "similar_notes": { "title": "相似筆記", @@ -1004,7 +1007,7 @@ "no_attachments": "此筆記沒有附件。" }, "book": { - "no_children_help": "此類型為書籍的筆記沒有任何子筆記,因此沒有內容可顯示。請參閱 wiki 以了解詳情。", + "no_children_help": "此集合沒有任何子筆記,因此沒有內容可顯示。", "drag_locked_title": "鎖定編輯", "drag_locked_message": "無法拖曳,因為此集合已被鎖定編輯。" }, @@ -1060,15 +1063,6 @@ "default_new_note_title": "新筆記", "click_on_canvas_to_place_new_note": "點擊畫布以放置新筆記" }, - "render": { - "note_detail_render_help_1": "之所以顯示此說明筆記,是因為該類型的渲染 HTML 沒有設定好必須的關聯。", - "note_detail_render_help_2": "渲染筆記類型用於編寫 腳本。簡單說就是您可以寫HTML程式碼(或者加上一些JavaScript程式碼), 然後這個筆記會把頁面渲染出來。要使其正常工作,您需要定義一個名為 \"renderNote\" 的 關聯 指向要呈現的 HTML 筆記。" - }, - "web_view": { - "web_view": "網頁顯示", - "embed_websites": "網頁顯示類型的筆記允許您將網站嵌入至 Trilium 中。", - "create_label": "首先,請新增一個帶有您要嵌入的 URL 地址的標籤,例如 #webViewSrc=\"https://www.bing.com\"" - }, "backend_log": { "refresh": "重新整理" }, @@ -1379,7 +1373,8 @@ "description": "描述", "reload_app": "重新載入應用以套用更改", "set_all_to_default": "將所有快捷鍵重設為預設值", - "confirm_reset": "您確定要將所有鍵盤快捷鍵重設為預設值嗎?" + "confirm_reset": "您確定要將所有鍵盤快捷鍵重設為預設值嗎?", + "no_results": "未找到符合 '{{filter}}' 的捷徑" }, "spellcheck": { "title": "拼寫檢查", @@ -1583,7 +1578,9 @@ "print_report_collection_content_one": "集合中的 {{count}} 篇筆記無法列印,因為它們不被支援或受到保護。", "print_report_collection_content_other": "", "print_report_collection_details_button": "查看詳情", - "print_report_collection_details_ignored_notes": "忽略的筆記" + "print_report_collection_details_ignored_notes": "忽略的筆記", + "print_report_error_title": "列印失敗", + "print_report_stack_trace": "堆棧追蹤" }, "note_title": { "placeholder": "請輸入筆記標題...", @@ -2077,7 +2074,8 @@ "raster": "柵格", "vector_light": "向量(淺色)", "vector_dark": "向量(深色)", - "show-scale": "顯示比例尺" + "show-scale": "顯示比例尺", + "show-labels": "顯示標記名稱" }, "table_context_menu": { "delete_row": "刪除列" @@ -2156,7 +2154,6 @@ "app-restart-required": "(需要重啟程式以套用更改)" }, "pagination": { - "page_title": "第 {{startIndex}} - {{endIndex}} 頁", "total_notes": "{{count}} 筆記" }, "collections": { @@ -2272,9 +2269,57 @@ }, "mobile_tab_switcher": { "more_options": "更多選項", - "title_one": "{{count}} 個分頁" + "title_one": "{{count}} 個分頁", + "title_other": "" }, "platform_indicator": { "available_on": "可於 {{platform}} 使用" + }, + "bookmark_buttons": { + "bookmarks": "書籤" + }, + "render": { + "setup_title": "在此筆記中顯示自訂 HTML 或 Preact JSX", + "setup_create_sample_preact": "使用 Preact 建立範例筆記", + "setup_create_sample_html": "使用 HTML 建立範例筆記", + "setup_sample_created": "已建立一個範例筆記作為子筆記。", + "disabled_description": "此渲染筆記來自外部來源。為保護您免受惡意內容侵害,此功能預設為停用狀態。啟用前請務必確認來源可信。", + "disabled_button_enable": "啟用渲染筆記" + }, + "web_view_setup": { + "title": "將網頁直接匯入 Trilium 建立即時預覽", + "url_placeholder": "輸入或貼上網站網址,例如 https://triliumnotes.org", + "create_button": "建立網頁檢視", + "invalid_url_title": "無效地址", + "invalid_url_message": "請輸入有效的網址,例如 https://triliumnotes.org。", + "disabled_description": "此網頁檢視來自外部來源。為協助保護您免受網路釣魚或惡意內容侵害,內容不會自動載入。若您信任來源,可手動啟用此功能。", + "disabled_button_enable": "啟用網頁檢視" + }, + "active_content_badges": { + "type_icon_pack": "圖示包", + "type_backend_script": "後端腳本", + "type_frontend_script": "前端腳本", + "type_widget": "元件", + "type_app_css": "自訂 CSS", + "type_render_note": "渲染筆記", + "type_web_view": "網頁顯示", + "type_app_theme": "自訂主題", + "toggle_tooltip_enable_tooltip": "點擊以啟用此 {{type}}。", + "toggle_tooltip_disable_tooltip": "點擊以停用此 {{type}}。", + "menu_docs": "打開文件", + "menu_execute_now": "立即執行腳本", + "menu_run": "自動執行", + "menu_run_disabled": "手動", + "menu_run_backend_startup": "當後端啟動時", + "menu_run_hourly": "每小時", + "menu_run_daily": "每日", + "menu_run_frontend_startup": "當桌面前端啟動時", + "menu_run_mobile_startup": "當移動前端啟動時", + "menu_change_to_widget": "更改為元件", + "menu_change_to_frontend_script": "更改為前端腳本", + "menu_theme_base": "主題基底" + }, + "setup_form": { + "more_info": "了解更多" } } diff --git a/apps/client/src/translations/uk/translation.json b/apps/client/src/translations/uk/translation.json index 3d0614fdfe..c2c8a5588d 100644 --- a/apps/client/src/translations/uk/translation.json +++ b/apps/client/src/translations/uk/translation.json @@ -1130,15 +1130,6 @@ "default_new_note_title": "нова нотатка", "click_on_canvas_to_place_new_note": "Натисніть на полотно, щоб розмістити нову нотатку" }, - "render": { - "note_detail_render_help_1": "Ця довідка відображається, оскільки ця нотатка типу Render HTML не має необхідного зв'язку для належного функціонування.", - "note_detail_render_help_2": "Тип нотатки Render HTML використовується для скриптів. Коротше кажучи, у вас є нотатка з HTML-кодом (за бажанням з деяким JavaScript), і ця нотатка її відобразить. Щоб це запрацювало, вам потрібно визначити відношення під назвою \"renderNote\", яке вказує на нотатку HTML для відображення." - }, - "web_view": { - "web_view": "Веб-перегляд", - "embed_websites": "Нотатка типу Веб-перегляд дозволяє вбудовувати веб-сайти в Trilium.", - "create_label": "Для початку створіть мітку з URL-адресою, яку ви хочете вбудувати, наприклад, #webViewSrc=\"https://www.google.com\"" - }, "backend_log": { "refresh": "Оновити" }, @@ -2072,7 +2063,6 @@ "app-restart-required": "(щоб зміни набули чинності, потрібен перезапуск програми)" }, "pagination": { - "page_title": "Сторінка {{startIndex}} - {{endIndex}}", "total_notes": "{{count}} нотаток" }, "collections": { diff --git a/apps/client/src/types-lib.d.ts b/apps/client/src/types-lib.d.ts index aa125f389d..4f942b8cb6 100644 --- a/apps/client/src/types-lib.d.ts +++ b/apps/client/src/types-lib.d.ts @@ -63,11 +63,13 @@ declare global { declare module "preact" { namespace JSX { + interface ElectronWebViewElement extends JSX.HTMLAttributes { + src: string; + class: string; + } + interface IntrinsicElements { - webview: { - src: string; - class: string; - } + webview: ElectronWebViewElement; } } } diff --git a/apps/client/src/types.d.ts b/apps/client/src/types.d.ts index 2e2a36e6ee..f7673901c1 100644 --- a/apps/client/src/types.d.ts +++ b/apps/client/src/types.d.ts @@ -119,7 +119,7 @@ declare global { setNote(noteId: string); } - var logError: (message: string, e?: Error | string) => void; + var logError: (message: string, e?: unknown) => void; var logInfo: (message: string) => void; var glob: CustomGlobals; //@ts-ignore diff --git a/apps/client/src/widgets/NoteDetail.tsx b/apps/client/src/widgets/NoteDetail.tsx index 78450811da..1b2cc8f8cc 100644 --- a/apps/client/src/widgets/NoteDetail.tsx +++ b/apps/client/src/widgets/NoteDetail.tsx @@ -1,6 +1,7 @@ import "./NoteDetail.css"; import clsx from "clsx"; +import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js"; import { isValidElement, VNode } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; @@ -355,6 +356,14 @@ export function checkFullHeight(noteContext: NoteContext | undefined, type: Exte // https://github.com/zadam/trilium/issues/2522 const isBackendNote = noteContext?.noteId === "_backendLog"; const isFullHeightNoteType = type && TYPE_MAPPINGS[type].isFullHeight; + + // Allow vertical centering when there are no results. + if (type === "book" && + [ "grid", "list" ].includes(noteContext.note?.getLabelValue("viewType") ?? "grid") && + !noteContext.note?.hasChildren()) { + return true; + } + return (!noteContext?.hasNoteList() && isFullHeightNoteType) || noteContext?.viewScope?.viewMode === "attachments" || isBackendNote; @@ -370,7 +379,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(<> +

{printReport.message}

+
+ {t("note_detail.print_report_stack_trace")} +
{printReport.stack}
+
+ , { + 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", diff --git a/apps/client/src/widgets/PromotedAttributes.css b/apps/client/src/widgets/PromotedAttributes.css index 6e3c7795d1..ef15905192 100644 --- a/apps/client/src/widgets/PromotedAttributes.css +++ b/apps/client/src/widgets/PromotedAttributes.css @@ -16,6 +16,10 @@ body.mobile .promoted-attributes-widget { display: table; } +body.experimental-feature-new-layout .promoted-attributes-container { + max-height: unset; +} + .promoted-attribute-cell { display: flex; align-items: center; @@ -94,4 +98,4 @@ body.mobile .promoted-attributes-widget { background: rgba(0, 0, 0, 0.5); transform: rotate(45deg); pointer-events: none; -} \ No newline at end of file +} diff --git a/apps/client/src/widgets/buttons/global_menu.tsx b/apps/client/src/widgets/buttons/global_menu.tsx index 9db0393692..25f48c5db2 100644 --- a/apps/client/src/widgets/buttons/global_menu.tsx +++ b/apps/client/src/widgets/buttons/global_menu.tsx @@ -47,6 +47,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout: > {isMobile() && <> + } diff --git a/apps/client/src/widgets/collections/NoteList.css b/apps/client/src/widgets/collections/NoteList.css index 449f45d97c..d312f6a427 100644 --- a/apps/client/src/widgets/collections/NoteList.css +++ b/apps/client/src/widgets/collections/NoteList.css @@ -2,8 +2,12 @@ min-height: 0; max-width: var(--max-content-width); /* Inherited from .note-split */ - overflow: auto; + overflow: visible; contain: none !important; + + &.full-height { + overflow: auto; + } } body.prefers-centered-content .note-list-widget:not(.full-height) { @@ -19,14 +23,3 @@ body.prefers-centered-content .note-list-widget:not(.full-height) { .note-list-widget video { height: 100%; } - -/* #region Pagination */ -.note-list-pager { - font-size: 1rem; - - span.current-page { - text-decoration: underline; - font-weight: bold; - } -} -/* #endregion */ diff --git a/apps/client/src/widgets/collections/Pagination.css b/apps/client/src/widgets/collections/Pagination.css new file mode 100644 index 0000000000..93ee13a76d --- /dev/null +++ b/apps/client/src/widgets/collections/Pagination.css @@ -0,0 +1,88 @@ +:where(.note-list-pager) { + --note-list-pager-page-button-width: 40px; + --note-list-pager-page-button-gap: 3px; + --note-list-pager-ellipsis-width: 20px; + --note-list-pager-justify-content: flex-end; + + --note-list-pager-current-page-button-background-color: var(--button-group-active-button-background); + --note-list-pager-current-page-button-text-color: var(--button-group-active-button-text-color); +} + +.note-list-pager-container { + display: flex; + flex-direction: column; + width: 100%; + container: note-list-pager / inline-size; +} + +.note-list-pager { + display: flex; + align-items: center; + font-size: .8rem; + align-self: var(--note-list-pager-justify-content); + + .note-list-pager-nav-button { + --icon-button-icon-ratio: .75; + } + + .note-list-pager-page-button-container { + display: flex; + align-items: baseline; + justify-content: space-around; + gap: var(--note-list-pager-page-button-gap); + + &.note-list-pager-ellipsis-present { + /* Prevent the prev/next buttons from shifting when ellipses appear or disappear */ + --_gap-max-width: calc((var(--note-list-pager-page-button-count) + 2) * var(--note-list-pager-page-button-gap)); + + min-width: calc(var(--note-list-pager-page-button-count) * var(--note-list-pager-page-button-width) + + (var(--note-list-pager-ellipsis-width) * 2) + + var(--_gap-max-width)); + } + + .note-list-pager-page-button { + min-width: var(--note-list-pager-page-button-width); + padding-inline: 0; + padding-block: 4px; + + &.note-list-pager-page-button-current { + background: var(--note-list-pager-current-page-button-background-color); + color: var(--note-list-pager-current-page-button-text-color); + font-weight: bold; + opacity: unset; + } + } + + .note-list-pager-ellipsis { + display: inline-block; + width: var(--note-list-pager-ellipsis-width); + text-align: center; + opacity: .5; + } + } + + .note-list-pager-narrow-counter { + display: none; + min-width: 60px; + text-align: center; + white-space: nowrap; + } + + .note-list-pager-total-count { + margin-inline-start: 8px; + opacity: .5; + white-space: nowrap; + } + + @container note-list-pager (max-width: 550px) { + .note-list-pager-page-button-container, + .note-list-pager-total-count { + display: none; + } + + .note-list-pager-narrow-counter { + display: block; + } + } +} + diff --git a/apps/client/src/widgets/collections/Pagination.tsx b/apps/client/src/widgets/collections/Pagination.tsx index 6b74964a64..26d22215cb 100644 --- a/apps/client/src/widgets/collections/Pagination.tsx +++ b/apps/client/src/widgets/collections/Pagination.tsx @@ -4,6 +4,10 @@ import FNote from "../../entities/fnote"; import froca from "../../services/froca"; import { useNoteLabelInt } from "../react/hooks"; import { t } from "../../services/i18n"; +import ActionButton from "../react/ActionButton"; +import Button from "../react/Button"; +import "./Pagination.css"; +import clsx from "clsx"; interface PaginationContext { page: number; @@ -17,46 +21,106 @@ interface PaginationContext { export function Pager({ page, pageSize, setPage, pageCount, totalNotes }: Omit) { if (pageCount < 2) return; - let lastPrinted = false; - let children: ComponentChildren[] = []; - for (let i = 1; i <= pageCount; i++) { - if (pageCount < 20 || i <= 5 || pageCount - i <= 5 || Math.abs(page - i) <= 2) { - lastPrinted = true; - - const startIndex = (i - 1) * pageSize + 1; - const endIndex = Math.min(totalNotes, i * pageSize); - - if (i !== page) { - children.push(( - setPage(i)} - > - {i} - - )) - } else { - // Current page - children.push({i}) - } - - children.push(<>{" "} {" "}); - } else if (lastPrinted) { - children.push(<>{"... "} {" "}); - lastPrinted = false; - } - } - return ( -
- {children} +
+
+ setPage(page - 1)} + /> - ({t("pagination.total_notes", { count: totalNotes })}) + +
+ {page} / {pageCount} +
+ + setPage(page + 1)} + /> + +
+ {t("pagination.total_notes", { count: totalNotes })} +
+
) } +interface PageButtonsProps { + page: number; + setPage: Dispatch>; + pageCount: number; +} + +function PageButtons(props: PageButtonsProps) { + const maxButtonCount = 9; + const maxLeftRightSegmentLength = 2; + + // The left-side segment + const leftLength = Math.min(props.pageCount, maxLeftRightSegmentLength); + const leftStart = 1; + + // The middle segment + const middleMaxLength = maxButtonCount - maxLeftRightSegmentLength * 2; + const middleLength = Math.min(props.pageCount - leftLength, middleMaxLength); + let middleStart = props.page - Math.floor(middleLength / 2); + middleStart = Math.max(middleStart, leftLength + 1); + + // The right-side segment + const rightLength = Math.min(props.pageCount - (middleLength + leftLength), maxLeftRightSegmentLength); + const rightStart = props.pageCount - rightLength + 1; + middleStart = Math.min(middleStart, rightStart - middleLength); + + const totalButtonCount = leftLength + middleLength + rightLength; + const hasLeadingEllipsis = (middleStart - leftLength > 1); + const hasTrailingEllipsis = (rightStart - (middleStart + middleLength - 1) > 1); + + return
+ {[ + ...createSegment(leftStart, leftLength, props.page, props.setPage, false), + ...createSegment(middleStart, middleLength, props.page, props.setPage, hasLeadingEllipsis), + ...createSegment(rightStart, rightLength, props.page, props.setPage, hasTrailingEllipsis), + ]} +
; +} + +function createSegment(start: number, length: number, currentPage: number, setPage: Dispatch>, prependEllipsis: boolean): ComponentChildren[] { + const children: ComponentChildren[] = []; + + if (prependEllipsis) { + children.push(...); + } + + for (let i = 0; i < length; i++) { + const pageNum = start + i; + const isCurrent = (pageNum === currentPage); + children.push(( +
); } +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 ; + return ; } if (location) { const latLng = location?.split(",", 2).map((el) => parseFloat(el)) as [ number, number ] | undefined; if (!latLng) return; - return ; + return ; } } -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(); const blob = useNoteBlob(note); @@ -256,7 +284,7 @@ function NoteGpxTrack({ note }: { note: FNote }) { const options = useMemo(() => ({ 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 && ; } diff --git a/apps/client/src/widgets/collections/geomap/map.tsx b/apps/client/src/widgets/collections/geomap/map.tsx index 035f863cc8..19a4586c83 100644 --- a/apps/client/src/widgets/collections/geomap/map.tsx +++ b/apps/client/src/widgets/collections/geomap/map.tsx @@ -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; 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(null); const containerRef = useSyncedRef(_containerRef); @@ -49,8 +49,6 @@ export default function Map({ coordinates, zoom, layerName, viewportChanged, chi const [ layer, setLayer ] = useState(); 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 (
{children} diff --git a/apps/client/src/widgets/collections/geomap/map_layer.ts b/apps/client/src/widgets/collections/geomap/map_layer.ts index 7b12a10761..bb5f6174e6 100644 --- a/apps/client/src/widgets/collections/geomap/map_layer.ts +++ b/apps/client/src/widgets/collections/geomap/map_layer.ts @@ -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 = { +export const MAP_LAYERS: Record = { "openstreetmap": { name: "OpenStreetMap", type: "raster", diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.css b/apps/client/src/widgets/collections/legacy/ListOrGridView.css index 1bfa389e5c..222682cc9f 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.css +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.css @@ -1,5 +1,5 @@ .note-list { - overflow: hidden; + overflow: visible; position: relative; height: 100%; } @@ -100,23 +100,206 @@ overflow: auto; } -.note-expander { - font-size: x-large; - position: relative; - top: 3px; - cursor: pointer; +/* #region List view */ + +@keyframes note-preview-show { + from { + opacity: 0; + } to { + opacity: 1; + } } -.note-list-pager { - text-align: center; +.nested-note-list { + --card-nested-section-indent: 25px; + + &.search-results { + --card-nested-section-indent: 32px; + } } -.note-list.list-view .note-path { - margin-left: 0.5em; - vertical-align: middle; - opacity: 0.5; +/* List item */ +.nested-note-list-item { + h5 { + display: flex; + align-items: center; + font-size: 1em; + font-weight: normal; + margin: 0; + } + + .note-expander { + margin-inline-end: 4px; + font-size: x-large; + cursor: pointer; + } + + .tn-icon { + margin-inline-end: 8px; + color: var(--note-list-view-icon-color); + font-size: 1.2em; + } + + .note-book-title { + --link-hover-background: transparent; + --link-hover-color: currentColor; + color: inherit; + font-weight: normal; + } + + .note-path { + margin-left: 0.5em; + vertical-align: middle; + opacity: 0.5; + } + + .note-list-attributes { + flex-grow: 1; + margin-inline-start: 1em; + text-align: right; + font-size: .75em; + opacity: .75; + } + + .nested-note-list-item-menu { + margin-inline-start: 8px; + flex-shrink: 0; + } + + &.archived { + span.tn-icon + span, + .tn-icon { + opacity: .6; + } + } + + &.use-note-color { + span.tn-icon + span, + .nested-note-list:not(.search-results) & .tn-icon, + .rendered-note-attributes { + color: var(--custom-color); + } + } } +.nested-note-list:not(.search-results) h5 { + span.tn-icon + span, + .note-list-attributes { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } +} + +/* List item (search results view) */ +.nested-note-list.search-results .nested-note-list-item { + span.tn-icon + span > span { + display: flex; + flex-direction: column-reverse; + align-items: flex-start; + } + + small { + line-height: .85em; + } + + .note-path { + margin-left: 0; + font-size: .85em; + line-height: .85em; + font-weight: 500; + letter-spacing: .5pt; + } + + .tn-icon { + display: flex; + flex-shrink: 0; + justify-content: center; + align-items: center; + width: 1.75em; + height: 1.75em; + margin-inline-end: 12px; + border-radius: 50%; + background: var(--note-icon-custom-background-color, var(--note-list-view-large-icon-background)); + font-size: 1.2em; + color: var(--note-icon-custom-color, var(--note-list-view-large-icon-color)); + } + + h5 .ck-find-result { + background: var(--note-list-view-search-result-highlight-background); + color: var(--note-list-view-search-result-highlight-color); + font-weight: 600; + text-decoration: underline; + } +} + +/* Note content preview */ +.nested-note-list .note-book-content { + display: none; + outline: 1px solid var(--note-list-view-content-background); + border-radius: 8px; + background-color: var(--note-list-view-content-background); + overflow: hidden; + user-select: text; + font-size: .85rem; + animation: note-preview-show .25s ease-out; + will-change: opacity; + + &.note-book-content-ready { + display: block; + } + + > .rendered-content > *:last-child { + margin-bottom: 0; + } + + &.type-text { + padding: 8px 24px; + + .ck-content > *:last-child { + margin-bottom: 0; + } + } + + &.type-protectedSession { + padding: 20px; + } + + &.type-image { + padding: 0; + } + + &.type-pdf { + iframe { + height: 50vh; + } + + .file-footer { + padding: 8px; + } + } + + &.type-webView { + display: flex; + flex-direction: column; + justify-content: center; + min-height: 50vh; + } + + .ck-find-result { + outline: 2px solid var(--note-list-view-content-search-result-highlight-background); + border-radius: 4px; + background: var(--note-list-view-content-search-result-highlight-background); + color: var(--note-list-view-content-search-result-highlight-color); + } +} + +.note-content-preview:has(.note-book-content:empty) { + display: none; +} + +/* #endregion */ + /* #region Grid view */ .note-list.grid-view .note-list-container { display: flex; @@ -128,6 +311,10 @@ border: 1px solid transparent; } +body.mobile .note-list.grid-view .note-book-card { + flex-basis: 150px; +} + .note-list.grid-view .note-book-card { max-height: 300px; } diff --git a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx index 61c7193a6e..cdde8a6087 100644 --- a/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx +++ b/apps/client/src/widgets/collections/legacy/ListOrGridView.tsx @@ -1,4 +1,5 @@ import "./ListOrGridView.css"; +import { Card, CardSection } from "../../react/Card"; import { useEffect, useRef, useState } from "preact/hooks"; @@ -14,6 +15,11 @@ import NoteLink from "../../react/NoteLink"; import { ViewModeProps } from "../interface"; import { Pager, usePagination } from "../Pagination"; import { filterChildNotes, useFilteredNoteIds } from "./utils"; +import { JSX } from "preact/jsx-runtime"; +import { clsx } from "clsx"; +import ActionButton from "../../react/ActionButton"; +import linkContextMenuService from "../../../menus/link_context_menu"; +import { TargetedMouseEvent } from "preact"; export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens }: ViewModeProps<{}>) { const expandDepth = useExpansionDepth(note); @@ -33,7 +39,7 @@ export function ListView({ note, noteIds: unfilteredNoteIds, highlightedTokens } { noteIds.length > 0 &&
{!hasCollectionProperties && } - +
} @@ -93,27 +99,52 @@ function ListNoteCard({ note, parentNote, highlightedTokens, currentLevel, expan // Reset expand state if switching to another note, or if user manually toggled expansion state. useEffect(() => setExpanded(currentLevel <= expandDepth), [ note, currentLevel, expandDepth ]); + let subSections: JSX.Element | undefined = undefined; + if (isExpanded) { + subSections = <> + + + + + + + } + return ( -
-
- setExpanded(!isExpanded)} - /> - +
+ setExpanded(!isExpanded)}/> - + + openNoteMenu(notePath, e)} + />
- - {isExpanded && <> - - - } -
+ ); } @@ -165,6 +196,9 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc const contentRef = useRef(null); const highlightSearch = useImperativeSearchHighlighlighting(highlightedTokens); + const [ready, setReady] = useState(false); + const [noteType, setNoteType] = useState("none"); + useEffect(() => { content_renderer.getRenderedContent(note, { trim, @@ -179,17 +213,19 @@ export function NoteContent({ note, trim, noChildrenList, highlightedTokens, inc } else { contentRef.current.replaceChildren(); } - contentRef.current.classList.add(`type-${type}`); highlightSearch(contentRef.current); + setNoteType(type); + setReady(true); }) .catch(e => { console.warn(`Caught error while rendering note '${note.noteId}' of type '${note.type}'`); console.error(e); contentRef.current?.replaceChildren(t("collections.rendering_error")); + setReady(true); }); }, [ note, highlightedTokens ]); - return
; + return
; } function NoteChildren({ note, parentNote, highlightedTokens, currentLevel, expandDepth, includeArchived }: { @@ -238,3 +274,8 @@ function useExpansionDepth(note: FNote) { return parseInt(expandDepth, 10); } + +function openNoteMenu(notePath, e: TargetedMouseEvent) { + linkContextMenuService.openContextMenu(notePath, e); + e.stopPropagation() +} diff --git a/apps/client/src/widgets/containers/scrolling_container.css b/apps/client/src/widgets/containers/scrolling_container.css index 0e590801c4..a3fae557a3 100644 --- a/apps/client/src/widgets/containers/scrolling_container.css +++ b/apps/client/src/widgets/containers/scrolling_container.css @@ -19,6 +19,10 @@ } } +body.mobile .scrolling-container { + --content-margin-inline: 8px; +} + .note-split.type-code:not(.mime-text-x-sqlite) { &> .scrolling-container { background-color: var(--code-background-color); diff --git a/apps/client/src/widgets/dialogs/PopupEditor.css b/apps/client/src/widgets/dialogs/PopupEditor.css index 3357b00f3e..84f4c93197 100644 --- a/apps/client/src/widgets/dialogs/PopupEditor.css +++ b/apps/client/src/widgets/dialogs/PopupEditor.css @@ -32,6 +32,12 @@ body.mobile .modal.popup-editor-dialog .modal-dialog { display: flex; align-items: center; margin-block: 0; + + .note-icon-widget { + display: flex; + align-items: center; + margin-inline-start: 0; + } } .modal.popup-editor-dialog .modal-header .note-title-widget { diff --git a/apps/client/src/widgets/dialogs/PopupEditor.tsx b/apps/client/src/widgets/dialogs/PopupEditor.tsx index a7f3fde393..07363b2e91 100644 --- a/apps/client/src/widgets/dialogs/PopupEditor.tsx +++ b/apps/client/src/widgets/dialogs/PopupEditor.tsx @@ -67,10 +67,7 @@ export default function PopupEditor() { - - {isNewLayout && } - } + title={} customTitleBarButtons={[{ iconClassName: "bx-expand-alt", title: t("popup-editor.maximize"), @@ -123,6 +120,7 @@ export function TitleRow() {
+ {isNewLayout && }
); } diff --git a/apps/client/src/widgets/dialogs/bulk_actions.tsx b/apps/client/src/widgets/dialogs/bulk_actions.tsx index 05033255c4..cbb04a404a 100644 --- a/apps/client/src/widgets/dialogs/bulk_actions.tsx +++ b/apps/client/src/widgets/dialogs/bulk_actions.tsx @@ -57,7 +57,7 @@ export default function BulkActionsDialog() { className="bulk-actions-dialog" size="xl" title={t("bulk_actions.bulk_actions")} - footer={
); } diff --git a/apps/client/src/widgets/layout/StatusBar.css b/apps/client/src/widgets/layout/StatusBar.css index a0b22c8d26..c8d01c83be 100644 --- a/apps/client/src/widgets/layout/StatusBar.css +++ b/apps/client/src/widgets/layout/StatusBar.css @@ -37,6 +37,10 @@ &:hover { background: var(--input-background-color); } + + .text { + white-space: nowrap; + } } .status-bar-dropdown-button { diff --git a/apps/client/src/widgets/layout/StatusBar.tsx b/apps/client/src/widgets/layout/StatusBar.tsx index c608c8f203..16f7ad1123 100644 --- a/apps/client/src/widgets/layout/StatusBar.tsx +++ b/apps/client/src/widgets/layout/StatusBar.tsx @@ -414,7 +414,7 @@ function NotePaths({ note, hoistedNoteId, notePath }: StatusBarContext) { const dropdownRef = useRef(null); const sortedNotePaths = useSortedNotePaths(note, hoistedNoteId); const count = sortedNotePaths?.length ?? 0; - const enabled = count > 1; + const enabled = true; // Keyboard shortcut. useTriliumEvent("toggleRibbonTabNotePaths", () => enabled && dropdownRef.current?.show()); diff --git a/apps/client/src/widgets/mobile_widgets/TabSwitcher.css b/apps/client/src/widgets/mobile_widgets/TabSwitcher.css index 8be65240b2..58b6c1fbc3 100644 --- a/apps/client/src/widgets/mobile_widgets/TabSwitcher.css +++ b/apps/client/src/widgets/mobile_widgets/TabSwitcher.css @@ -35,11 +35,6 @@ display: flex; flex-direction: column; - &.with-hue { - background-color: hsl(var(--bg-hue), 8.8%, 11.2%); - border-color: hsl(var(--bg-hue), 9.4%, 25.1%); - } - &.active { outline: 4px solid var(--more-accented-background-color); background: var(--card-background-hover-color); diff --git a/apps/client/src/widgets/mobile_widgets/sidebar_container.ts b/apps/client/src/widgets/mobile_widgets/sidebar_container.ts index ef719d36a9..f79d8a72c2 100644 --- a/apps/client/src/widgets/mobile_widgets/sidebar_container.ts +++ b/apps/client/src/widgets/mobile_widgets/sidebar_container.ts @@ -13,7 +13,7 @@ const DRAG_OPEN_THRESHOLD = 10; /** The number of pixels the user has to drag across the screen to the right when the sidebar is closed to trigger the drag open animation. */ const DRAG_CLOSED_START_THRESHOLD = 10; /** The number of pixels the user has to drag across the screen to the left when the sidebar is opened to trigger the drag close animation. */ -const DRAG_OPENED_START_THRESHOLD = 80; +const DRAG_OPENED_START_THRESHOLD = 100; export default class SidebarContainer extends FlexContainer { private screenName: Screen; @@ -54,7 +54,7 @@ export default class SidebarContainer extends FlexContainer { this.startX = x; // Prevent dragging if too far from the edge of the screen and the menu is closed. - let dragRefX = glob.isRtl ? this.screenWidth - x : x; + const dragRefX = glob.isRtl ? this.screenWidth - x : x; if (dragRefX > 30 && this.currentTranslate === -100) { return; } @@ -89,7 +89,7 @@ export default class SidebarContainer extends FlexContainer { } } else if (this.dragState === DRAG_STATE_DRAGGING) { const width = this.sidebarEl.offsetWidth; - let translatePercentage = Math.min(0, Math.max(this.currentTranslate + (deltaX / width) * 100, -100)); + const translatePercentage = Math.min(0, Math.max(this.currentTranslate + (deltaX / width) * 100, -100)); const backdropOpacity = Math.max(0, 1 + translatePercentage / 100); this.translatePercentage = translatePercentage; if (glob.isRtl) { @@ -160,12 +160,10 @@ export default class SidebarContainer extends FlexContainer { this.sidebarEl.classList.toggle("show", isOpen); if (isOpen) { this.sidebarEl.style.transform = "translateX(0)"; + } else if (glob.isRtl) { + this.sidebarEl.style.transform = "translateX(100%)"; } else { - if (glob.isRtl) { - this.sidebarEl.style.transform = "translateX(100%)" - } else { - this.sidebarEl.style.transform = "translateX(-100%)"; - } + this.sidebarEl.style.transform = "translateX(-100%)"; } this.sidebarEl.style.transition = this.originalSidebarTransition; diff --git a/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx b/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx index 8e689954b0..b87e8cb90e 100644 --- a/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx +++ b/apps/client/src/widgets/mobile_widgets/toggle_sidebar_button.tsx @@ -1,5 +1,5 @@ -import ActionButton from "../react/ActionButton"; import { t } from "../../services/i18n"; +import ActionButton from "../react/ActionButton"; import { useNoteContext } from "../react/hooks"; export default function ToggleSidebarButton() { @@ -10,10 +10,15 @@ export default function ToggleSidebarButton() { { noteContext?.isMainContext() && parentComponent?.triggerCommand("setActiveScreen", { - screen: "tree" - })} + onClick={(e) => { + // Remove focus to prevent tooltip showing on top of the sidebar. + (e.currentTarget as HTMLButtonElement).blur(); + + parentComponent?.triggerCommand("setActiveScreen", { + screen: "tree" + }); + }} />}
- ) + ); } diff --git a/apps/client/src/widgets/note_bars/CollectionProperties.css b/apps/client/src/widgets/note_bars/CollectionProperties.css index 99700f77a7..c8802a42a0 100644 --- a/apps/client/src/widgets/note_bars/CollectionProperties.css +++ b/apps/client/src/widgets/note_bars/CollectionProperties.css @@ -5,7 +5,7 @@ align-items: center; width: 100%; max-width: unset; - font-size: 0.8em; + font-size: 0.8rem; .dropdown-menu { input.form-control { diff --git a/apps/client/src/widgets/note_bars/CollectionProperties.tsx b/apps/client/src/widgets/note_bars/CollectionProperties.tsx index 5dba675e6d..66bfb32c45 100644 --- a/apps/client/src/widgets/note_bars/CollectionProperties.tsx +++ b/apps/client/src/widgets/note_bars/CollectionProperties.tsx @@ -2,18 +2,16 @@ import "./CollectionProperties.css"; import { t } from "i18next"; import { ComponentChildren } from "preact"; -import { useContext, useRef } from "preact/hooks"; -import { Fragment } from "preact/jsx-runtime"; +import { useRef } from "preact/hooks"; import FNote from "../../entities/fnote"; import { ViewTypeOptions } from "../collections/interface"; import Dropdown from "../react/Dropdown"; -import { FormDropdownDivider, FormDropdownSubmenu, FormListItem, FormListToggleableItem } from "../react/FormList"; -import FormTextBox from "../react/FormTextBox"; -import { useNoteLabel, useNoteLabelBoolean, useNoteLabelWithDefault, useNoteProperty, useTriliumEvent } from "../react/hooks"; +import { FormDropdownDivider, FormListItem } from "../react/FormList"; +import { useNoteProperty, useTriliumEvent } from "../react/hooks"; import Icon from "../react/Icon"; -import { ParentComponent } from "../react/react_utils"; -import { bookPropertiesConfig, BookProperty, ButtonProperty, CheckBoxProperty, ComboBoxItem, ComboBoxProperty, NumberProperty, SplitButtonProperty } from "../ribbon/collection-properties-config"; +import { CheckBoxProperty, ViewProperty } from "../react/NotePropertyMenu"; +import { bookPropertiesConfig } from "../ribbon/collection-properties-config"; import { useViewType, VIEW_TYPE_MAPPINGS } from "../ribbon/CollectionPropertiesTab"; export const ICON_MAPPINGS: Record = { @@ -85,9 +83,11 @@ function ViewOptions({ note, viewType }: { note: FNote, viewType: ViewTypeOption - {properties.map(property => ( - + {properties.map((property, index) => ( + ))} {properties.length > 0 && } @@ -107,127 +107,3 @@ function ViewOptions({ note, viewType }: { note: FNote, viewType: ViewTypeOption ); } - -function ViewProperty({ note, property }: { note: FNote, property: BookProperty }) { - switch (property.type) { - case "button": - return ; - case "split-button": - return ; - case "checkbox": - return ; - case "number": - return ; - case "combobox": - return ; - } -} - -function ButtonPropertyView({ note, property }: { note: FNote, property: ButtonProperty }) { - const parentComponent = useContext(ParentComponent); - - return ( - { - if (!parentComponent) return; - property.onClick({ - note, - triggerCommand: parentComponent.triggerCommand.bind(parentComponent) - }); - }} - >{property.label} - ); -} - -function SplitButtonPropertyView({ note, property }: { note: FNote, property: SplitButtonProperty }) { - const parentComponent = useContext(ParentComponent); - const ItemsComponent = property.items; - const clickContext = parentComponent && { - note, - triggerCommand: parentComponent.triggerCommand.bind(parentComponent) - }; - - return (parentComponent && - clickContext && property.onClick(clickContext)} - > - - - ); -} - -function NumberPropertyView({ note, property }: { note: FNote, property: NumberProperty }) { - //@ts-expect-error Interop with text box which takes in string values even for numbers. - const [ value, setValue ] = useNoteLabel(note, property.bindToLabel); - const disabled = property.disabled?.(note); - - return ( - e.stopPropagation()} - > - {property.label} - - - ); -} - -function ComboBoxPropertyView({ note, property }: { note: FNote, property: ComboBoxProperty }) { - const [ value, setValue ] = useNoteLabelWithDefault(note, property.bindToLabel, property.defaultValue ?? ""); - - function renderItem(option: ComboBoxItem) { - return ( - setValue(option.value)} - > - {option.label} - - ); - } - - return ( - - {(property.options).map((option, index) => { - if ("items" in option) { - return ( - - {option.title} - {option.items.map(renderItem)} - {index < property.options.length - 1 && } - - ); - } - return renderItem(option); - - })} - - ); -} - -function CheckBoxPropertyView({ note, property }: { note: FNote, property: CheckBoxProperty }) { - const [ value, setValue ] = useNoteLabelBoolean(note, property.bindToLabel); - return ( - - ); -} diff --git a/apps/client/src/widgets/note_icon.tsx b/apps/client/src/widgets/note_icon.tsx index 9df9ad48f4..31ca7e65b4 100644 --- a/apps/client/src/widgets/note_icon.tsx +++ b/apps/client/src/widgets/note_icon.tsx @@ -69,7 +69,7 @@ function MobileNoteIconSwitcher({ note, icon }: { const [ modalShown, setModalShown ] = useState(false); const { windowWidth } = useWindowSize(); - return (note && + return (
- setModalShown(false)} columnCount={Math.max(1, Math.floor(windowWidth / ICON_SIZE))} /> + {note && setModalShown(false)} columnCount={Math.max(1, Math.floor(windowWidth / ICON_SIZE))} />} ), document.body)}
diff --git a/apps/client/src/widgets/note_tree.css b/apps/client/src/widgets/note_tree.css index dbcb66cbc1..8c4f6ad426 100644 --- a/apps/client/src/widgets/note_tree.css +++ b/apps/client/src/widgets/note_tree.css @@ -9,7 +9,6 @@ border-radius: 0.5em; font-size: 0.7rem; font-weight: normal; - float: right; vertical-align: middle; } diff --git a/apps/client/src/widgets/note_tree.ts b/apps/client/src/widgets/note_tree.ts index 68b0310684..5c2aadb1ea 100644 --- a/apps/client/src/widgets/note_tree.ts +++ b/apps/client/src/widgets/note_tree.ts @@ -1992,7 +1992,7 @@ function buildEnhanceTitle() { if (isSubtreeHidden && count > 0) { const $badge = $(`${count}`); $badge.attr("title", t("note_tree.subtree-hidden-tooltip", { count })); - $span.find(".fancytree-title").append($badge); + $span.append($badge); } }; } diff --git a/apps/client/src/widgets/note_types.tsx b/apps/client/src/widgets/note_types.tsx index e58960d708..d0209bf5a2 100644 --- a/apps/client/src/widgets/note_types.tsx +++ b/apps/client/src/widgets/note_types.tsx @@ -43,7 +43,8 @@ export const TYPE_MAPPINGS: Record = { }, protectedSession: { view: () => import("./type_widgets/ProtectedSession"), - className: "protected-session-password-component" + className: "protected-session-password-component", + isFullHeight: true }, book: { view: () => import("./type_widgets/Book"), diff --git a/apps/client/src/widgets/react/ActionButton.tsx b/apps/client/src/widgets/react/ActionButton.tsx index feb5972ef4..764e155c44 100644 --- a/apps/client/src/widgets/react/ActionButton.tsx +++ b/apps/client/src/widgets/react/ActionButton.tsx @@ -3,6 +3,7 @@ import { useEffect, useRef, useState } from "preact/hooks"; import { CommandNames } from "../../components/app_context"; import keyboard_actions from "../../services/keyboard_actions"; +import { isMobile } from "../../services/utils"; import { useStaticTooltip } from "./hooks"; export interface ActionButtonProps extends Pick, "onClick" | "onAuxClick" | "onContextMenu" | "style"> { @@ -17,6 +18,8 @@ export interface ActionButtonProps extends Pick(null); const [ keyboardShortcut, setKeyboardShortcut ] = useState(); @@ -25,6 +28,7 @@ export default function ActionButton({ text, icon, className, triggerCommand, ti title: keyboardShortcut?.length ? `${text} (${keyboardShortcut?.join(",")})` : text, placement: titlePosition ?? "bottom", fallbackPlacements: [ titlePosition ?? "bottom" ], + trigger: cachedIsMobile ? "focus" : "hover focus", animation: false }); diff --git a/apps/client/src/widgets/react/Button.tsx b/apps/client/src/widgets/react/Button.tsx index ffdc6ddd2c..6269000563 100644 --- a/apps/client/src/widgets/react/Button.tsx +++ b/apps/client/src/widgets/react/Button.tsx @@ -1,13 +1,14 @@ -import type { ComponentChildren, RefObject } from "preact"; -import type { CSSProperties } from "preact/compat"; +import type { ComponentChildren, CSSProperties, RefObject } from "preact"; import { memo } from "preact/compat"; import { useMemo } from "preact/hooks"; import { CommandNames } from "../../components/app_context"; -import { isDesktop } from "../../services/utils"; +import { isDesktop, isMobile } from "../../services/utils"; import ActionButton from "./ActionButton"; import Icon from "./Icon"; +const cachedIsMobile = isMobile(); + export interface ButtonProps { name?: string; /** Reference to the button element. Mostly useful for requesting focus. */ @@ -18,7 +19,7 @@ export interface ButtonProps { keyboardShortcut?: string; /** Called when the button is clicked. If not set, the button will submit the form (if any). */ onClick?: () => void; - primary?: boolean; + kind?: "primary" | "secondary" | "lowProfile"; disabled?: boolean; size?: "normal" | "small" | "micro"; style?: CSSProperties; @@ -26,15 +27,23 @@ export interface ButtonProps { title?: string; } -const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortcut, icon, primary, disabled, size, style, triggerCommand, ...restProps }: ButtonProps) => { +const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortcut, icon, kind, disabled, size, style, triggerCommand, ...restProps }: ButtonProps) => { // Memoize classes array to prevent recreation const classes = useMemo(() => { const classList: string[] = ["btn"]; - if (primary) { - classList.push("btn-primary"); - } else { - classList.push("btn-secondary"); + + switch(kind) { + case "primary": + classList.push("btn-primary"); + break; + case "lowProfile": + classList.push("tn-low-profile"); + break; + default: + classList.push("btn-secondary"); + break; } + if (className) { classList.push(className); } @@ -44,11 +53,11 @@ const Button = memo(({ name, buttonRef, className, text, onClick, keyboardShortc classList.push("btn-micro"); } return classList.join(" "); - }, [primary, className, size]); + }, [kind, className, size]); // Memoize keyboard shortcut rendering const shortcutElements = useMemo(() => { - if (!keyboardShortcut) return null; + if (!keyboardShortcut || cachedIsMobile) return null; const splitShortcut = keyboardShortcut.split("+"); return splitShortcut.map((key, index) => ( <> diff --git a/apps/client/src/widgets/react/Card.css b/apps/client/src/widgets/react/Card.css new file mode 100644 index 0000000000..cabc4a0889 --- /dev/null +++ b/apps/client/src/widgets/react/Card.css @@ -0,0 +1,47 @@ +:where(.tn-card) { + --card-border-radius: 8px; + --card-padding-block: 8px; + --card-padding-inline: 16px; + --card-section-gap: 3px; + --card-nested-section-indent: 30px; +} + +.tn-card-heading { + margin-bottom: 10px; + font-size: .75rem; + font-weight: 600; + letter-spacing: .4pt; + text-transform: uppercase; +} + +.tn-card-body { + display: flex; + flex-direction: column; + gap: var(--card-section-gap); + + .tn-card-section { + padding: var(--card-padding-block) var(--card-padding-inline); + border: 1px solid var(--card-border-color, var(--main-border-color)); + background: var(--card-background-color); + + &:first-of-type { + border-top-left-radius: var(--card-border-radius); + border-top-right-radius: var(--card-border-radius); + } + + &:last-of-type { + border-bottom-left-radius: var(--card-border-radius); + border-bottom-right-radius: var(--card-border-radius); + } + + &.tn-card-section-nested { + padding-left: calc(var(--card-padding-inline) + var(--card-nested-section-indent) * var(--tn-card-section-nesting-level)); + background-color: color-mix(in srgb, var(--card-background-color) calc(100% / (var(--tn-card-section-nesting-level) + 1)) , transparent); + } + + &.tn-card-section-highlight-on-hover:hover { + background-color: var(--card-background-hover-color); + transition: background-color .2s ease-out; + } + } +} \ No newline at end of file diff --git a/apps/client/src/widgets/react/Card.tsx b/apps/client/src/widgets/react/Card.tsx new file mode 100644 index 0000000000..224a151504 --- /dev/null +++ b/apps/client/src/widgets/react/Card.tsx @@ -0,0 +1,63 @@ +import "./Card.css"; +import { ComponentChildren, createContext } from "preact"; +import { JSX } from "preact"; +import { useContext } from "preact/hooks"; +import clsx from "clsx"; + +// #region Card + +export interface CardProps { + className?: string; + heading?: string; +} + +export function Card(props: {children: ComponentChildren} & CardProps) { + return
+ {props.heading &&
{props.heading}
} +
+ {props.children} +
+
; +} + +// #endregion + +// #region Card Section + +export interface CardSectionProps { + className?: string; + subSections?: JSX.Element | JSX.Element[]; + subSectionsVisible?: boolean; + highlightOnHover?: boolean; + onAction?: () => void; +} + +interface CardSectionContextType { + nestingLevel: number; +} + +const CardSectionContext = createContext(undefined); + +export function CardSection(props: {children: ComponentChildren} & CardSectionProps) { + const parentContext = useContext(CardSectionContext); + const nestingLevel = (parentContext && parentContext.nestingLevel + 1) ?? 0; + + return <> +
0, + "tn-card-section-highlight-on-hover": props.highlightOnHover || props.onAction + })} + style={{"--tn-card-section-nesting-level": (nestingLevel) ? nestingLevel : null}} + onClick={props.onAction}> + {props.children} +
+ + {props.subSectionsVisible && props.subSections && + + {props.subSections} + + } + ; +} + +// #endregion \ No newline at end of file diff --git a/apps/client/src/widgets/react/Collapsible.css b/apps/client/src/widgets/react/Collapsible.css index 7acf628f71..00aeb2bf7a 100644 --- a/apps/client/src/widgets/react/Collapsible.css +++ b/apps/client/src/widgets/react/Collapsible.css @@ -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; diff --git a/apps/client/src/widgets/react/Collapsible.tsx b/apps/client/src/widgets/react/Collapsible.tsx index 212de203dc..cdbd0dcac5 100644 --- a/apps/client/src/widgets/react/Collapsible.tsx +++ b/apps/client/src/widgets/react/Collapsible.tsx @@ -57,7 +57,7 @@ export function ExternallyControlledCollapsible({ title, children, className, ex "with-transition": transitionEnabled })}>