Compare commits

...

36 Commits

Author SHA1 Message Date
renovate[bot]
bfaaa7eebb fix(deps): update dependency mind-elixir to v5.7.0 2026-02-02 01:52:48 +00:00
Elian Doran
f8b414c354 feat(etapi): add attachments etapi endpoint (#8578) 2026-02-01 22:34:37 +02:00
Elian Doran
82a21624c3 Translations update from Hosted Weblate (#8579) 2026-02-01 22:32:35 +02:00
Elian Doran
1b212ac720 Improved mobile note actions (#8580) 2026-02-01 22:30:45 +02:00
Elian Doran
c36ce3ea14 fix(mobile/note_actions): insert child note not working 2026-02-01 22:29:43 +02:00
Elian Doran
841fab77a8 chore(client): address requested changes 2026-02-01 22:22:25 +02:00
Elian Doran
fd6f910824 fix(mobile/note_actions): backdrop remains when closing split 2026-02-01 22:02:54 +02:00
Elian Doran
ce9ca1917d fix(mobile/note_actions): reintroduce split buttons 2026-02-01 22:01:26 +02:00
perfectra1n
c702fb273c feat(tests): add tests for new attachments endpoint 2026-02-01 11:46:03 -08:00
Elian Doran
4c72d8691b fix(mobile/note_actions): reintroduce help button 2026-02-01 21:45:43 +02:00
Elian Doran
35ac5fc514 fix(mobile/note_actions): reintroduce insert child note 2026-02-01 21:42:48 +02:00
Elian Doran
92991cc03c fix(promoted_attributes): displayed in non-default view modes 2026-02-01 21:37:20 +02:00
Elian Doran
76492475e3 fix(mobile/note_actions): find not working 2026-02-01 21:27:24 +02:00
Elian Doran
e2363d860c fix(mobile/note_actions): font too big 2026-02-01 21:25:40 +02:00
Elian Doran
c06a90913a fix(mobile/note_actions): submenus not working 2026-02-01 21:12:50 +02:00
Elian Doran
e88c0f7326 fix(mobile/note_actions): toggles on two rows 2026-02-01 21:02:46 +02:00
Elian Doran
2a4280b5bf feat(mobile/note_actions): remove bottom rounded corners 2026-02-01 20:59:50 +02:00
Elian Doran
d3c733c57f feat(mobile/note_actions): add backdrop 2026-02-01 20:57:01 +02:00
Elian Doran
f91add3cd4 chore(mobile/note_actions): position like global menu 2026-02-01 20:53:33 +02:00
Elian Doran
90e3f7508a chore(mobile): enforce new layout 2026-02-01 20:50:00 +02:00
Elian Doran
5e981da4df feat(mobile): use the desktop version of note actions 2026-02-01 20:48:55 +02:00
Aindriú Mac Giolla Eoin
2ddd5d75fc Added translation using Weblate (Irish) 2026-02-01 19:33:10 +01:00
Aindriú Mac Giolla Eoin
88f509cbb6 Added translation using Weblate (Irish) 2026-02-01 19:33:08 +01:00
Aindriú Mac Giolla Eoin
ca161bc881 Added translation using Weblate (Irish) 2026-02-01 19:33:05 +01:00
Aindriú Mac Giolla Eoin
676ca44cdf Added translation using Weblate (Irish) 2026-02-01 19:33:01 +01:00
green
5d0c91202f Translated using Weblate (Japanese)
Currently translated at 100.0% (1767 of 1767 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ja/
2026-02-01 19:32:59 +01:00
Ulices
a166f049d5 Translated using Weblate (Spanish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/es/
2026-02-01 19:32:59 +01:00
noobhjy
0dc4692dfc Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1767 of 1767 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/zh_Hans/
2026-02-01 19:32:59 +01:00
ibs-allaow
996607d096 Translated using Weblate (Arabic)
Currently translated at 59.5% (1053 of 1767 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/ar/
2026-02-01 19:32:58 +01:00
Ulices
bd907ea008 Translated using Weblate (Spanish)
Currently translated at 100.0% (1767 of 1767 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/es/
2026-02-01 19:32:58 +01:00
noobhjy
b1573b1f3b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/zh_Hans/
2026-02-01 19:32:57 +01:00
Marcel
246849ce94 Translated using Weblate (German)
Currently translated at 100.0% (1767 of 1767 strings)

Translation: Trilium Notes/Client
Translate-URL: https://hosted.weblate.org/projects/trilium/client/de/
2026-02-01 19:32:57 +01:00
Marcel
2c2c68261a Translated using Weblate (German)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/de/
2026-02-01 19:32:56 +01:00
green
e38a0361bf Translated using Weblate (Japanese)
Currently translated at 100.0% (389 of 389 strings)

Translation: Trilium Notes/Server
Translate-URL: https://hosted.weblate.org/projects/trilium/server/ja/
2026-02-01 19:32:56 +01:00
ibs-allaow
cbf879bd32 Translated using Weblate (Arabic)
Currently translated at 59.2% (90 of 152 strings)

Translation: Trilium Notes/Website
Translate-URL: https://hosted.weblate.org/projects/trilium/website/ar/
2026-02-01 19:32:56 +01:00
perfectra1n
808625e564 feat(etapi): add attachments etapi endpoint 2026-02-01 09:19:37 -08:00
28 changed files with 600 additions and 118 deletions

View File

@@ -56,7 +56,7 @@
"mark.js": "8.11.1",
"marked": "17.0.1",
"mermaid": "11.12.2",
"mind-elixir": "5.6.1",
"mind-elixir": "5.7.0",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.28.3",

View File

@@ -7,6 +7,7 @@ import FlexContainer from "../widgets/containers/flex_container.js";
import RootContainer from "../widgets/containers/root_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import FindWidget from "../widgets/find.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
@@ -27,7 +28,6 @@ import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx";
import SearchResult from "../widgets/search_result.jsx";
import SharedInfoWidget from "../widgets/shared_info.js";
import TabRowWidget from "../widgets/tab_row.js";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
import { applyModals } from "./layout_commons.js";
@@ -148,7 +148,6 @@ export default class MobileLayout {
.child(
new FlexContainer("row")
.contentSized()
.css("font-size", "larger")
.css("align-items", "center")
.child(<ToggleSidebarButton />)
.child(<NoteTitleWidget />)
@@ -171,6 +170,7 @@ export default class MobileLayout {
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)
.child(new FindWidget())
)
)
)

View File

@@ -1,5 +1,6 @@
import { t } from "./i18n";
import options from "./options";
import { isMobile } from "./utils";
export interface ExperimentalFeature {
id: string;
@@ -21,7 +22,7 @@ let enabledFeatures: Set<ExperimentalFeatureId> | null = null;
export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId): boolean {
if (featureId === "new-layout") {
return options.is("newLayout");
return (isMobile() || options.is("newLayout"));
}
return getEnabledFeatures().has(featureId);
@@ -29,7 +30,7 @@ export function isExperimentalFeatureEnabled(featureId: ExperimentalFeatureId):
export function getEnabledExperimentalFeatureIds() {
const values = [ ...getEnabledFeatures().values() ];
if (options.is("newLayout")) {
if (isMobile() || options.is("newLayout")) {
values.push("new-layout");
}
return values;

View File

@@ -454,7 +454,7 @@ body.desktop .tabulator-popup-container,
visibility: hidden;
}
body.desktop .dropdown-menu:not(#context-menu-container) .dropdown-item,
.dropdown-menu:not(#context-menu-container) .dropdown-item,
body.desktop .dropdown-menu .dropdown-toggle,
body #context-menu-container .dropdown-item > span,
body.mobile .dropdown .dropdown-submenu > span {
@@ -462,6 +462,15 @@ body.mobile .dropdown .dropdown-submenu > span {
align-items: center;
}
body.mobile .dropdown .dropdown-submenu {
flex-wrap: wrap;
& > span {
flex-grow: 1;
}
}
.dropdown-item span.keyboard-shortcut,
.dropdown-item *:not(.keyboard-shortcut) > kbd {
flex-grow: 1;
@@ -1530,7 +1539,8 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
@media (max-width: 991px) {
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
body.mobile #launcher-container .dropdown > .dropdown-menu.show {
body.mobile #launcher-container .dropdown > .dropdown-menu.show,
body.mobile .dropdown.note-actions > .dropdown-menu.show {
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
position: fixed !important;
bottom: var(--dropdown-bottom) !important;

View File

@@ -29,7 +29,9 @@
"widget-render-error": {
"title": "فشل عرض عنصر واجهة مستخدم React مخصص"
},
"widget-missing-parent": "لا تحتوي الأداة المخصصة على خاصية إلزامية '{{property}}'.\n\nإذا كان من المفترض تشغيل هذا البرنامج النصي بدون عنصر واجهة مستخدم، فاستخدم '#run=frontendStartup' بدلاً من ذلك."
"widget-missing-parent": "لا تحتوي الأداة المخصصة على خاصية إلزامية '{{property}}'.\n\nإذا كان من المفترض تشغيل هذا البرنامج النصي بدون عنصر واجهة مستخدم، فاستخدم '#run=frontendStartup' بدلاً من ذلك.",
"open-script-note": "فتح ملاحظة برمجية",
"scripting-error": "خطأ في النص البرمجي المخصص: {{title}}"
},
"add_link": {
"add_link": "أضافة رابط",

View File

@@ -1782,8 +1782,8 @@
"desktop-application": "桌面应用程序",
"native-title-bar": "原生标题栏",
"native-title-bar-description": "对于 Windows 和 macOS关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。",
"background-effects": "启用背景效果(仅适用于 Windows 11",
"background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。",
"background-effects": "启用背景效果",
"background-effects-description": "为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。",
"restart-app-button": "重启应用程序以查看更改",
"zoom-factor": "缩放系数"
},
@@ -1802,7 +1802,8 @@
"geo-map": {
"create-child-note-title": "创建一个新的子笔记并将其添加到地图中",
"create-child-note-instruction": "单击地图以在该位置创建新笔记,或按 Escape 以取消。",
"unable-to-load-map": "无法加载地图。"
"unable-to-load-map": "无法加载地图。",
"create-child-note-text": "添加标记"
},
"geo-map-context": {
"open-location": "打开位置",
@@ -2117,7 +2118,7 @@
},
"call_to_action": {
"background_effects_title": "背景效果现已推出稳定版本",
"background_effects_message": "在 Windows 装置上,背景效果现在已完全稳定。背景效果通过模糊背后的背景,为使用者界面增添一抹色彩。此技术也用于其他应用程序,例如 Windows 资源管理器。",
"background_effects_message": "在 Windows 和 macOS 设备上,背景效果现在已稳定。背景效果通过模糊背后的背景,为使用者界面增添一抹色彩。",
"background_effects_button": "启用背景效果",
"next_theme_title": "试用新 Trilium 主题",
"next_theme_message": "当前使用旧版主题,要试用新主题吗?",
@@ -2253,5 +2254,12 @@
"pages_alt": "第{{pageNumber}}页",
"pages_loading": "加载中...",
"layers_other": "{{count}} 层"
},
"platform_indicator": {
"available_on": "在 {{platform}} 上可用"
},
"mobile_tab_switcher": {
"title_other": "{{count}} 选项卡",
"more_options": "更多选项"
}
}

View File

@@ -1771,7 +1771,8 @@
"geo-map": {
"create-child-note-title": "Neue Unternotiz anlegen und zur Karte hinzufügen",
"create-child-note-instruction": "Auf die Karte klicken, um eine neue Notiz an der Stelle zu erstellen oder Escape drücken um abzubrechen.",
"unable-to-load-map": "Karte konnte nicht geladen werden."
"unable-to-load-map": "Karte konnte nicht geladen werden.",
"create-child-note-text": "Marker hinzufügen"
},
"geo-map-context": {
"open-location": "Ort öffnen",
@@ -2270,5 +2271,10 @@
},
"platform_indicator": {
"available_on": "Verfügbar auf {{platform}}"
},
"mobile_tab_switcher": {
"title_one": "{{count}} Tab",
"title_other": "{{count}} Tabs",
"more_options": "Weitere Optionen"
}
}

View File

@@ -2285,5 +2285,11 @@
},
"platform_indicator": {
"available_on": "Disponible en {{platform}}"
},
"mobile_tab_switcher": {
"title_one": "{{count}} pestaña",
"title_many": "{{count}} pestañas",
"title_other": "{{count}} pestañas",
"more_options": "Más opciones"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -2008,7 +2008,8 @@
"geo-map": {
"create-child-note-title": "新しい子ノートを作成し、マップに追加する",
"create-child-note-instruction": "地図をクリックしてその場所に新しいートを作成するか、Esc キーを押して閉じます。",
"unable-to-load-map": "マップを読み込めません。"
"unable-to-load-map": "マップを読み込めません。",
"create-child-note-text": "マーカーを追加"
},
"geo-map-context": {
"open-location": "現在位置を表示",
@@ -2256,5 +2257,9 @@
},
"platform_indicator": {
"available_on": "{{platform}} で利用可能"
},
"mobile_tab_switcher": {
"title_other": "{{count}} タブ",
"more_options": "その他のオプション"
}
}

View File

@@ -5,6 +5,7 @@ import clsx from "clsx";
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import NoteContext from "../components/note_context";
import FAttribute from "../entities/fattribute";
import FNote from "../entities/fnote";
import { Attribute } from "../services/attribute_parser";
@@ -40,8 +41,8 @@ type OnChangeEventData = TargetedEvent<HTMLInputElement, Event> | InputEvent | J
type OnChangeListener = (e: OnChangeEventData) => Promise<void>;
export default function PromotedAttributes() {
const { note, componentId } = useNoteContext();
const [ cells, setCells ] = usePromotedAttributeData(note, componentId);
const { note, componentId, noteContext } = useNoteContext();
const [ cells, setCells ] = usePromotedAttributeData(note, componentId, noteContext);
return <PromotedAttributesContent note={note} componentId={componentId} cells={cells} setCells={setCells} />;
}
@@ -74,12 +75,12 @@ export function PromotedAttributesContent({ note, componentId, cells, setCells }
*
* The cells are returned as a state since they can also be altered internally if needed, for example to add a new empty cell.
*/
export function usePromotedAttributeData(note: FNote | null | undefined, componentId: string): [ Cell[] | undefined, Dispatch<StateUpdater<Cell[] | undefined>> ] {
export function usePromotedAttributeData(note: FNote | null | undefined, componentId: string, noteContext: NoteContext | undefined): [ Cell[] | undefined, Dispatch<StateUpdater<Cell[] | undefined>> ] {
const [ viewType ] = useNoteLabel(note, "viewType");
const [ cells, setCells ] = useState<Cell[]>();
function refresh() {
if (!note || viewType === "table") {
if (!note || viewType === "table" || noteContext?.viewScope?.viewMode !== "default") {
setCells([]);
return;
}
@@ -124,7 +125,7 @@ export function usePromotedAttributeData(note: FNote | null | undefined, compone
setCells(cells);
}
useEffect(refresh, [ note, viewType ]);
useEffect(refresh, [ note, viewType, noteContext ]);
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
if (loadResults.getAttributeRows(componentId).find((attr) => attributes.isAffecting(attr, note))) {
refresh();

View File

@@ -29,7 +29,6 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
const isVerticalLayout = !isHorizontalLayout;
const parentComponent = useContext(ParentComponent);
const { isUpdateAvailable, latestVersion } = useTriliumUpdateStatus();
const isMobileLocal = isMobile();
const logoRef = useRef<SVGSVGElement>(null);
useStaticTooltip(logoRef);
@@ -44,8 +43,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
</div>}
</>}
noDropdownListStyle
onShown={isMobileLocal ? () => document.getElementById("context-menu-cover")?.classList.add("show", "global-menu-cover") : undefined}
onHidden={isMobileLocal ? () => document.getElementById("context-menu-cover")?.classList.remove("show", "global-menu-cover") : undefined}
mobileBackdrop
>
<MenuItem command="openNewWindow" icon="bx bx-window-open" text={t("global_menu.open_new_window")} />

View File

@@ -48,7 +48,7 @@ function PromotedAttributes({ note, componentId, noteContext }: {
componentId: string,
noteContext: NoteContext | undefined
}) {
const [ cells, setCells ] = usePromotedAttributeData(note, componentId);
const [ cells, setCells ] = usePromotedAttributeData(note, componentId, noteContext);
const [ expanded, setExpanded ] = useState(false);
useEffect(() => {

View File

@@ -1,84 +1,57 @@
import { useContext } from "preact/hooks";
import appContext, { CommandMappings } from "../../components/app_context";
import contextMenu, { MenuItem } from "../../menus/context_menu";
import branches from "../../services/branches";
import { t } from "../../services/i18n";
import { getHelpUrlForNote } from "../../services/in_app_help";
import note_create from "../../services/note_create";
import tree from "../../services/tree";
import { openInAppHelpFromUrl } from "../../services/utils";
import BasicWidget from "../basic_widget";
import ActionButton from "../react/ActionButton";
import { ParentComponent } from "../react/react_utils";
import { FormDropdownDivider, FormListItem } from "../react/FormList";
import { useNoteContext } from "../react/hooks";
import { NoteContextMenu } from "../ribbon/NoteActions";
export default function MobileDetailMenu() {
const parentComponent = useContext(ParentComponent);
const { note, noteContext, parentComponent, ntxId } = useNoteContext();
const helpUrl = getHelpUrlForNote(note);
const subContexts = noteContext?.getMainContext().getSubContexts() ?? [];
const isMainContext = noteContext?.isMainContext();
return (
<ActionButton
icon="bx bx-dots-vertical-rounded"
text=""
onClick={(e) => {
const ntxId = (parentComponent as BasicWidget | null)?.getClosestNtxId();
if (!ntxId) return;
const noteContext = appContext.tabManager.getNoteContextById(ntxId);
const subContexts = noteContext.getMainContext().getSubContexts();
const isMainContext = noteContext?.isMainContext();
const note = noteContext.note;
const helpUrl = getHelpUrlForNote(note);
const items: (MenuItem<keyof CommandMappings>)[] = [
{ title: t("mobile_detail_menu.insert_child_note"), command: "insertChildNote", uiIcon: "bx bx-plus", enabled: note?.type !== "search" },
{ title: t("mobile_detail_menu.delete_this_note"), command: "delete", uiIcon: "bx bx-trash", enabled: note?.noteId !== "root" },
{ kind: "separator" },
{ title: t("mobile_detail_menu.note_revisions"), command: "showRevisions", uiIcon: "bx bx-history" },
{ kind: "separator" },
helpUrl && {
title: t("help-button.title"),
uiIcon: "bx bx-help-circle",
handler: () => openInAppHelpFromUrl(helpUrl)
},
{ kind: "separator" },
subContexts.length < 2 && { title: t("create_pane_button.create_new_split"), command: "openNewNoteSplit", uiIcon: "bx bx-dock-right" },
!isMainContext && { title: t("close_pane_button.close_this_pane"), command: "closeThisNoteSplit", uiIcon: "bx bx-x" }
].filter(i => !!i) as MenuItem<keyof CommandMappings>[];
const lastItem = items.at(-1);
if (lastItem && "kind" in lastItem && lastItem.kind === "separator") {
items.pop();
}
contextMenu.show<keyof CommandMappings>({
x: e.pageX,
y: e.pageY,
items,
selectMenuItemHandler: async ({ command }) => {
if (command === "insertChildNote") {
note_create.createNote(appContext.tabManager.getActiveContextNotePath() ?? undefined);
} else if (command === "delete") {
const notePath = appContext.tabManager.getActiveContextNotePath();
if (!notePath) {
throw new Error("Cannot get note path to delete.");
}
const branchId = await tree.getBranchIdFromUrl(notePath);
if (!branchId) {
throw new Error(t("mobile_detail_menu.error_cannot_get_branch_id", { notePath }));
}
if (await branches.deleteNotes([branchId]) && parentComponent) {
parentComponent.triggerCommand("setActiveScreen", { screen: "tree" });
}
} else if (command && parentComponent) {
parentComponent.triggerCommand(command, { ntxId });
}
},
forcePositionOnMobile: true
});
}}
/>
<div style={{ contain: "none" }}>
{note && (
<NoteContextMenu
note={note} noteContext={noteContext}
extraItems={<>
<FormListItem
onClick={() => noteContext?.notePath && note_create.createNote(noteContext.notePath)}
icon="bx bx-plus"
>{t("mobile_detail_menu.insert_child_note")}</FormListItem>
{helpUrl && <>
<FormDropdownDivider />
<FormListItem
icon="bx bx-help-circle"
onClick={() => openInAppHelpFromUrl(helpUrl)}
>{t("help-button.title")}</FormListItem>
</>}
{subContexts.length < 2 && <>
<FormDropdownDivider />
<FormListItem
onClick={() => parentComponent.triggerCommand("openNewNoteSplit", { ntxId })}
icon="bx bx-dock-right"
>{t("create_pane_button.create_new_split")}</FormListItem>
</>}
{!isMainContext && <>
<FormDropdownDivider />
<FormListItem
icon="bx bx-x"
onClick={() => {
// Wait first for the context menu to be dismissed, otherwise the backdrop stays on.
requestAnimationFrame(() => {
parentComponent.triggerCommand("closeThisNoteSplit", { ntxId });
});
}}
>{t("close_pane_button.close_this_pane")}</FormListItem>
</>}
<FormDropdownDivider />
</>}
/>
)}
</div>
);
}

View File

@@ -3,6 +3,7 @@ import { ComponentChildren, HTMLAttributes } from "preact";
import { CSSProperties, HTMLProps } from "preact/compat";
import { MutableRef, useCallback, useEffect, useRef, useState } from "preact/hooks";
import { isMobile } from "../../services/utils";
import { useTooltip, useUniqueName } from "./hooks";
type DataAttributes = {
@@ -32,9 +33,10 @@ export interface DropdownProps extends Pick<HTMLProps<HTMLDivElement>, "id" | "c
dropdownRef?: MutableRef<BootstrapDropdown | null>;
titlePosition?: "top" | "right" | "bottom" | "left";
titleOptions?: Partial<Tooltip.Options>;
mobileBackdrop?: boolean;
}
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, dropdownContainerRef: externalContainerRef, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown, onShown: externalOnShown, onHidden: externalOnHidden, dropdownOptions, buttonProps, dropdownRef, titlePosition, titleOptions }: DropdownProps) {
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, dropdownContainerRef: externalContainerRef, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown, onShown: externalOnShown, onHidden: externalOnHidden, dropdownOptions, buttonProps, dropdownRef, titlePosition, titleOptions, mobileBackdrop }: DropdownProps) {
const containerRef = useRef<HTMLDivElement | null>(null);
const triggerRef = useRef<HTMLButtonElement | null>(null);
const dropdownContainerRef = useRef<HTMLUListElement | null>(null);
@@ -74,12 +76,18 @@ export default function Dropdown({ id, className, buttonClassName, isStatic, chi
setShown(true);
externalOnShown?.();
hideTooltip();
}, [ hideTooltip ]);
if (mobileBackdrop && isMobile()) {
document.getElementById("context-menu-cover")?.classList.add("show", "global-menu-cover");
}
}, [ hideTooltip, mobileBackdrop ]);
const onHidden = useCallback(() => {
setShown(false);
externalOnHidden?.();
}, []);
if (mobileBackdrop && isMobile()) {
document.getElementById("context-menu-cover")?.classList.remove("show", "global-menu-cover");
}
}, [ mobileBackdrop ]);
useEffect(() => {
if (!containerRef.current) return;

View File

@@ -1,6 +1,6 @@
import { ConvertToAttachmentResponse } from "@triliumnext/commons";
import { Dropdown as BootstrapDropdown } from "bootstrap";
import { RefObject } from "preact";
import { ComponentChildren, RefObject } from "preact";
import { useContext, useEffect, useRef } from "preact/hooks";
import appContext, { CommandNames } from "../../components/app_context";
@@ -63,7 +63,7 @@ function RevisionsButton({ note }: { note: FNote }) {
type ItemToFocus = "basic-properties";
function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: NoteContext }) {
export function NoteContextMenu({ note, noteContext, extraItems }: { note: FNote, noteContext?: NoteContext, extraItems?: ComponentChildren; }) {
const dropdownRef = useRef<BootstrapDropdown>(null);
const parentComponent = useContext(ParentComponent);
const noteType = useNoteProperty(note, "type") ?? "";
@@ -99,12 +99,15 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
dropdownRef={dropdownRef}
buttonClassName={ isNewLayout ? "bx bx-dots-horizontal-rounded" : "bx bx-dots-vertical-rounded" }
className="note-actions"
dropdownContainerClassName="mobile-bottom-menu"
hideToggleArrow
noSelectButtonStyle
noDropdownListStyle
iconAction
onHidden={() => itemToFocusRef.current = null }
mobileBackdrop
>
{extraItems}
{isReadOnly && <>
<CommandItem icon="bx bx-pencil" text={t("read-only-info.edit-note")}
@@ -277,7 +280,7 @@ function DevelopmentActions({ note, noteContext }: { note: FNote, noteContext?:
);
}
function CommandItem({ icon, text, title, command, disabled }: { icon: string, text: string, title?: string, command: CommandNames | (() => void), disabled?: boolean, destructive?: boolean }) {
export function CommandItem({ icon, text, title, command, disabled }: { icon: string, text: string, title?: string, command: CommandNames | (() => void), disabled?: boolean, destructive?: boolean }) {
return <FormListItem
icon={icon}
title={title}

View File

@@ -362,6 +362,31 @@ paths:
application/json; charset=utf-8:
schema:
$ref: "#/components/schemas/Error"
/notes/{noteId}/attachments:
parameters:
- name: noteId
in: path
required: true
schema:
$ref: "#/components/schemas/EntityId"
get:
description: Returns all attachments for a note identified by its ID
operationId: getNoteAttachments
responses:
"200":
description: list of attachments
content:
application/json; charset=utf-8:
schema:
type: array
items:
$ref: "#/components/schemas/Attachment"
default:
description: unexpected error
content:
application/json; charset=utf-8:
schema:
$ref: "#/components/schemas/Error"
/notes/{noteId}/undelete:
parameters:
- name: noteId

View File

@@ -0,0 +1,82 @@
import { Application } from "express";
import { beforeAll, describe, expect, it } from "vitest";
import supertest from "supertest";
import { createNote, login } from "./utils.js";
import config from "../../src/services/config.js";
let app: Application;
let token: string;
const USER = "etapi";
let createdNoteId: string;
let createdAttachmentId: string;
describe("etapi/get-note-attachments", () => {
beforeAll(async () => {
config.General.noAuthentication = false;
const buildApp = (await (import("../../src/app.js"))).default;
app = await buildApp();
token = await login(app);
createdNoteId = await createNote(app, token);
// Create an attachment for the note
const response = await supertest(app)
.post(`/etapi/attachments`)
.auth(USER, token, { "type": "basic" })
.send({
"ownerId": createdNoteId,
"role": "file",
"mime": "text/plain",
"title": "test-attachment.txt",
"content": "test content",
"position": 10
});
createdAttachmentId = response.body.attachmentId;
expect(createdAttachmentId).toBeTruthy();
});
it("gets attachments for a note", async () => {
const response = await supertest(app)
.get(`/etapi/notes/${createdNoteId}/attachments`)
.auth(USER, token, { "type": "basic" })
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
expect(response.body.length).toBeGreaterThan(0);
const attachment = response.body[0];
expect(attachment).toHaveProperty("attachmentId", createdAttachmentId);
expect(attachment).toHaveProperty("ownerId", createdNoteId);
expect(attachment).toHaveProperty("role", "file");
expect(attachment).toHaveProperty("mime", "text/plain");
expect(attachment).toHaveProperty("title", "test-attachment.txt");
expect(attachment).toHaveProperty("position", 10);
expect(attachment).toHaveProperty("blobId");
expect(attachment).toHaveProperty("dateModified");
expect(attachment).toHaveProperty("utcDateModified");
expect(attachment).toHaveProperty("contentLength");
});
it("returns empty array for note with no attachments", async () => {
// Create a new note without any attachments
const newNoteId = await createNote(app, token, "Note without attachments");
const response = await supertest(app)
.get(`/etapi/notes/${newNoteId}/attachments`)
.auth(USER, token, { "type": "basic" })
.expect(200);
expect(Array.isArray(response.body)).toBe(true);
expect(response.body.length).toBe(0);
});
it("returns 404 for non-existent note", async () => {
const response = await supertest(app)
.get("/etapi/notes/nonexistentnote/attachments")
.auth(USER, token, { "type": "basic" })
.expect(404);
expect(response.body.code).toStrictEqual("NOTE_NOT_FOUND");
});
});

View File

@@ -259,7 +259,8 @@
"ai-llm-title": "AI/LLM",
"inbox-title": "收件箱",
"command-palette": "打开命令面板",
"zen-mode": "禅模式"
"zen-mode": "禅模式",
"tab-switcher-title": "标签切换器"
},
"notes": {
"new-note": "新建笔记",

View File

@@ -257,7 +257,8 @@
"localization": "Sprache & Region",
"inbox-title": "Posteingang",
"zen-mode": "Zen-Modus",
"command-palette": "Befehlspalette öffnen"
"command-palette": "Befehlspalette öffnen",
"tab-switcher-title": "Tabauswahl"
},
"notes": {
"new-note": "Neue Notiz",

View File

@@ -259,7 +259,8 @@
"inbox-title": "Bandeja",
"jump-to-note-title": "Saltar a...",
"command-palette": "Abrir paleta de comandos",
"zen-mode": "Modo Zen"
"zen-mode": "Modo Zen",
"tab-switcher-title": "Conmutador de pestañas"
},
"notes": {
"new-note": "Nueva nota",

View File

@@ -0,0 +1 @@
{}

View File

@@ -344,7 +344,8 @@
"inbox-title": "Inbox",
"base-abstract-launcher-title": "ベース アブストラクトランチャー",
"command-palette": "コマンドパレットを開く",
"zen-mode": "禅モード"
"zen-mode": "禅モード",
"tab-switcher-title": "タブ切り替え"
},
"notes": {
"new-note": "新しいノート",

View File

@@ -8,6 +8,12 @@ import type { AttachmentRow } from "@triliumnext/commons";
import type { ValidatorMap } from "./etapi-interface.js";
function register(router: Router) {
eu.route(router, "get", "/etapi/notes/:noteId/attachments", (req, res, next) => {
const note = eu.getAndCheckNote(req.params.noteId);
const attachments = note.getAttachments();
res.json(attachments.map((attachment) => mappers.mapAttachmentToPojo(attachment)));
});
const ALLOWED_PROPERTIES_FOR_CREATE_ATTACHMENT: ValidatorMap = {
ownerId: [v.notNull, v.isNoteId],
role: [v.notNull, v.isString],

View File

@@ -41,7 +41,9 @@
"search_title": "البحث القوي",
"web_clipper_title": "اداة قص الويب",
"title": "الانتاجية والسلامة",
"jump_to_title": "الاوامر والبحث السريع"
"jump_to_title": "الاوامر والبحث السريع",
"revisions_content": "تُحفظ الملاحظات دوريًا في الخلفية، ويمكن استخدام التعديلات للمراجعة أو للتراجع عن التغييرات غير المقصودة. كما يمكن إنشاء التعديلات عند الطلب.",
"sync_content": "استخدم نسخة مستضافة ذاتيًا أو نسخة سحابية لمزامنة ملاحظاتك بسهولة عبر أجهزة متعددة، وللوصول إليها من هاتفك المحمول باستخدام تطبيق ويب تقدمي (PWA)."
},
"note_types": {
"canvas_title": "مساحة العمل",

View File

@@ -0,0 +1 @@
{}

337
docs/README-ga.md vendored Normal file
View File

@@ -0,0 +1,337 @@
<div align="center">
<sup>Special thanks to:</sup><br />
<a href="https://go.warp.dev/Trilium" target="_blank">
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-03.png"><br />
Warp, built for coding with multiple AI agents<br />
</a>
<sup>Available for macOS, Linux and Windows</sup>
</div>
<hr />
# Trilium Notes
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran)
![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)\
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/trilium)
![GitHub Downloads (all assets, all
releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp)
[![Translation
status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
<!-- translate:off -->
<!-- LANGUAGE SWITCHER -->
[Chinese (Simplified Han script)](./README-ZH_CN.md) | [Chinese (Traditional Han
script)](./README-ZH_TW.md) | [English](../README.md) | [French](./README-fr.md)
| [German](./README-de.md) | [Greek](./README-el.md) | [Italian](./README-it.md)
| [Japanese](./README-ja.md) | [Romanian](./README-ro.md) |
[Spanish](./README-es.md)
<!-- translate:on -->
Trilium Notes is a free and open-source, cross-platform hierarchical note taking
application with focus on building large personal knowledge bases.
<img src="./app.png" alt="Trilium Screenshot" width="1000">
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
Our documentation is available in multiple formats:
- **Online Documentation**: Browse the full documentation at
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
- **In-App Help**: Press `F1` within Trilium to access the same documentation
directly in the application
- **GitHub**: Navigate through the [User Guide](./User%20Guide/User%20Guide/) in
this repository
### Quick Links
- [Getting Started Guide](https://docs.triliumnotes.org/)
- [Installation Instructions](https://docs.triliumnotes.org/user-guide/setup)
- [Docker
Setup](https://docs.triliumnotes.org/user-guide/setup/server/installation/docker)
- [Upgrading
TriliumNext](https://docs.triliumnotes.org/user-guide/setup/upgrading)
- [Basic Concepts and
Features](https://docs.triliumnotes.org/user-guide/concepts/notes)
- [Patterns of Personal Knowledge
Base](https://docs.triliumnotes.org/user-guide/misc/patterns-of-personal-knowledge)
## 🎁 Features
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
into multiple places in the tree (see
[cloning](https://docs.triliumnotes.org/user-guide/concepts/notes/cloning))
* Rich WYSIWYG note editor including e.g. tables, images and
[math](https://docs.triliumnotes.org/user-guide/note-types/text) with markdown
[autoformat](https://docs.triliumnotes.org/user-guide/note-types/text/markdown-formatting)
* Support for editing [notes with source
code](https://docs.triliumnotes.org/user-guide/note-types/code), including
syntax highlighting
* Fast and easy [navigation between
notes](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-navigation),
full text search and [note
hoisting](https://docs.triliumnotes.org/user-guide/concepts/navigation/note-hoisting)
* Seamless [note
versioning](https://docs.triliumnotes.org/user-guide/concepts/notes/note-revisions)
* Note
[attributes](https://docs.triliumnotes.org/user-guide/advanced-usage/attributes)
can be used for note organization, querying and advanced
[scripting](https://docs.triliumnotes.org/user-guide/scripts)
* UI available in English, German, Spanish, French, Romanian, and Chinese
(simplified and traditional)
* Direct [OpenID and TOTP
integration](https://docs.triliumnotes.org/user-guide/setup/server/mfa) for
more secure login
* [Synchronization](https://docs.triliumnotes.org/user-guide/setup/synchronization)
with self-hosted sync server
* there are [3rd party services for hosting synchronisation
server](https://docs.triliumnotes.org/user-guide/setup/server/cloud-hosting)
* [Sharing](https://docs.triliumnotes.org/user-guide/advanced-usage/sharing)
(publishing) notes to public internet
* Strong [note
encryption](https://docs.triliumnotes.org/user-guide/concepts/notes/protected-notes)
with per-note granularity
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type
"canvas")
* [Relation
maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and
[note/link maps](https://docs.triliumnotes.org/user-guide/note-types/note-map)
for visualizing notes and their relations
* Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/)
* [Geo maps](https://docs.triliumnotes.org/user-guide/collections/geomap) with
location pins and GPX tracks
* [Scripting](https://docs.triliumnotes.org/user-guide/scripts) - see [Advanced
showcases](https://docs.triliumnotes.org/user-guide/advanced-usage/advanced-showcases)
* [REST API](https://docs.triliumnotes.org/user-guide/advanced-usage/etapi) for
automation
* Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile
frontend](https://docs.triliumnotes.org/user-guide/setup/mobile-frontend) for
smartphones and tablets
* Built-in [dark
theme](https://docs.triliumnotes.org/user-guide/concepts/themes), support for
user themes
* [Evernote](https://docs.triliumnotes.org/user-guide/concepts/import-export/evernote)
and [Markdown import &
export](https://docs.triliumnotes.org/user-guide/concepts/import-export/markdown)
* [Web Clipper](https://docs.triliumnotes.org/user-guide/setup/web-clipper) for
easy saving of web content
* Customizable UI (sidebar buttons, user-defined widgets, ...)
* [Metrics](https://docs.triliumnotes.org/user-guide/advanced-usage/metrics),
along with a Grafana Dashboard.
✨ Check out the following third-party resources/communities for more TriliumNext
related goodies:
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party
themes, scripts, plugins and more.
- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
## ❓Why TriliumNext?
The original Trilium developer ([Zadam](https://github.com/zadam)) has
graciously given the Trilium repository to the community project which resides
at https://github.com/TriliumNext
### ⬆Migrating from Zadam/Trilium?
There are no special migration steps to migrate from a zadam/Trilium instance to
a TriliumNext/Trilium instance. Simply [install
TriliumNext/Trilium](#-installation) as usual and it will use your existing
database.
Versions up to and including
[v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) are
compatible with the latest zadam/trilium version of
[v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later
versions of TriliumNext/Trilium have their sync versions incremented which
prevents direct migration.
## 💬 Discuss with us
Feel free to join our official conversations. We would love to hear what
features, suggestions, or issues you may have!
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous
discussions.)
- The `General` Matrix room is also bridged to
[XMPP](xmpp:discuss@trilium.thisgreat.party?join)
- [Github Discussions](https://github.com/TriliumNext/Trilium/discussions) (For
asynchronous discussions.)
- [Github Issues](https://github.com/TriliumNext/Trilium/issues) (For bug
reports and feature requests.)
## 🏗 Installation
### Windows / MacOS
Download the binary release for your platform from the [latest release
page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package
and run the `trilium` executable.
### Linux
If your distribution is listed in the table below, use your distribution's
package.
[![Packaging
status](https://repology.org/badge/vertical-allrepos/triliumnext.svg)](https://repology.org/project/triliumnext/versions)
You may also download the binary release for your platform from the [latest
release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the
package and run the `trilium` executable.
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
### Browser (any OS)
If you use a server installation (see below), you can directly access the web
interface (which is almost identical to the desktop app).
Currently only the latest versions of Chrome & Firefox are supported (and
tested).
### Mobile
To use TriliumNext on a mobile device, you can use a mobile web browser to
access the mobile interface of a server installation (see below).
See issue https://github.com/TriliumNext/Trilium/issues/4962 for more
information on mobile app support.
If you prefer a native Android app, you can use
[TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid).
Report bugs and missing features at [their
repository](https://github.com/FliegendeWurst/TriliumDroid). Note: It is best to
disable automatic updates on your server installation (see below) when using
TriliumDroid since the sync version must match between Trilium and TriliumDroid.
### Server
To install TriliumNext on your own server (including via Docker from
[Dockerhub](https://hub.docker.com/r/triliumnext/trilium)) follow [the server
installation docs](https://docs.triliumnotes.org/user-guide/setup/server).
## 💻 Contribute
### Translations
If you are a native speaker, help us translate Trilium by heading over to our
[Weblate page](https://hosted.weblate.org/engage/trilium/).
Here's the language coverage we have so far:
[![Translation
status](https://hosted.weblate.org/widget/trilium/multi-auto.svg)](https://hosted.weblate.org/engage/trilium/)
### Code
Download the repository, install dependencies using `pnpm` and then run the
server (available at http://localhost:8080):
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm run server:start
```
### Documentation
Download the repository, install dependencies using `pnpm` and then run the
environment required to edit the documentation:
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm edit-docs:edit-docs
```
### Building the Executable
Download the repository, install dependencies using `pnpm` and then build the
desktop app for Windows:
```shell
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32
```
For more details, see the [development
docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).
### Developer Documentation
Please view the [documentation
guide](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md)
for details. If you have more questions, feel free to reach out via the links
described in the "Discuss with us" section above.
## 👏 Shoutouts
* [zadam](https://github.com/zadam) for the original concept and implementation
of the application.
* [Sarah Hussein](https://github.com/Sarah-Hussein) for designing the
application icon.
* [nriver](https://github.com/nriver) for his work on internationalization.
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas.
* [antoniotejada](https://github.com/nriver) for the original syntax highlight
widget.
* [Dosu](https://dosu.dev/) for providing us with the automated responses to
GitHub issues and discussions.
* [Tabler Icons](https://tabler.io/icons) for the system tray icons.
Trilium would not be possible without the technologies behind it:
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - the visual editor behind
text notes. We are grateful for being offered a set of the premium features.
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with
support for huge amount of languages.
* [Excalidraw](https://github.com/excalidraw/excalidraw) - the infinite
whiteboard used in Canvas notes.
* [Mind Elixir](https://github.com/SSShooter/mind-elixir-core) - providing the
mind map functionality.
* [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical
maps.
* [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive
table used in collections.
* [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library
without real competition.
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library.
Used in [relation
maps](https://docs.triliumnotes.org/user-guide/note-types/relation-map) and
[link
maps](https://docs.triliumnotes.org/user-guide/advanced-usage/note-map#link-map)
## 🤝 Support
Trilium is built and maintained with [hundreds of hours of
work](https://github.com/TriliumNext/Trilium/graphs/commit-activity). Your
support keeps it open-source, improves features, and covers costs such as
hosting.
Consider supporting the main developer
([eliandoran](https://github.com/eliandoran)) of the application via:
- [GitHub Sponsors](https://github.com/sponsors/eliandoran)
- [PayPal](https://paypal.me/eliandoran)
- [Buy Me a Coffee](https://buymeacoffee.com/eliandoran)
## 🔑 License
Copyright 2017-2025 zadam, Elian Doran, and other contributors
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

22
pnpm-lock.yaml generated
View File

@@ -208,7 +208,7 @@ importers:
version: 0.2.0(mermaid@11.12.2)
'@mind-elixir/node-menu':
specifier: 5.0.1
version: 5.0.1(mind-elixir@5.6.1)
version: 5.0.1(mind-elixir@5.7.0)
'@popperjs/core':
specifier: 2.11.8
version: 2.11.8
@@ -300,8 +300,8 @@ importers:
specifier: 11.12.2
version: 11.12.2
mind-elixir:
specifier: 5.6.1
version: 5.6.1
specifier: 5.7.0
version: 5.7.0
normalize.css:
specifier: 8.0.1
version: 8.0.1
@@ -10904,8 +10904,8 @@ packages:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
mind-elixir@5.6.1:
resolution: {integrity: sha512-FTpP5yfyjqXxtHbUAcJVrzBgbU9en0dQIbYx4lQc1C7aWOnjHGHr9iVccgMqU4gh9jVIBpunm4++2DpN753mGg==}
mind-elixir@5.7.0:
resolution: {integrity: sha512-h7s+Zxr+vRN0+CNTw7bNRMNJZKbq2mJWcvOOkc4n3MDeNnFL/J+oi//PQzemF28vNMyoaOz3h1Jm8EiuzcK7gw==}
mini-css-extract-plugin@2.9.4:
resolution: {integrity: sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==}
@@ -16254,6 +16254,8 @@ snapshots:
'@ckeditor/ckeditor5-table': 47.4.0
'@ckeditor/ckeditor5-utils': 47.4.0
ckeditor5: 47.4.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-emoji@47.4.0':
dependencies:
@@ -16436,6 +16438,8 @@ snapshots:
'@ckeditor/ckeditor5-widget': 47.4.0
ckeditor5: 47.4.0
es-toolkit: 1.39.5
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-icons@47.4.0': {}
@@ -16934,8 +16938,6 @@ snapshots:
'@ckeditor/ckeditor5-icons': 47.4.0
'@ckeditor/ckeditor5-ui': 47.4.0
'@ckeditor/ckeditor5-utils': 47.4.0
transitivePeerDependencies:
- supports-color
'@ckeditor/ckeditor5-upload@47.4.0':
dependencies:
@@ -19030,9 +19032,9 @@ snapshots:
'@microsoft/tsdoc@0.15.1': {}
'@mind-elixir/node-menu@5.0.1(mind-elixir@5.6.1)':
'@mind-elixir/node-menu@5.0.1(mind-elixir@5.7.0)':
dependencies:
mind-elixir: 5.6.1
mind-elixir: 5.7.0
'@mixmark-io/domino@2.2.0': {}
@@ -27662,7 +27664,7 @@ snapshots:
mimic-response@3.1.0: {}
mind-elixir@5.6.1: {}
mind-elixir@5.7.0: {}
mini-css-extract-plugin@2.9.4(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.2)):
dependencies: