mirror of
https://github.com/zadam/trilium.git
synced 2025-12-05 15:04:24 +01:00
Compare commits
30 Commits
9dd51e080f
...
c18be653d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c18be653d4 | ||
|
|
b4ab07bd78 | ||
|
|
fd6ad6dce3 | ||
|
|
ab97068a1d | ||
|
|
70fe3b9773 | ||
|
|
1fe8079fd5 | ||
|
|
80627997d1 | ||
|
|
12abdcaf6c | ||
|
|
a6ed4d92c9 | ||
|
|
0471640f54 | ||
|
|
4cf3e82fb5 | ||
|
|
fbbe999806 | ||
|
|
76af488d35 | ||
|
|
a54d2a5f22 | ||
|
|
a1df075194 | ||
|
|
4de2182b40 | ||
|
|
6fa88123f1 | ||
|
|
f81dbde15e | ||
|
|
484fbc6b9d | ||
|
|
8ba30135a1 | ||
|
|
ba5a72fdad | ||
|
|
70b39ddadf | ||
|
|
8200c0b0ab | ||
|
|
59ebfa6cc7 | ||
|
|
57b694162d | ||
|
|
2e6bdc225f | ||
|
|
8ced689432 | ||
|
|
5ecafe214f | ||
|
|
8baf0ad6af | ||
|
|
5d5fd2079a |
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,6 +8,7 @@ out-tsc
|
|||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
node_modules
|
node_modules
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
/.idea
|
/.idea
|
||||||
@ -18,6 +19,7 @@ node_modules
|
|||||||
*.launch
|
*.launch
|
||||||
.settings/
|
.settings/
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
.devcontainer
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
/.sass-cache
|
/.sass-cache
|
||||||
|
|||||||
19
README.md
19
README.md
@ -146,6 +146,21 @@ Here's the language coverage we have so far:
|
|||||||
|
|
||||||
### Code
|
### Code
|
||||||
|
|
||||||
|
General (OS / docker / podman, etc.) dependencies:
|
||||||
|
|
||||||
|
Debian
|
||||||
|
```
|
||||||
|
apt update
|
||||||
|
apt install -y build-essential python3 make g++ libsqlite3-dev
|
||||||
|
corepack enable
|
||||||
|
```
|
||||||
|
|
||||||
|
Alpine
|
||||||
|
```
|
||||||
|
apk add --no-cache build-base python3 python3-dev sqlite-dev
|
||||||
|
corepack enable
|
||||||
|
```
|
||||||
|
|
||||||
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
|
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/TriliumNext/Trilium.git
|
git clone https://github.com/TriliumNext/Trilium.git
|
||||||
@ -154,6 +169,10 @@ pnpm install
|
|||||||
pnpm run server:start
|
pnpm run server:start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> If you faced with some problems, try to delete all `node_modules` and `.pnpm-store` folders, not only from the root, from every directory, like `apps/{app_name}/node_modules`and `/packages/{package_name}/node_modules` and then reinstall it by the `pnpm install`.
|
||||||
|
|
||||||
|
Share styles not compiling by default, if you see share page without styles, make `pnpm run server:build` and then run development server.
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
|
Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
|
||||||
|
|||||||
@ -1554,12 +1554,15 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
|||||||
@media (max-width: 991px) {
|
@media (max-width: 991px) {
|
||||||
body.mobile #launcher-pane .dropdown.global-menu > .dropdown-menu.show,
|
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 {
|
||||||
|
--dropdown-bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size)) !important;
|
bottom: var(--dropdown-bottom) !important;
|
||||||
top: unset !important;
|
top: unset !important;
|
||||||
inset-inline-start: 0 !important;
|
inset-inline-start: 0 !important;
|
||||||
inset-inline-end: 0 !important;
|
inset-inline-end: 0 !important;
|
||||||
transform: unset !important;
|
transform: unset !important;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: calc(90vh - var(--dropdown-bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile-sidebar-container {
|
#mobile-sidebar-container {
|
||||||
|
|||||||
@ -308,6 +308,15 @@ body.mobile #context-menu-cover {
|
|||||||
&.show {
|
&.show {
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.global-menu-cover {
|
||||||
|
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .dropdown-menu.mobile-bottom-menu,
|
||||||
|
body.mobile .dropdown.global-menu .dropdown-menu {
|
||||||
|
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.mobile .dropdown-menu {
|
body.mobile .dropdown-menu {
|
||||||
@ -316,7 +325,6 @@ body.mobile .dropdown-menu {
|
|||||||
--hover-item-background-color: var(--card-background-color);
|
--hover-item-background-color: var(--card-background-color);
|
||||||
font-size: 1em !important;
|
font-size: 1em !important;
|
||||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||||
border-radius: var(--dropdown-border-radius) var(--dropdown-border-radius) 0 0;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.dropdown-toggle::after {
|
.dropdown-toggle::after {
|
||||||
@ -334,7 +342,7 @@ body.mobile .dropdown-menu {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal) !important;
|
padding: var(--dropdown-menu-padding-vertical) var(--dropdown-menu-padding-horizontal) !important;
|
||||||
background: var(--card-background-color);
|
background: var(--card-background-color);
|
||||||
border-bottom: 1px solid var(--main-border-color) !important;
|
border-bottom: 1px solid var(--menu-item-delimiter-color) !important;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,12 +391,38 @@ body.mobile .dropdown-menu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-divider {
|
||||||
|
visibility: visible;
|
||||||
|
margin: 0;
|
||||||
|
height: 3px;
|
||||||
|
border-top: unset;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.submenu-open {
|
&.submenu-open {
|
||||||
.dropdown-toggle {
|
.dropdown-toggle {
|
||||||
padding-bottom: var(--dropdown-menu-padding-vertical);
|
padding-bottom: var(--dropdown-menu-padding-vertical);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-custom-item:has(.note-color-picker) {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-color-picker {
|
||||||
|
padding: 0;
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.color-cell {
|
||||||
|
--color-picker-cell-size: 26px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* #endregion */
|
/* #endregion */
|
||||||
|
|
||||||
|
|||||||
@ -1557,7 +1557,8 @@
|
|||||||
"refresh-saved-search-results": "刷新保存的搜索结果",
|
"refresh-saved-search-results": "刷新保存的搜索结果",
|
||||||
"create-child-note": "创建子笔记",
|
"create-child-note": "创建子笔记",
|
||||||
"unhoist": "取消聚焦",
|
"unhoist": "取消聚焦",
|
||||||
"toggle-sidebar": "切换侧边栏"
|
"toggle-sidebar": "切换侧边栏",
|
||||||
|
"dropping-not-allowed": "不允许移动笔记到此处。"
|
||||||
},
|
},
|
||||||
"title_bar_buttons": {
|
"title_bar_buttons": {
|
||||||
"window-on-top": "保持此窗口置顶"
|
"window-on-top": "保持此窗口置顶"
|
||||||
@ -1660,7 +1661,8 @@
|
|||||||
"duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">"
|
"duplicate-launcher": "复制启动器 <kbd data-command=\"duplicateSubtree\">"
|
||||||
},
|
},
|
||||||
"editable-text": {
|
"editable-text": {
|
||||||
"auto-detect-language": "自动检测"
|
"auto-detect-language": "自动检测",
|
||||||
|
"keeps-crashing": "编辑组件时崩溃。请尝试重启 Trilium。如果问题仍然存在,请考虑提交错误报告。"
|
||||||
},
|
},
|
||||||
"highlighting": {
|
"highlighting": {
|
||||||
"title": "代码块",
|
"title": "代码块",
|
||||||
|
|||||||
@ -70,7 +70,7 @@
|
|||||||
"cancel": "Zrušit",
|
"cancel": "Zrušit",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"confirmation": "Potvrzení",
|
"confirmation": "Potvrzení",
|
||||||
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů?",
|
"are_you_sure_remove_note": "Opravdu chcete odstranit poznámku „{{title}}“ z mapy vztahů? ",
|
||||||
"if_you_dont_check": "Pokud tuto možnost nezaškrtnete, poznámka bude odstraněna pouze z mapy vztahů.",
|
"if_you_dont_check": "Pokud tuto možnost nezaškrtnete, poznámka bude odstraněna pouze z mapy vztahů.",
|
||||||
"also_delete_note": "Odstraňte také poznámku"
|
"also_delete_note": "Odstraňte také poznámku"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
},
|
},
|
||||||
"bundle-error": {
|
"bundle-error": {
|
||||||
"title": "Benutzerdefiniertes Skript konnte nicht geladen werden",
|
"title": "Benutzerdefiniertes Skript konnte nicht geladen werden",
|
||||||
"message": "Skript von der Notiz mit der ID \"{{id}}\", und dem Titel \"{{title}}\" konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
"message": "Skript aus der Notiz \"{{title}}\" mit der ID \"{{id}}\", konnte nicht ausgeführt werden wegen:\n\n{{message}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"add_link": {
|
"add_link": {
|
||||||
@ -41,7 +41,8 @@
|
|||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"branch_prefix_saved": "Zweigpräfix wurde gespeichert.",
|
"branch_prefix_saved": "Zweigpräfix wurde gespeichert.",
|
||||||
"branch_prefix_saved_multiple": "Der Zweigpräfix wurde für {{count}} Zweige gespeichert.",
|
"branch_prefix_saved_multiple": "Der Zweigpräfix wurde für {{count}} Zweige gespeichert.",
|
||||||
"edit_branch_prefix_multiple": "Präfix für {{count}} Zweige bearbeiten"
|
"edit_branch_prefix_multiple": "Branch-Präfix für {{count}} Zweige bearbeiten",
|
||||||
|
"affected_branches": "Betroffene Zweige ({{count}}):"
|
||||||
},
|
},
|
||||||
"bulk_actions": {
|
"bulk_actions": {
|
||||||
"bulk_actions": "Massenaktionen",
|
"bulk_actions": "Massenaktionen",
|
||||||
@ -770,7 +771,10 @@
|
|||||||
"board": "Tafel",
|
"board": "Tafel",
|
||||||
"include_archived_notes": "Zeige archivierte Notizen",
|
"include_archived_notes": "Zeige archivierte Notizen",
|
||||||
"presentation": "Präsentation",
|
"presentation": "Präsentation",
|
||||||
"expand_all_levels": "Alle Ebenen erweitern"
|
"expand_all_levels": "Alle Ebenen erweitern",
|
||||||
|
"expand_tooltip": "Erweitert die direkten Unterelemente dieser Sammlung (eine Ebene tiefer). Für weitere Optionen auf den Pfeil rechts klicken.",
|
||||||
|
"expand_first_level": "Direkte Unterelemente erweitern",
|
||||||
|
"expand_nth_level": "{{depth}} Ebenen erweitern"
|
||||||
},
|
},
|
||||||
"edited_notes": {
|
"edited_notes": {
|
||||||
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
|
||||||
@ -1517,7 +1521,8 @@
|
|||||||
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
||||||
"create-child-note": "Unternotiz anlegen",
|
"create-child-note": "Unternotiz anlegen",
|
||||||
"unhoist": "Fokus verlassen",
|
"unhoist": "Fokus verlassen",
|
||||||
"toggle-sidebar": "Seitenleiste ein-/ausblenden"
|
"toggle-sidebar": "Seitenleiste ein-/ausblenden",
|
||||||
|
"dropping-not-allowed": "Ablegen von Notizen an dieser Stelle ist nicht zulässig."
|
||||||
},
|
},
|
||||||
"title_bar_buttons": {
|
"title_bar_buttons": {
|
||||||
"window-on-top": "Dieses Fenster immer oben halten"
|
"window-on-top": "Dieses Fenster immer oben halten"
|
||||||
@ -1620,7 +1625,8 @@
|
|||||||
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
|
"duplicate-launcher": "Launcher duplizieren <kbd data-command=\"duplicateSubtree\">"
|
||||||
},
|
},
|
||||||
"editable-text": {
|
"editable-text": {
|
||||||
"auto-detect-language": "Automatisch erkannt"
|
"auto-detect-language": "Automatisch erkannt",
|
||||||
|
"keeps-crashing": "Die Bearbeitungskomponente stürzt immer wieder ab. Bitte starten Sie Trilium neu. Wenn das Problem weiterhin besteht, erstellen Sie einen Fehlerbericht."
|
||||||
},
|
},
|
||||||
"highlighting": {
|
"highlighting": {
|
||||||
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
|
||||||
@ -2089,7 +2095,7 @@
|
|||||||
"slide-overview": "Übersicht der Folien ein-/ausblenden"
|
"slide-overview": "Übersicht der Folien ein-/ausblenden"
|
||||||
},
|
},
|
||||||
"read-only-info": {
|
"read-only-info": {
|
||||||
"read-only-note": "Aktuell wird eine Notiz nur im Lese-Modus angezeigt.",
|
"read-only-note": "Aktuelle Notiz wird im Lese-Modus angezeigt.",
|
||||||
"auto-read-only-note": "Diese Notiz wird im Nur-Lesen-Modus angezeigt, um ein schnelleres Laden zu ermöglichen.",
|
"auto-read-only-note": "Diese Notiz wird im Nur-Lesen-Modus angezeigt, um ein schnelleres Laden zu ermöglichen.",
|
||||||
"auto-read-only-learn-more": "Mehr erfahren",
|
"auto-read-only-learn-more": "Mehr erfahren",
|
||||||
"edit-note": "Notiz bearbeiten"
|
"edit-note": "Notiz bearbeiten"
|
||||||
|
|||||||
@ -1212,7 +1212,8 @@
|
|||||||
"unhoist": "ホイスト解除",
|
"unhoist": "ホイスト解除",
|
||||||
"saved-search-note-refreshed": "保存した検索ノートが更新されました。",
|
"saved-search-note-refreshed": "保存した検索ノートが更新されました。",
|
||||||
"refresh-saved-search-results": "保存した検索結果を更新",
|
"refresh-saved-search-results": "保存した検索結果を更新",
|
||||||
"toggle-sidebar": "サイドバーを切り替え"
|
"toggle-sidebar": "サイドバーを切り替え",
|
||||||
|
"dropping-not-allowed": "この場所にノートをドロップすることはできません。"
|
||||||
},
|
},
|
||||||
"bulk_actions": {
|
"bulk_actions": {
|
||||||
"bulk_actions": "一括操作",
|
"bulk_actions": "一括操作",
|
||||||
@ -1266,7 +1267,8 @@
|
|||||||
"reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。"
|
"reset_launcher_confirm": "本当に「{{title}}」をリセットしますか? このノート(およびその子ノート)のすべてのデータと設定が失われ、ランチャーは元の場所に戻ります。"
|
||||||
},
|
},
|
||||||
"editable-text": {
|
"editable-text": {
|
||||||
"auto-detect-language": "自動検出"
|
"auto-detect-language": "自動検出",
|
||||||
|
"keeps-crashing": "編集コンポーネントがクラッシュし続けます。Trilium を再起動してください。問題が解決しない場合は、バグレポートの作成をご検討ください。"
|
||||||
},
|
},
|
||||||
"highlighting": {
|
"highlighting": {
|
||||||
"title": "コードブロック",
|
"title": "コードブロック",
|
||||||
|
|||||||
@ -39,7 +39,9 @@
|
|||||||
"edit_branch_prefix": "브랜치 접두사 편집",
|
"edit_branch_prefix": "브랜치 접두사 편집",
|
||||||
"help_on_tree_prefix": "트리 접두사에 대한 도움말",
|
"help_on_tree_prefix": "트리 접두사에 대한 도움말",
|
||||||
"prefix": "접두사: ",
|
"prefix": "접두사: ",
|
||||||
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다."
|
"branch_prefix_saved": "브랜치 접두사가 저장되었습니다.",
|
||||||
|
"edit_branch_prefix_multiple": "{{count}}개의 지점 접두사 편집",
|
||||||
|
"branch_prefix_saved_multiple": "{{count}}개의 지점에 대해 지점 접두사가 저장되었습니다."
|
||||||
},
|
},
|
||||||
"bulk_actions": {
|
"bulk_actions": {
|
||||||
"bulk_actions": "대량 작업",
|
"bulk_actions": "대량 작업",
|
||||||
|
|||||||
@ -1516,7 +1516,8 @@
|
|||||||
"refresh-saved-search-results": "重新整理儲存的搜尋結果",
|
"refresh-saved-search-results": "重新整理儲存的搜尋結果",
|
||||||
"create-child-note": "建立子筆記",
|
"create-child-note": "建立子筆記",
|
||||||
"unhoist": "取消聚焦",
|
"unhoist": "取消聚焦",
|
||||||
"toggle-sidebar": "切換側邊欄"
|
"toggle-sidebar": "切換側邊欄",
|
||||||
|
"dropping-not-allowed": "不允許移動筆記至此處。"
|
||||||
},
|
},
|
||||||
"title_bar_buttons": {
|
"title_bar_buttons": {
|
||||||
"window-on-top": "保持此視窗置頂"
|
"window-on-top": "保持此視窗置頂"
|
||||||
@ -1619,7 +1620,8 @@
|
|||||||
"duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">"
|
"duplicate-launcher": "複製啟動器 <kbd data-command=\"duplicateSubtree\">"
|
||||||
},
|
},
|
||||||
"editable-text": {
|
"editable-text": {
|
||||||
"auto-detect-language": "自動檢測"
|
"auto-detect-language": "自動檢測",
|
||||||
|
"keeps-crashing": "編輯元件持續發生崩潰。請嘗試重新啟動 Trilium。若問題仍存在,請考慮提交錯誤報告。"
|
||||||
},
|
},
|
||||||
"highlighting": {
|
"highlighting": {
|
||||||
"description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。",
|
"description": "控制文字筆記程式碼區塊中的語法高亮,程式碼筆記不會受到影響。",
|
||||||
|
|||||||
@ -28,8 +28,9 @@ export default function NoteDetail() {
|
|||||||
const { note, type, mime, noteContext, parentComponent } = useNoteInfo();
|
const { note, type, mime, noteContext, parentComponent } = useNoteInfo();
|
||||||
const { ntxId, viewScope } = noteContext ?? {};
|
const { ntxId, viewScope } = noteContext ?? {};
|
||||||
const isFullHeight = checkFullHeight(noteContext, type);
|
const isFullHeight = checkFullHeight(noteContext, type);
|
||||||
const noteTypesToRender = useRef<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
const [ noteTypesToRender, setNoteTypesToRender ] = useState<{ [ key in ExtendedNoteType ]?: (props: TypeWidgetProps) => VNode }>({});
|
||||||
const [ activeNoteType, setActiveNoteType ] = useState<ExtendedNoteType>();
|
const [ activeNoteType, setActiveNoteType ] = useState<ExtendedNoteType>();
|
||||||
|
const widgetRequestId = useRef(0);
|
||||||
|
|
||||||
const props: TypeWidgetProps = {
|
const props: TypeWidgetProps = {
|
||||||
note: note!,
|
note: note!,
|
||||||
@ -38,19 +39,28 @@ export default function NoteDetail() {
|
|||||||
parentComponent,
|
parentComponent,
|
||||||
noteContext
|
noteContext
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!type) return;
|
if (!type) return;
|
||||||
|
const requestId = ++widgetRequestId.current;
|
||||||
|
|
||||||
if (!noteTypesToRender.current[type]) {
|
if (!noteTypesToRender[type]) {
|
||||||
getCorrespondingWidget(type).then((el) => {
|
getCorrespondingWidget(type).then((el) => {
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
noteTypesToRender.current[type] = el;
|
|
||||||
|
// Ignore stale requests
|
||||||
|
if (requestId !== widgetRequestId.current) return;
|
||||||
|
|
||||||
|
setNoteTypesToRender(prev => ({
|
||||||
|
...prev,
|
||||||
|
[type]: el
|
||||||
|
}));
|
||||||
setActiveNoteType(type);
|
setActiveNoteType(type);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setActiveNoteType(type);
|
setActiveNoteType(type);
|
||||||
}
|
}
|
||||||
}, [ note, viewScope, type ]);
|
}, [ note, viewScope, type, noteTypesToRender ]);
|
||||||
|
|
||||||
// Detect note type changes.
|
// Detect note type changes.
|
||||||
useTriliumEvent("entitiesReloaded", async ({ loadResults }) => {
|
useTriliumEvent("entitiesReloaded", async ({ loadResults }) => {
|
||||||
@ -192,7 +202,7 @@ export default function NoteDetail() {
|
|||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
class={`note-detail ${isFullHeight ? "full-height" : ""}`}
|
class={`note-detail ${isFullHeight ? "full-height" : ""}`}
|
||||||
>
|
>
|
||||||
{Object.entries(noteTypesToRender.current).map(([ itemType, Element ]) => {
|
{Object.entries(noteTypesToRender).map(([ itemType, Element ]) => {
|
||||||
return <NoteDetailWrapper
|
return <NoteDetailWrapper
|
||||||
Element={Element}
|
Element={Element}
|
||||||
key={itemType}
|
key={itemType}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
|
|||||||
const isVerticalLayout = !isHorizontalLayout;
|
const isVerticalLayout = !isHorizontalLayout;
|
||||||
const parentComponent = useContext(ParentComponent);
|
const parentComponent = useContext(ParentComponent);
|
||||||
const { isUpdateAvailable, latestVersion } = useTriliumUpdateStatus();
|
const { isUpdateAvailable, latestVersion } = useTriliumUpdateStatus();
|
||||||
|
const isMobileLocal = isMobile();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
@ -38,6 +39,8 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
|
|||||||
</div>}
|
</div>}
|
||||||
</>}
|
</>}
|
||||||
noDropdownListStyle
|
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}
|
||||||
>
|
>
|
||||||
|
|
||||||
<MenuItem command="openNewWindow" icon="bx bx-window-open" text={t("global_menu.open_new_window")} />
|
<MenuItem command="openNewWindow" icon="bx bx-window-open" text={t("global_menu.open_new_window")} />
|
||||||
|
|||||||
@ -204,8 +204,19 @@ function AddNewColumn({ api, isInRelationMode }: { api: BoardApi, isInRelationMo
|
|||||||
setIsCreatingNewColumn(true);
|
setIsCreatingNewColumn(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const keydownCallback = useCallback((e: KeyboardEvent) => {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
setIsCreatingNewColumn(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`board-add-column ${isCreatingNewColumn ? "editing" : ""}`} onClick={addColumnCallback}>
|
<div
|
||||||
|
className={`board-add-column ${isCreatingNewColumn ? "editing" : ""}`}
|
||||||
|
onClick={addColumnCallback}
|
||||||
|
onKeyDown={keydownCallback}
|
||||||
|
tabIndex={300}
|
||||||
|
>
|
||||||
{!isCreatingNewColumn
|
{!isCreatingNewColumn
|
||||||
? <>
|
? <>
|
||||||
<Icon icon="bx bx-plus" />{" "}
|
<Icon icon="bx bx-plus" />{" "}
|
||||||
|
|||||||
@ -59,6 +59,7 @@ body.desktop .modal.popup-editor-dialog .modal-dialog {
|
|||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
background: var(--modal-background-color);
|
background: var(--modal-background-color);
|
||||||
z-index: 998;
|
z-index: 998;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal.popup-editor-dialog .note-detail.full-height {
|
.modal.popup-editor-dialog .note-detail.full-height {
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import utils from "../../services/utils";
|
|||||||
import tree from "../../services/tree";
|
import tree from "../../services/tree";
|
||||||
import froca from "../../services/froca";
|
import froca from "../../services/froca";
|
||||||
import ReadOnlyNoteInfoBar from "../ReadOnlyNoteInfoBar";
|
import ReadOnlyNoteInfoBar from "../ReadOnlyNoteInfoBar";
|
||||||
|
import MobileEditorToolbar from "../type_widgets/text/mobile_editor_toolbar";
|
||||||
|
|
||||||
export default function PopupEditor() {
|
export default function PopupEditor() {
|
||||||
const [ shown, setShown ] = useState(false);
|
const [ shown, setShown ] = useState(false);
|
||||||
@ -67,10 +68,15 @@ export default function PopupEditor() {
|
|||||||
}}
|
}}
|
||||||
onHidden={() => setShown(false)}
|
onHidden={() => setShown(false)}
|
||||||
keepInDom // needed for faster loading
|
keepInDom // needed for faster loading
|
||||||
|
noFocus // automatic focus breaks block popup
|
||||||
>
|
>
|
||||||
<ReadOnlyNoteInfoBar />
|
<ReadOnlyNoteInfoBar />
|
||||||
<PromotedAttributes />
|
<PromotedAttributes />
|
||||||
<StandaloneRibbonAdapter component={FormattingToolbar} />
|
|
||||||
|
{isMobile
|
||||||
|
? <MobileEditorToolbar inPopupEditor />
|
||||||
|
: <StandaloneRibbonAdapter component={FormattingToolbar} />}
|
||||||
|
|
||||||
<FloatingButtons items={items} />
|
<FloatingButtons items={items} />
|
||||||
<NoteDetail />
|
<NoteDetail />
|
||||||
<NoteList media="screen" displayOnlyCollections />
|
<NoteList media="screen" displayOnlyCollections />
|
||||||
|
|||||||
@ -19,9 +19,11 @@ export interface DropdownProps extends Pick<HTMLProps<HTMLDivElement>, "id" | "c
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
text?: ComponentChildren;
|
text?: ComponentChildren;
|
||||||
forceShown?: boolean;
|
forceShown?: boolean;
|
||||||
|
onShown?: () => void;
|
||||||
|
onHidden?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown }: DropdownProps) {
|
export default function Dropdown({ id, className, buttonClassName, isStatic, children, title, text, dropdownContainerStyle, dropdownContainerClassName, hideToggleArrow, iconAction, disabled, noSelectButtonStyle, noDropdownListStyle, forceShown, onShown: externalOnShown, onHidden: externalOnHidden }: DropdownProps) {
|
||||||
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
||||||
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
@ -40,10 +42,12 @@ export default function Dropdown({ id, className, buttonClassName, isStatic, chi
|
|||||||
|
|
||||||
const onShown = useCallback(() => {
|
const onShown = useCallback(() => {
|
||||||
setShown(true);
|
setShown(true);
|
||||||
|
externalOnShown?.();
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onHidden = useCallback(() => {
|
const onHidden = useCallback(() => {
|
||||||
setShown(false);
|
setShown(false);
|
||||||
|
externalOnHidden?.();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -66,9 +66,13 @@ interface ModalProps {
|
|||||||
* If true, the modal will remain in the DOM even when not shown. This can be useful for certain CSS transitions or when you want to avoid re-mounting the modal content.
|
* If true, the modal will remain in the DOM even when not shown. This can be useful for certain CSS transitions or when you want to avoid re-mounting the modal content.
|
||||||
*/
|
*/
|
||||||
keepInDom?: boolean;
|
keepInDom?: boolean;
|
||||||
|
/**
|
||||||
|
* If true, the modal will not focus itself after becoming visible.
|
||||||
|
*/
|
||||||
|
noFocus?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom }: ModalProps) {
|
export default function Modal({ children, className, size, title, header, footer, footerStyle, footerAlignment, onShown, onSubmit, helpPageId, minWidth, maxWidth, zIndex, scrollable, onHidden: onHidden, modalRef: externalModalRef, formRef, bodyStyle, show, stackable, keepInDom, noFocus }: ModalProps) {
|
||||||
const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef);
|
const modalRef = useSyncedRef<HTMLDivElement>(externalModalRef);
|
||||||
const modalInstanceRef = useRef<BootstrapModal>();
|
const modalInstanceRef = useRef<BootstrapModal>();
|
||||||
const elementToFocus = useRef<Element | null>();
|
const elementToFocus = useRef<Element | null>();
|
||||||
@ -100,13 +104,15 @@ export default function Modal({ children, className, size, title, header, footer
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (show && modalRef.current) {
|
if (show && modalRef.current) {
|
||||||
elementToFocus.current = document.activeElement;
|
elementToFocus.current = document.activeElement;
|
||||||
openDialog($(modalRef.current), !stackable).then(($widget) => {
|
openDialog($(modalRef.current), !stackable, {
|
||||||
|
focus: !noFocus
|
||||||
|
}).then(($widget) => {
|
||||||
modalInstanceRef.current = BootstrapModal.getOrCreateInstance($widget[0]);
|
modalInstanceRef.current = BootstrapModal.getOrCreateInstance($widget[0]);
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
modalInstanceRef.current?.hide();
|
modalInstanceRef.current?.hide();
|
||||||
}
|
}
|
||||||
}, [ show, modalRef.current ]);
|
}, [ show, modalRef.current, noFocus ]);
|
||||||
|
|
||||||
// Memoize styles to prevent recreation on every render
|
// Memoize styles to prevent recreation on every render
|
||||||
const dialogStyle = useMemo<CSSProperties>(() => {
|
const dialogStyle = useMemo<CSSProperties>(() => {
|
||||||
|
|||||||
@ -461,27 +461,31 @@ export function useNoteLabelInt(note: FNote | undefined | null, labelName: Filte
|
|||||||
|
|
||||||
export function useNoteBlob(note: FNote | null | undefined, componentId?: string): FBlob | null | undefined {
|
export function useNoteBlob(note: FNote | null | undefined, componentId?: string): FBlob | null | undefined {
|
||||||
const [ blob, setBlob ] = useState<FBlob | null>();
|
const [ blob, setBlob ] = useState<FBlob | null>();
|
||||||
|
const requestIdRef = useRef(0);
|
||||||
|
|
||||||
function refresh() {
|
async function refresh() {
|
||||||
note?.getBlob().then(setBlob);
|
const requestId = ++requestIdRef.current;
|
||||||
|
const newBlob = await note?.getBlob();
|
||||||
|
|
||||||
|
// Only update if this is the latest request.
|
||||||
|
if (requestId === requestIdRef.current) {
|
||||||
|
setBlob(newBlob);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(refresh, [ note?.noteId ]);
|
useEffect(() => { refresh() }, [ note?.noteId ]);
|
||||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||||
if (!note) return;
|
if (!note) return;
|
||||||
|
|
||||||
// Check if the note was deleted.
|
// Check if the note was deleted.
|
||||||
if (loadResults.getEntityRow("notes", note.noteId)?.isDeleted) {
|
if (loadResults.getEntityRow("notes", note.noteId)?.isDeleted) {
|
||||||
|
requestIdRef.current++; // invalidate pending results
|
||||||
setBlob(null);
|
setBlob(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a revision occurred.
|
if (loadResults.hasRevisionForNote(note.noteId) ||
|
||||||
if (loadResults.hasRevisionForNote(note.noteId)) {
|
loadResults.isNoteContentReloaded(note.noteId, componentId)) {
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadResults.isNoteContentReloaded(note.noteId, componentId)) {
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import NoteActions from "./NoteActions";
|
|||||||
import { KeyboardActionNames } from "@triliumnext/commons";
|
import { KeyboardActionNames } from "@triliumnext/commons";
|
||||||
import { RIBBON_TAB_DEFINITIONS } from "./RibbonDefinition";
|
import { RIBBON_TAB_DEFINITIONS } from "./RibbonDefinition";
|
||||||
import { TabConfiguration, TitleContext } from "./ribbon-interface";
|
import { TabConfiguration, TitleContext } from "./ribbon-interface";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>(RIBBON_TAB_DEFINITIONS);
|
const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>(RIBBON_TAB_DEFINITIONS);
|
||||||
|
|
||||||
@ -63,62 +64,61 @@ export default function Ribbon() {
|
|||||||
}, [ computedTabs, activeTabIndex ]));
|
}, [ computedTabs, activeTabIndex ]));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ribbon-container" style={{ contain: "none" }}>
|
<div
|
||||||
{noteContext?.viewScope?.viewMode === "default" && (
|
className={clsx("ribbon-container", noteContext?.viewScope?.viewMode !== "default" && "hidden-ext")}
|
||||||
<>
|
style={{ contain: "none" }}
|
||||||
<div className="ribbon-top-row">
|
>
|
||||||
<div className="ribbon-tab-container">
|
<div className="ribbon-top-row">
|
||||||
{computedTabs && computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
<div className="ribbon-tab-container">
|
||||||
shouldShow && <RibbonTab
|
{computedTabs && computedTabs.map(({ title, icon, index, toggleCommand, shouldShow }) => (
|
||||||
icon={icon}
|
shouldShow && <RibbonTab
|
||||||
title={typeof title === "string" ? title : title(titleContext)}
|
icon={icon}
|
||||||
active={index === activeTabIndex}
|
title={typeof title === "string" ? title : title(titleContext)}
|
||||||
toggleCommand={toggleCommand}
|
active={index === activeTabIndex}
|
||||||
onClick={() => {
|
toggleCommand={toggleCommand}
|
||||||
if (activeTabIndex !== index) {
|
onClick={() => {
|
||||||
setActiveTabIndex(index);
|
if (activeTabIndex !== index) {
|
||||||
} else {
|
setActiveTabIndex(index);
|
||||||
// Collapse
|
} else {
|
||||||
setActiveTabIndex(undefined);
|
// Collapse
|
||||||
}
|
setActiveTabIndex(undefined);
|
||||||
}}
|
}
|
||||||
/>
|
}}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="ribbon-button-container">
|
||||||
|
{ note && <NoteActions note={note} noteContext={noteContext} /> }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ribbon-body-container">
|
||||||
|
{computedTabs && computedTabs.map(tab => {
|
||||||
|
const isActive = tab.index === activeTabIndex;
|
||||||
|
if (!isActive && !tab.stayInDom) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TabContent = tab.content;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`ribbon-body ${!isActive ? "hidden-ext" : ""}`}>
|
||||||
|
<TabContent
|
||||||
|
note={note}
|
||||||
|
hidden={!isActive}
|
||||||
|
ntxId={ntxId}
|
||||||
|
hoistedNoteId={hoistedNoteId}
|
||||||
|
notePath={notePath}
|
||||||
|
noteContext={noteContext}
|
||||||
|
componentId={componentId}
|
||||||
|
activate={useCallback(() => {
|
||||||
|
setActiveTabIndex(tab.index)
|
||||||
|
}, [setActiveTabIndex])}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ribbon-button-container">
|
);
|
||||||
{ note && <NoteActions note={note} noteContext={noteContext} /> }
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="ribbon-body-container">
|
|
||||||
{computedTabs && computedTabs.map(tab => {
|
|
||||||
const isActive = tab.index === activeTabIndex;
|
|
||||||
if (!isActive && !tab.stayInDom) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TabContent = tab.content;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`ribbon-body ${!isActive ? "hidden-ext" : ""}`}>
|
|
||||||
<TabContent
|
|
||||||
note={note}
|
|
||||||
hidden={!isActive}
|
|
||||||
ntxId={ntxId}
|
|
||||||
hoistedNoteId={hoistedNoteId}
|
|
||||||
notePath={notePath}
|
|
||||||
noteContext={noteContext}
|
|
||||||
componentId={componentId}
|
|
||||||
activate={useCallback(() => {
|
|
||||||
setActiveTabIndex(tab.index)
|
|
||||||
}, [setActiveTabIndex])}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,6 @@ export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetPro
|
|||||||
|
|
||||||
// React to included note changes.
|
// React to included note changes.
|
||||||
useTriliumEvent("refreshIncludedNote", ({ noteId }) => {
|
useTriliumEvent("refreshIncludedNote", ({ noteId }) => {
|
||||||
console.log("Refresh ", noteId);
|
|
||||||
if (!contentRef.current) return;
|
if (!contentRef.current) return;
|
||||||
refreshIncludedNote(contentRef.current, noteId);
|
refreshIncludedNote(contentRef.current, noteId);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,52 +1,54 @@
|
|||||||
.classic-toolbar-outer-container {
|
body.mobile {
|
||||||
contain: none !important;
|
.classic-toolbar-outer-container {
|
||||||
}
|
contain: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.classic-toolbar-outer-container.visible {
|
.classic-toolbar-outer-container.visible {
|
||||||
height: 38px;
|
height: 38px;
|
||||||
background-color: var(--main-background-color);
|
background-color: var(--main-background-color);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#root-widget.virtual-keyboard-opened .classic-toolbar-outer-container.ios {
|
#root-widget.virtual-keyboard-opened .classic-toolbar-outer-container.ios {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.classic-toolbar-widget {
|
.classic-toolbar-widget {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
inset-inline-end: 0;
|
inset-inline-end: 0;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
scrollbar-width: 0 !important;
|
scrollbar-width: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.classic-toolbar-widget::-webkit-scrollbar:horizontal {
|
.classic-toolbar-widget::-webkit-scrollbar:horizontal {
|
||||||
height: 0 !important;
|
height: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.classic-toolbar-widget.dropdown-active {
|
.classic-toolbar-widget.dropdown-active {
|
||||||
height: 50vh;
|
height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.classic-toolbar-widget .ck.ck-toolbar {
|
.classic-toolbar-widget .ck.ck-toolbar {
|
||||||
--ck-color-toolbar-background: transparent;
|
--ck-color-toolbar-background: transparent;
|
||||||
--ck-color-button-default-background: transparent;
|
--ck-color-button-default-background: transparent;
|
||||||
--ck-color-button-default-disabled-background: transparent;
|
--ck-color-button-default-disabled-background: transparent;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.classic-toolbar-widget .ck.ck-button.ck-disabled {
|
.classic-toolbar-widget .ck.ck-button.ck-disabled {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -4,19 +4,23 @@ import "./mobile_editor_toolbar.css";
|
|||||||
import { isIOS } from "../../../services/utils";
|
import { isIOS } from "../../../services/utils";
|
||||||
import { CKTextEditor, ClassicEditor } from "@triliumnext/ckeditor5";
|
import { CKTextEditor, ClassicEditor } from "@triliumnext/ckeditor5";
|
||||||
|
|
||||||
|
interface MobileEditorToolbarProps {
|
||||||
|
inPopupEditor?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism:
|
* Handles the editing toolbar for CKEditor in mobile mode. The toolbar acts as a floating bar, with two different mechanism:
|
||||||
*
|
*
|
||||||
* - On iOS, because it does not respect the viewport meta value `interactive-widget=resizes-content`, we need to listen to window resizes and scroll and reposition the toolbar using absolute positioning.
|
* - On iOS, because it does not respect the viewport meta value `interactive-widget=resizes-content`, we need to listen to window resizes and scroll and reposition the toolbar using absolute positioning.
|
||||||
* - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style).
|
* - On Android, the viewport change makes the keyboard resize the content area, all we have to do is to hide the tab bar and global menu (handled in the global style).
|
||||||
*/
|
*/
|
||||||
export default function MobileEditorToolbar() {
|
export default function MobileEditorToolbar({ inPopupEditor }: MobileEditorToolbarProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const { note, noteContext, ntxId } = useNoteContext();
|
const { note, noteContext, ntxId } = useNoteContext();
|
||||||
const [ shouldDisplay, setShouldDisplay ] = useState(false);
|
const [ shouldDisplay, setShouldDisplay ] = useState(false);
|
||||||
const [ dropdownActive, setDropdownActive ] = useState(false);
|
const [ dropdownActive, setDropdownActive ] = useState(false);
|
||||||
|
|
||||||
usePositioningOniOS(containerRef);
|
usePositioningOniOS(!inPopupEditor, containerRef);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
noteContext?.isReadOnly().then(isReadOnly => {
|
noteContext?.isReadOnly().then(isReadOnly => {
|
||||||
@ -29,7 +33,10 @@ export default function MobileEditorToolbar() {
|
|||||||
if (eventNtxId !== ntxId || !containerRef.current) return;
|
if (eventNtxId !== ntxId || !containerRef.current) return;
|
||||||
const toolbar = editor.ui.view.toolbar?.element;
|
const toolbar = editor.ui.view.toolbar?.element;
|
||||||
|
|
||||||
repositionDropdowns(editor);
|
if (!inPopupEditor) {
|
||||||
|
repositionDropdowns(editor);
|
||||||
|
}
|
||||||
|
|
||||||
if (toolbar) {
|
if (toolbar) {
|
||||||
containerRef.current.replaceChildren(toolbar);
|
containerRef.current.replaceChildren(toolbar);
|
||||||
} else {
|
} else {
|
||||||
@ -60,7 +67,7 @@ export default function MobileEditorToolbar() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
function usePositioningOniOS(enabled: boolean, wrapperRef: MutableRef<HTMLDivElement | null>) {
|
||||||
const adjustPosition = useCallback(() => {
|
const adjustPosition = useCallback(() => {
|
||||||
if (!wrapperRef.current) return;
|
if (!wrapperRef.current) return;
|
||||||
let bottom = window.innerHeight - (window.visualViewport?.height || 0);
|
let bottom = window.innerHeight - (window.visualViewport?.height || 0);
|
||||||
@ -68,7 +75,7 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isIOS()) return;
|
if (!isIOS() || !enabled) return;
|
||||||
|
|
||||||
window.visualViewport?.addEventListener("resize", adjustPosition);
|
window.visualViewport?.addEventListener("resize", adjustPosition);
|
||||||
window.addEventListener("scroll", adjustPosition);
|
window.addEventListener("scroll", adjustPosition);
|
||||||
@ -77,7 +84,7 @@ function usePositioningOniOS(wrapperRef: MutableRef<HTMLDivElement | null>) {
|
|||||||
window.visualViewport?.removeEventListener("resize", adjustPosition);
|
window.visualViewport?.removeEventListener("resize", adjustPosition);
|
||||||
window.removeEventListener("scroll", adjustPosition);
|
window.removeEventListener("scroll", adjustPosition);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [ enabled ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "2.1.3",
|
"@electron/remote": "2.1.3",
|
||||||
"better-sqlite3": "12.4.6",
|
"better-sqlite3": "12.5.0",
|
||||||
"electron-debug": "4.1.0",
|
"electron-debug": "4.1.0",
|
||||||
"electron-dl": "4.0.0",
|
"electron-dl": "4.0.0",
|
||||||
"electron-squirrel-startup": "1.0.1",
|
"electron-squirrel-startup": "1.0.1",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes",
|
"description": "Standalone tool to dump contents of Trilium document.db file into a directory tree of notes",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "12.4.6",
|
"better-sqlite3": "12.5.0",
|
||||||
"mime-types": "3.0.2",
|
"mime-types": "3.0.2",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
"tsx": "4.20.6",
|
"tsx": "4.20.6",
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
|
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"better-sqlite3": "12.4.6"
|
"better-sqlite3": "12.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@triliumnext/client": "workspace:*",
|
"@triliumnext/client": "workspace:*",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "12.4.6"
|
"better-sqlite3": "12.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@
|
|||||||
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine"
|
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"better-sqlite3": "12.4.6",
|
"better-sqlite3": "12.5.0",
|
||||||
"html-to-text": "9.0.5",
|
"html-to-text": "9.0.5",
|
||||||
"node-html-parser": "7.0.1"
|
"node-html-parser": "7.0.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -39,7 +39,28 @@
|
|||||||
"activate-previous-tab": "좌측 탭 활성화",
|
"activate-previous-tab": "좌측 탭 활성화",
|
||||||
"open-new-window": "새 비어있는 창 열기",
|
"open-new-window": "새 비어있는 창 열기",
|
||||||
"toggle-tray": "시스템 트레이에서 애플리케이션 보여주기/숨기기",
|
"toggle-tray": "시스템 트레이에서 애플리케이션 보여주기/숨기기",
|
||||||
"tabs-and-windows": "탭 & 창"
|
"tabs-and-windows": "탭 & 창",
|
||||||
|
"first-tab": "목록의 첫 번째 탭 활성화",
|
||||||
|
"second-tab": "목록의 두 번째 탭 활성화",
|
||||||
|
"third-tab": "목록의 세 번째 탭 활성화",
|
||||||
|
"fourth-tab": "목록의 네 번째 탭 활성화",
|
||||||
|
"fifth-tab": "목록의 다섯 번째 탭 활성화",
|
||||||
|
"sixth-tab": "목록의 여섯 번째 탭 활성화",
|
||||||
|
"seventh-tab": "목록의 일곱 번째 탭 활성화",
|
||||||
|
"eight-tab": "목록의 여덟 번째 탭 활성화",
|
||||||
|
"ninth-tab": "목록의 아홉 번째 탭 활성화",
|
||||||
|
"last-tab": "목록의 마지막 탭 활성화",
|
||||||
|
"dialogs": "대화 상자",
|
||||||
|
"show-note-source": "\"노트 소스\" 대화 상자 표시",
|
||||||
|
"show-options": "\"옵션\" 페이지 열기",
|
||||||
|
"show-revisions": "\"노트 리비젼\" 대화 상자 표시",
|
||||||
|
"show-recent-changes": "\"최근 변경 사항\" 대화 상자 표시",
|
||||||
|
"show-sql-console": "\"SQL 콘솔\" 페이지 열기",
|
||||||
|
"show-backend-log": "\"백엔드 로그\" 페이지 열기",
|
||||||
|
"show-help": "내장 사용자 설명서 열기",
|
||||||
|
"show-cheatsheet": "일반적인 키보드 형식의 팝업 표시",
|
||||||
|
"text-note-operations": "텍스트 노트 작업",
|
||||||
|
"add-link-to-text": "텍스트에 링크 추가를 위한 대화 상자 열기"
|
||||||
},
|
},
|
||||||
"hidden-subtree": {
|
"hidden-subtree": {
|
||||||
"zen-mode": "젠 모드",
|
"zen-mode": "젠 모드",
|
||||||
|
|||||||
@ -40,6 +40,13 @@ interface Subroot {
|
|||||||
|
|
||||||
type GetNoteFunction = (id: string) => SNote | BNote | null;
|
type GetNoteFunction = (id: string) => SNote | BNote | null;
|
||||||
|
|
||||||
|
function addContentAccessQuery(note: SNote | BNote, secondEl?:boolean) {
|
||||||
|
if (!(note instanceof BNote) && note.contentAccessor && note.contentAccessor?.type === "query") {
|
||||||
|
return secondEl ? `&cat=${note.contentAccessor.getToken()}` : `?cat=${note.contentAccessor.getToken()}`;
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot {
|
function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot {
|
||||||
if (!note || note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
|
if (!note || note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
|
||||||
// share root itself is not shared
|
// share root itself is not shared
|
||||||
@ -111,7 +118,7 @@ export function renderNoteContent(note: SNote) {
|
|||||||
cssToLoad.push(`assets/scripts.css`);
|
cssToLoad.push(`assets/scripts.css`);
|
||||||
}
|
}
|
||||||
for (const cssRelation of note.getRelations("shareCss")) {
|
for (const cssRelation of note.getRelations("shareCss")) {
|
||||||
cssToLoad.push(`api/notes/${cssRelation.value}/download`);
|
cssToLoad.push(`api/notes/${cssRelation.value}/download${addContentAccessQuery(note)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine JS to load.
|
// Determine JS to load.
|
||||||
@ -119,11 +126,11 @@ export function renderNoteContent(note: SNote) {
|
|||||||
"assets/scripts.js"
|
"assets/scripts.js"
|
||||||
];
|
];
|
||||||
for (const jsRelation of note.getRelations("shareJs")) {
|
for (const jsRelation of note.getRelations("shareJs")) {
|
||||||
jsToLoad.push(`api/notes/${jsRelation.value}/download`);
|
jsToLoad.push(`api/notes/${jsRelation.value}/download${addContentAccessQuery(note)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const customLogoId = note.getRelation("shareLogo")?.value;
|
const customLogoId = note.getRelation("shareLogo")?.value;
|
||||||
const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png` : `../${assetUrlFragment}/images/icon-color.svg`;
|
const logoUrl = customLogoId ? `api/images/${customLogoId}/image.png${addContentAccessQuery(note)}` : `../${assetUrlFragment}/images/icon-color.svg`;
|
||||||
|
|
||||||
return renderNoteContentInternal(note, {
|
return renderNoteContentInternal(note, {
|
||||||
subRoot,
|
subRoot,
|
||||||
@ -133,7 +140,7 @@ export function renderNoteContent(note: SNote) {
|
|||||||
logoUrl,
|
logoUrl,
|
||||||
ancestors,
|
ancestors,
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
faviconUrl: note.hasRelation("shareFavicon") ? `api/notes/${note.getRelationValue("shareFavicon")}/download` : `../favicon.ico`
|
faviconUrl: note.hasRelation("shareFavicon") ? `api/notes/${note.getRelationValue("shareFavicon")}/download${addContentAccessQuery(note)}` : `../favicon.ico`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,6 +165,7 @@ function renderNoteContentInternal(note: SNote | BNote, renderArgs: RenderArgs)
|
|||||||
isEmpty,
|
isEmpty,
|
||||||
assetPath: shareAdjustedAssetPath,
|
assetPath: shareAdjustedAssetPath,
|
||||||
assetUrlFragment,
|
assetUrlFragment,
|
||||||
|
addContentAccessQuery: (second: boolean | undefined) => addContentAccessQuery(note, second),
|
||||||
showLoginInShareTheme,
|
showLoginInShareTheme,
|
||||||
t,
|
t,
|
||||||
isDev,
|
isDev,
|
||||||
@ -325,7 +333,7 @@ function renderText(result: Result, note: SNote | BNote) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (href?.startsWith("#")) {
|
if (href?.startsWith("#")) {
|
||||||
handleAttachmentLink(linkEl, href, getNote, getAttachment);
|
handleAttachmentLink(linkEl, href, getNote, getAttachment, note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,7 +357,7 @@ function renderText(result: Result, note: SNote | BNote) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNoteFunction, getAttachment: (id: string) => BAttachment | SAttachment | null) {
|
function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNoteFunction, getAttachment: (id: string) => BAttachment | SAttachment | null, note: SNote | BNote) {
|
||||||
const linkRegExp = /attachmentId=([a-zA-Z0-9_]+)/g;
|
const linkRegExp = /attachmentId=([a-zA-Z0-9_]+)/g;
|
||||||
let attachmentMatch;
|
let attachmentMatch;
|
||||||
if ((attachmentMatch = linkRegExp.exec(href))) {
|
if ((attachmentMatch = linkRegExp.exec(href))) {
|
||||||
@ -357,7 +365,7 @@ function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: GetNot
|
|||||||
const attachment = getAttachment(attachmentId);
|
const attachment = getAttachment(attachmentId);
|
||||||
|
|
||||||
if (attachment) {
|
if (attachment) {
|
||||||
linkEl.setAttribute("href", `api/attachments/${attachmentId}/download`);
|
linkEl.setAttribute("href", `api/attachments/${attachmentId}/download${addContentAccessQuery(note)}`);
|
||||||
linkEl.classList.add(`attachment-link`);
|
linkEl.classList.add(`attachment-link`);
|
||||||
linkEl.classList.add(`role-${attachment.role}`);
|
linkEl.classList.add(`role-${attachment.role}`);
|
||||||
linkEl.childNodes.length = 0;
|
linkEl.childNodes.length = 0;
|
||||||
@ -430,7 +438,7 @@ function renderMermaid(result: Result, note: SNote | BNote) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result.content = `
|
result.content = `
|
||||||
<img src="api/images/${note.noteId}/${note.encodedTitle}?${note.utcDateModified}">
|
<img src="api/images/${note.noteId}/${note.encodedTitle}?${note.utcDateModified}${addContentAccessQuery(note, true)}">
|
||||||
<hr>
|
<hr>
|
||||||
<details>
|
<details>
|
||||||
<summary>Chart source</summary>
|
<summary>Chart source</summary>
|
||||||
@ -439,14 +447,14 @@ function renderMermaid(result: Result, note: SNote | BNote) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderImage(result: Result, note: SNote | BNote) {
|
function renderImage(result: Result, note: SNote | BNote) {
|
||||||
result.content = `<img src="api/images/${note.noteId}/${note.encodedTitle}?${note.utcDateModified}">`;
|
result.content = `<img src="api/images/${note.noteId}/${note.encodedTitle}?${note.utcDateModified}${addContentAccessQuery(note, true)}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFile(note: SNote | BNote, result: Result) {
|
function renderFile(note: SNote | BNote, result: Result) {
|
||||||
if (note.mime === "application/pdf") {
|
if (note.mime === "application/pdf") {
|
||||||
result.content = `<iframe class="pdf-view" src="api/notes/${note.noteId}/view"></iframe>`;
|
result.content = `<iframe class="pdf-view" src="api/notes/${note.noteId}/view${addContentAccessQuery(note)}"></iframe>`;
|
||||||
} else {
|
} else {
|
||||||
result.content = `<button type="button" onclick="location.href='api/notes/${note.noteId}/download'">Download file</button>`;
|
result.content = `<button type="button" onclick="location.href='api/notes/${note.noteId}/download${addContentAccessQuery(note)}'">Download file</button>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,20 @@ function checkNoteAccess(noteId: string, req: Request, res: Response) {
|
|||||||
const header = req.header("Authorization");
|
const header = req.header("Authorization");
|
||||||
|
|
||||||
if (!header?.startsWith("Basic ")) {
|
if (!header?.startsWith("Basic ")) {
|
||||||
|
if (req.path.startsWith("/share/api") && note.contentAccessor) {
|
||||||
|
let contentAccessToken = ""
|
||||||
|
if (note.contentAccessor.type === "cookie") contentAccessToken += req.cookies["trilium.cat"] || ""
|
||||||
|
else if (note.contentAccessor.type === "query") contentAccessToken += req.query['cat'] || ""
|
||||||
|
|
||||||
|
if (contentAccessToken){
|
||||||
|
if (note.contentAccessor.isTokenValid(contentAccessToken)){
|
||||||
|
return note
|
||||||
|
}
|
||||||
|
res.status(401).send("Access is expired. Return back and update the page.");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,9 +138,14 @@ function register(router: Router) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.isLabelTruthy("shareExclude")) {
|
||||||
|
res.status(404);
|
||||||
|
render404(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checkNoteAccess(note.noteId, req, res)) {
|
if (!checkNoteAccess(note.noteId, req, res)) {
|
||||||
requestCredentials(res);
|
requestCredentials(res);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +157,10 @@ function register(router: Router) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.contentAccessor && note.contentAccessor.type === "cookie") {
|
||||||
|
res.cookie('trilium.cat', note.contentAccessor.getToken(), { maxAge: note.contentAccessor.getTokenExpiration() * 1000, httpOnly: true })
|
||||||
|
}
|
||||||
|
|
||||||
res.send(renderNoteContent(note));
|
res.send(renderNoteContent(note));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,6 +186,9 @@ function register(router: Router) {
|
|||||||
const { shareId } = req.params;
|
const { shareId } = req.params;
|
||||||
|
|
||||||
const note = shaca.aliasToNote[shareId] || shaca.notes[shareId];
|
const note = shaca.aliasToNote[shareId] || shaca.notes[shareId];
|
||||||
|
if (note){
|
||||||
|
note.initContentAccessor()
|
||||||
|
}
|
||||||
|
|
||||||
renderNote(note, req, res);
|
renderNote(note, req, res);
|
||||||
});
|
});
|
||||||
|
|||||||
81
apps/server/src/share/shaca/entities/content_accessor.ts
Normal file
81
apps/server/src/share/shaca/entities/content_accessor.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import crypto from "crypto";
|
||||||
|
import SNote from "./snote";
|
||||||
|
import utils from "../../../services/utils";
|
||||||
|
|
||||||
|
const DefaultAccessTimeoutSec = 10 * 60; // 10 minutes
|
||||||
|
|
||||||
|
export class ContentAccessor {
|
||||||
|
note: SNote;
|
||||||
|
token: string;
|
||||||
|
timestamp: number;
|
||||||
|
type: string;
|
||||||
|
timeout: number;
|
||||||
|
key: Buffer;
|
||||||
|
|
||||||
|
constructor(note: SNote) {
|
||||||
|
this.note = note;
|
||||||
|
this.key = crypto.randomBytes(32);
|
||||||
|
this.token = "";
|
||||||
|
this.timestamp = 0;
|
||||||
|
this.timeout = Number(this.note.getAttributeValue("label", "shareAccessTokenTimeout") || DefaultAccessTimeoutSec)
|
||||||
|
|
||||||
|
switch (this.note.getAttributeValue("label", "shareContentAccess")) {
|
||||||
|
case "basic": this.type = "basic"; break
|
||||||
|
case "query": this.type = "query"; break
|
||||||
|
default: this.type = "cookie"; break
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
__encrypt(text: string) {
|
||||||
|
const iv = crypto.randomBytes(16);
|
||||||
|
const cipher = crypto.createCipheriv('aes-256-cbc', this.key, iv);
|
||||||
|
let encrypted = cipher.update(text, 'utf8', 'hex');
|
||||||
|
encrypted += cipher.final('hex');
|
||||||
|
return iv.toString('hex') + encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
__decrypt(encryptedText: string) {
|
||||||
|
try {
|
||||||
|
const iv = Buffer.from(encryptedText.slice(0, 32), 'hex');
|
||||||
|
const decipher = crypto.createDecipheriv('aes-256-cbc', this.key, iv);
|
||||||
|
let decrypted = decipher.update(encryptedText.slice(32), 'hex', 'utf8');
|
||||||
|
decrypted += decipher.final('utf8');
|
||||||
|
return decrypted;
|
||||||
|
} catch {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__compare(originalText: string, encryptedText: string) {
|
||||||
|
return originalText === this.__decrypt(encryptedText)
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (new Date().getTime() < this.timestamp + this.getTimeout() * 1000) return
|
||||||
|
this.token = utils.randomString(36);
|
||||||
|
this.key = crypto.randomBytes(32);
|
||||||
|
this.timestamp = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
isTokenValid(encToken: string) {
|
||||||
|
return this.__compare(this.token, encToken) && new Date().getTime() < this.timestamp + this.getTimeout() * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
getToken() {
|
||||||
|
return this.__encrypt(this.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTokenExpiration() {
|
||||||
|
return (this.timestamp + (this.timeout * 1000) - new Date().getTime()) /1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTimeout() {
|
||||||
|
return this.timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
getContentAccessType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import type SAttribute from "./sattribute.js";
|
|||||||
import type SBranch from "./sbranch.js";
|
import type SBranch from "./sbranch.js";
|
||||||
import type { SNoteRow } from "./rows.js";
|
import type { SNoteRow } from "./rows.js";
|
||||||
import { NOTE_TYPE_ICONS } from "../../../becca/entities/bnote.js";
|
import { NOTE_TYPE_ICONS } from "../../../becca/entities/bnote.js";
|
||||||
|
import { ContentAccessor } from "./content_accessor.js";
|
||||||
|
|
||||||
const LABEL = "label";
|
const LABEL = "label";
|
||||||
const RELATION = "relation";
|
const RELATION = "relation";
|
||||||
@ -33,6 +34,7 @@ class SNote extends AbstractShacaEntity {
|
|||||||
private __inheritableAttributeCache: SAttribute[] | null;
|
private __inheritableAttributeCache: SAttribute[] | null;
|
||||||
targetRelations: SAttribute[];
|
targetRelations: SAttribute[];
|
||||||
attachments: SAttachment[];
|
attachments: SAttachment[];
|
||||||
|
contentAccessor: ContentAccessor | undefined;
|
||||||
|
|
||||||
constructor([noteId, title, type, mime, blobId, utcDateModified, isProtected]: SNoteRow) {
|
constructor([noteId, title, type, mime, blobId, utcDateModified, isProtected]: SNoteRow) {
|
||||||
super();
|
super();
|
||||||
@ -59,6 +61,15 @@ class SNote extends AbstractShacaEntity {
|
|||||||
this.shaca.notes[this.noteId] = this;
|
this.shaca.notes[this.noteId] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initContentAccessor(){
|
||||||
|
if (!this.contentAccessor && this.getCredentials().length > 0) {
|
||||||
|
this.contentAccessor = new ContentAccessor(this);
|
||||||
|
}
|
||||||
|
if (this.contentAccessor) {
|
||||||
|
this.contentAccessor.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getParentBranches() {
|
getParentBranches() {
|
||||||
return this.parentBranches;
|
return this.parentBranches;
|
||||||
}
|
}
|
||||||
@ -72,7 +83,7 @@ class SNote extends AbstractShacaEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getVisibleChildBranches() {
|
getVisibleChildBranches() {
|
||||||
return this.getChildBranches().filter((branch) => !branch.isHidden && !branch.getNote().isLabelTruthy("shareHiddenFromTree"));
|
return this.getChildBranches().filter((branch) => !branch.isHidden && !branch.getNote().isLabelTruthy("shareHiddenFromTree") && !branch.getNote().isLabelTruthy("shareExclude"));
|
||||||
}
|
}
|
||||||
|
|
||||||
getParentNotes() {
|
getParentNotes() {
|
||||||
@ -80,7 +91,7 @@ class SNote extends AbstractShacaEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getChildNotes() {
|
getChildNotes() {
|
||||||
return this.children;
|
return this.children.filter((note) => !note.isLabelTruthy("shareExclude"));
|
||||||
}
|
}
|
||||||
|
|
||||||
getVisibleChildNotes() {
|
getVisibleChildNotes() {
|
||||||
|
|||||||
@ -18,8 +18,8 @@
|
|||||||
"title": "Organizace",
|
"title": "Organizace",
|
||||||
"note_structure_title": "Struktura poznámek",
|
"note_structure_title": "Struktura poznámek",
|
||||||
"note_structure_description": "Poznámky lze uspořádat hierarchicky. Není třeba používat složky, protože každá poznámka může obsahovat podpoznámky. Jednu poznámku lze přidat na více míst v hierarchii.",
|
"note_structure_description": "Poznámky lze uspořádat hierarchicky. Není třeba používat složky, protože každá poznámka může obsahovat podpoznámky. Jednu poznámku lze přidat na více míst v hierarchii.",
|
||||||
"attributes_title": "Poznámky k štítkům a vztahům",
|
"attributes_title": "Poznámky k štítkům a vazbám",
|
||||||
"attributes_description": "Využijte vztahy mezi poznámkami nebo přidejte štítky pro snadnou kategorizaci. Pomocí propagovaných atributů zadejte strukturované informace, které lze použít v tabulkách.",
|
"attributes_description": "Využijte vazby mezi poznámkami nebo přidejte štítky pro snadnou kategorizaci. Pomocí propagovaných atributů zadejte strukturované informace, které lze použít v různých tabulkách.",
|
||||||
"hoisting_title": "Pracovní prostředí a hoisting",
|
"hoisting_title": "Pracovní prostředí a hoisting",
|
||||||
"hoisting_description": "Snadno oddělte své osobní a pracovní poznámky tím, že je seskupíte do pracovního prostoru, který zaměří strom poznámek tak, aby zobrazoval pouze konkrétní sadu poznámek."
|
"hoisting_description": "Snadno oddělte své osobní a pracovní poznámky tím, že je seskupíte do pracovního prostoru, který zaměří strom poznámek tak, aby zobrazoval pouze konkrétní sadu poznámek."
|
||||||
},
|
},
|
||||||
|
|||||||
@ -19,7 +19,9 @@
|
|||||||
"note_structure_title": "Notizstruktur",
|
"note_structure_title": "Notizstruktur",
|
||||||
"attributes_title": "Notiz Labels und Beziehungen",
|
"attributes_title": "Notiz Labels und Beziehungen",
|
||||||
"note_structure_description": "Notizen lassen sich hierarchisch anordnen. Ordner sind nicht nötig, da jede Notiz Unternotizen enthalten kann. Eine einzelne Notiz kann an mehreren Stellen in der Hierarchie hinzugefügt werden.",
|
"note_structure_description": "Notizen lassen sich hierarchisch anordnen. Ordner sind nicht nötig, da jede Notiz Unternotizen enthalten kann. Eine einzelne Notiz kann an mehreren Stellen in der Hierarchie hinzugefügt werden.",
|
||||||
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird."
|
"hoisting_description": "Trennen Sie Ihre persönlichen und beruflichen Notizen ganz einfach, indem Sie sie in einem Arbeitsbereich gruppieren. Dadurch wird Ihre Notizstruktur so fokussiert, dass nur ein bestimmter Satz von Notizen angezeigt wird.",
|
||||||
|
"hoisting_title": "Arbeitsbereiche und Fokusansicht",
|
||||||
|
"attributes_description": "Nutzen Sie Verbindungen zwischen Notizen oder fügen Sie Labels hinzu, um die Kategorisierung zu erleichtern. Mit hervorgehobenen („promoted“) Attributen können Sie strukturierte Informationen erfassen, die sich direkt in Tabellen und Boards verwenden lassen."
|
||||||
},
|
},
|
||||||
"productivity_benefits": {
|
"productivity_benefits": {
|
||||||
"revisions_title": "Notizrevisionen",
|
"revisions_title": "Notizrevisionen",
|
||||||
@ -29,7 +31,12 @@
|
|||||||
"jump_to_title": "Schnellsuche und Kommandos",
|
"jump_to_title": "Schnellsuche und Kommandos",
|
||||||
"search_title": "Leistungsstarke Suche",
|
"search_title": "Leistungsstarke Suche",
|
||||||
"web_clipper_title": "Web clipper",
|
"web_clipper_title": "Web clipper",
|
||||||
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden."
|
"revisions_content": "Notizen werden regelmäßig im Hintergrund gespeichert und Revisionen können zur Überprüfung oder zum Rückgängigmachen versehentlicher Änderungen verwendet werden. Revisionen können auch bei Bedarf erstellt werden.",
|
||||||
|
"sync_content": "Verwenden Sie eine selbst gehostete oder Cloud-Instanz, um Ihre Notizen ganz einfach auf mehreren Geräten zu synchronisieren und über eine WebApp von Ihrem mobilen Gerät aus darauf zuzugreifen.",
|
||||||
|
"protected_notes_content": "Halten Sie vertrauliche Informationen sicher, indem Sie Notizen verschlüsseln und mit einem Passwort schützen.",
|
||||||
|
"jump_to_content": "Springen Sie schnell zu Notizen oder UI-Befehlen in der gesamten Hierarchie, indem Sie nach ihrem Titel suchen. Dank Fuzzy-Matching finden Sie auch Treffer bei Tippfehlern oder leicht abweichenden Schreibweisen.",
|
||||||
|
"search_content": "Oder durchsuchen Sie den Inhalt von Notizen und grenzen Sie die Suche ein, indem Sie nach übergeordneten Notizen oder der Hierarchieebene filtern.",
|
||||||
|
"web_clipper_content": "Webseiten oder Screenshots direkt in Trilium speichern – mit der Web Clipper Browser-Erweiterung."
|
||||||
},
|
},
|
||||||
"note_types": {
|
"note_types": {
|
||||||
"text_title": "Text Notizen",
|
"text_title": "Text Notizen",
|
||||||
@ -38,15 +45,38 @@
|
|||||||
"mermaid_title": "Mermaid Diagramm",
|
"mermaid_title": "Mermaid Diagramm",
|
||||||
"mindmap_title": "Mind Map",
|
"mindmap_title": "Mind Map",
|
||||||
"text_description": "Die Notizen werden mit einem visuellen Editor (WYSIWYG) bearbeitet, der Tabellen, Bilder, mathematische Ausdrücke und Code-Blöcke mit Syntaxhervorhebung unterstützt. Formatieren Sie den Text schnell mit einer Markdown-ähnlichen Syntax oder mit Slash-Befehlen.",
|
"text_description": "Die Notizen werden mit einem visuellen Editor (WYSIWYG) bearbeitet, der Tabellen, Bilder, mathematische Ausdrücke und Code-Blöcke mit Syntaxhervorhebung unterstützt. Formatieren Sie den Text schnell mit einer Markdown-ähnlichen Syntax oder mit Slash-Befehlen.",
|
||||||
"code_description": "Große Quellcode- oder Skriptdateien werden mit einem speziellen Editor bearbeitet, der Syntaxhervorhebung für viele Programmiersprachen und diverse Farbschemata bietet."
|
"code_description": "Große Quellcode- oder Skriptdateien werden mit einem speziellen Editor bearbeitet, der Syntaxhervorhebung für viele Programmiersprachen und diverse Farbschemata bietet.",
|
||||||
|
"title": "Verschiedene Darstellungsformen für Ihre Informationen",
|
||||||
|
"file_title": "Datei Notizen",
|
||||||
|
"file_description": "Betten Sie Multimedia-Dateien wie PDFs, Bilder und Videos mit einer Vorschau innerhalb der Anwendung ein.",
|
||||||
|
"canvas_description": "Ordnen Sie Formen, Bilder und Text auf einer unendlichen Leinwand an, indem Sie dieselbe Technologie verwenden, die auch hinter excalidraw.com steckt. Ideal für Diagramme, Skizzen und visuelle Planung.",
|
||||||
|
"mermaid_description": "Erstellen Sie Fluss-, Klassen-, Sequenz- sowie Gantt-Diagramme und vieles mehr mit der Mermaid-Syntax.",
|
||||||
|
"mindmap_description": "Strukturieren Sie Ihre Gedanken visuell oder nutzen Sie eine Brainstorming-Sitzung.",
|
||||||
|
"others_list": "und andere: <0>note map</0>, <1>relation map</1>, <2>saved searches</2>, <3>render note</3>, and <4>web views</4>."
|
||||||
},
|
},
|
||||||
"extensibility_benefits": {
|
"extensibility_benefits": {
|
||||||
"import_export_title": "Import/Export",
|
"import_export_title": "Import/Export",
|
||||||
"scripting_title": "Erweitertes Scripting",
|
"scripting_title": "Erweitertes Scripting",
|
||||||
"api_title": "REST API"
|
"api_title": "REST API",
|
||||||
|
"title": "Freigabe & Erweiterung",
|
||||||
|
"import_export_description": "Einfache Interaktion mit anderen Anwendungen mithilfe von Markdown, ENEX und OML Formaten.",
|
||||||
|
"share_title": "Notizen im Web teilen",
|
||||||
|
"share_description": "Wenn Sie über einen Server verfügen, können Sie diesen nutzen, um einen Teil Ihrer Notizen mit anderen zu teilen.",
|
||||||
|
"scripting_description": "Erstellen Sie Ihre eigenen Integrationen innerhalb von Trilium mit benutzerdefinierten Widgets oder serverseitiger Logik.",
|
||||||
|
"api_description": "Nutzen Sie die integrierte REST-API, um flexibel und automatisiert mit Trilium zu interagieren."
|
||||||
},
|
},
|
||||||
"collections": {
|
"collections": {
|
||||||
"calendar_title": "Kalender"
|
"calendar_title": "Kalender",
|
||||||
|
"title": "Sammlungen",
|
||||||
|
"calendar_description": "Organisieren Sie Ihre privaten oder beruflichen Termine mithilfe eines Kalenders, der ganztägige und mehrtägige Termine unterstützt. Verschaffen Sie sich mit der Wochen-, Monats- und Jahresansicht einen Überblick über Ihre Termine. Einfaches Hinzufügen oder Verschieben von Terminen.",
|
||||||
|
"table_title": "Tabelle",
|
||||||
|
"table_description": "Zeigen Sie Informationen zu Notizen in einer tabellarischen Ansicht an und bearbeiten Sie diese. Dabei stehen verschiedene Spaltentypen wie Text, Zahlen, Kontrollkästchen, Datum sowie Uhrzeit, Links und Farben zur Verfügung, auch Beziehungen werden unterstützt. Optional können Sie die Notizen innerhalb einer Baumhierarchie in der Tabelle anzeigen.",
|
||||||
|
"board_title": "Kanban-Board",
|
||||||
|
"board_description": "Organisieren Sie Aufgaben und Projektstatus in einem Kanban-Board und ändern Sie den Status ganz einfach per Drag & Drop.",
|
||||||
|
"geomap_title": "Geokarte",
|
||||||
|
"geomap_description": "Planen Sie Ihren Urlaub oder markieren Sie Ihre Sehenswürdigkeiten direkt auf einer geografischen Karte mit individuellen Markierungen. Zeigen Sie aufgezeichnete GPX-Tracks an, um Reiserouten zu verfolgen.",
|
||||||
|
"presentation_title": "Präsentation",
|
||||||
|
"presentation_description": "Organisieren Sie Informationen in Folien und präsentieren Sie diese im Vollbildmodus mit flüssigen Übergängen. Die Folien können als PDF gespeichert und einfach geteilt werden."
|
||||||
},
|
},
|
||||||
"download_helper_desktop_macos": {
|
"download_helper_desktop_macos": {
|
||||||
"quick_start": "Installieren mit Homebrew:",
|
"quick_start": "Installieren mit Homebrew:",
|
||||||
@ -69,7 +99,13 @@
|
|||||||
"download_nixpkgs": "nixpkgs",
|
"download_nixpkgs": "nixpkgs",
|
||||||
"download_zip": "Portable (.zip)",
|
"download_zip": "Portable (.zip)",
|
||||||
"download_flatpak": ".flatpak",
|
"download_flatpak": ".flatpak",
|
||||||
"download_rpm": ".rpm"
|
"download_rpm": ".rpm",
|
||||||
|
"title_x64": "Linux 64-bit",
|
||||||
|
"title_arm64": "Linux on ARM",
|
||||||
|
"description_x64": "Für die meisten Linux-Distributionen, kompatibel mit der x86_64-Architektur.",
|
||||||
|
"description_arm64": "Für ARM-basierte Linux-Distributionen, kompatibel mit der aarch64-Architektur.",
|
||||||
|
"quick_start": "Wählen Sie je nach Ihrer Distribution ein geeignetes Paketformat aus:",
|
||||||
|
"download_deb": ".deb"
|
||||||
},
|
},
|
||||||
"download_helper_server_linux": {
|
"download_helper_server_linux": {
|
||||||
"title": "Self-hosted auf Linux",
|
"title": "Self-hosted auf Linux",
|
||||||
@ -83,5 +119,82 @@
|
|||||||
"description": "Trilium Notes wird auf PikaPods gehostet, einem kostenpflichtigen Dienst für einfachen Zugriff und Verwaltung. Es besteht keine direkte Verbindung zum Trilium-Team.",
|
"description": "Trilium Notes wird auf PikaPods gehostet, einem kostenpflichtigen Dienst für einfachen Zugriff und Verwaltung. Es besteht keine direkte Verbindung zum Trilium-Team.",
|
||||||
"download_pikapod": "Auf PikaPods installieren",
|
"download_pikapod": "Auf PikaPods installieren",
|
||||||
"download_triliumcc": "Alternativ siehe trilium.cc"
|
"download_triliumcc": "Alternativ siehe trilium.cc"
|
||||||
|
},
|
||||||
|
"faq": {
|
||||||
|
"title": "Häufig gestellte Fragen",
|
||||||
|
"mobile_question": "Gibt es eine mobile Applikation?",
|
||||||
|
"mobile_answer": "Derzeit gibt es keine offizielle mobile Anwendung. Wenn Sie jedoch über eine Serverinstanz verfügen, können Sie über einen Webbrowser darauf zugreifen und sie sogar als PWA installieren. Für Android gibt es eine inoffizielle Anwendung namens TriliumDroid, die sogar offline funktioniert (genau wie ein Desktop-Client).",
|
||||||
|
"database_question": "Wo werden die Daten gespeichert?",
|
||||||
|
"database_answer": "Alle Ihre Notizen werden in einer SQLite-Datenbank in einem Anwendungsordner gespeichert. Der Grund, warum Trilium eine Datenbank anstelle von einfachen Textdateien verwendet, liegt sowohl in der Leistung als auch darin, dass einige Funktionen, wie z. B. Klone (gleiche Notiz an mehreren Stellen im Baum), viel schwieriger zu implementieren wären. Um den Anwendungsordner zu finden, gehen Sie einfach zum Fenster „Über“.",
|
||||||
|
"server_question": "Benötige ich einen Server um Trilium zu nutzen?",
|
||||||
|
"server_answer": "Nein, der Server ermöglicht den Zugriff über einen Webbrowser und verwaltet die Synchronisierung, wenn Sie mehrere Geräte haben. Um loszulegen, reicht es aus, die Desktop-Anwendung herunterzuladen und zu verwenden.",
|
||||||
|
"scaling_question": "Wie gut skaliert die Anwendung bei einer großen Anzahl von Notizen?",
|
||||||
|
"scaling_answer": "Je nach Nutzung sollte die Anwendung min. 100.000 Notizen problemlos verarbeiten können. Beachten Sie, dass der Synchronisierungsvorgang manchmal fehlschlagen kann, wenn viele große Dateien (1 GB pro Datei) hochgeladen werden, da Trilium eher als Wissensdatenbank-Anwendung und nicht als Dateispeicher (wie beispielsweise NextCloud) konzipiert ist.",
|
||||||
|
"network_share_question": "Kann ich meine Datenbank über ein Netzlaufwerk freigeben?",
|
||||||
|
"network_share_answer": "Nein, es ist im Allgemeinen keine gute Idee, eine SQLite-Datenbank über ein Netzlaufwerk freizugeben. Auch wenn dies manchmal funktionieren mag, besteht die Gefahr, dass die Datenbank aufgrund unvollständiger Dateisperren über ein Netzwerk beschädigt wird.",
|
||||||
|
"security_question": "Wie werden meine Daten geschützt?",
|
||||||
|
"security_answer": "Standardmäßig sind Notizen nicht verschlüsselt und können direkt aus der Datenbank gelesen werden. Sobald eine Notiz als verschlüsselt markiert ist, wird diese mit AES-128-CBC verschlüsselt."
|
||||||
|
},
|
||||||
|
"final_cta": {
|
||||||
|
"title": "Sind Sie bereit, um mit Trilium Notes zu starten?",
|
||||||
|
"description": "Baue dein persönliches Wissensarchiv mit leistungsstarken Funktionen und vollständigem Datenschutz auf.",
|
||||||
|
"get_started": "Loslegen"
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"link_learn_more": "Mehr erfahren..."
|
||||||
|
},
|
||||||
|
"download_now": {
|
||||||
|
"text": "Herunterladen ",
|
||||||
|
"platform_big": "v{{version}} für {{platform}}",
|
||||||
|
"platform_small": "für {{platform}}",
|
||||||
|
"linux_big": "v{{version}} für Linux",
|
||||||
|
"linux_small": "für Linux",
|
||||||
|
"more_platforms": "Weitere Plattformen & Server-Einrichtung"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"get-started": "Loslegen",
|
||||||
|
"documentation": "Dokumentation",
|
||||||
|
"support-us": "Unterstützt uns"
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"copyright_and_the": " und die ",
|
||||||
|
"copyright_community": "Community"
|
||||||
|
},
|
||||||
|
"social_buttons": {
|
||||||
|
"github": "GitHub",
|
||||||
|
"github_discussions": "GitHub Discussions",
|
||||||
|
"matrix": "Matrix",
|
||||||
|
"reddit": "Reddit"
|
||||||
|
},
|
||||||
|
"support_us": {
|
||||||
|
"title": "Unterstütze uns",
|
||||||
|
"financial_donations_title": "Geldspenden",
|
||||||
|
"financial_donations_description": "Trilium wurde mit <Link>Hunderten von Arbeitsstunden</Link> entwickelt und wird mit diesem Aufwand auch gewartet. Ihre Unterstützung sorgt dafür, dass es Open Source bleibt, verbessert die Funktionen und deckt Kosten wie das Hosting.",
|
||||||
|
"financial_donations_cta": "Bitte unterstützen Sie den Hauptentwickler (<Link>eliandoran</Link>) der Anwendung über:",
|
||||||
|
"github_sponsors": "GitHub Sponsoren",
|
||||||
|
"paypal": "PayPal",
|
||||||
|
"buy_me_a_coffee": "Buy Me A Coffee"
|
||||||
|
},
|
||||||
|
"contribute": {
|
||||||
|
"title": "Weitere Möglichkeiten zum Mitwirken",
|
||||||
|
"way_translate": "Übersetzen Sie die Anwendung über <Link>Weblate</Link> in Ihre Muttersprache.",
|
||||||
|
"way_community": "Interagieren Sie mit der Community auf <Discussions>GitHub Discussions</Discussions> oder auf <Matrix>Matrix</Matrix>.",
|
||||||
|
"way_reports": "Fehlfunktionen über <Link>GitHub-Issues</Link> melden.",
|
||||||
|
"way_document": "Verbessern Sie die Dokumentation, indem Sie uns auf Lücken hinweisen oder durch eigene Beiträge wie Anleitungen, FAQs oder Tutorials unterstützen.",
|
||||||
|
"way_market": "Weitersagen: Teilen Sie Trilium Notes mit Freunden, in Blogs und sozialen Medien."
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"title": "404: Not Found",
|
||||||
|
"description": "Die gesuchte Seite konnte nicht gefunden werden. Möglicherweise wurde sie gelöscht oder die URL ist falsch."
|
||||||
|
},
|
||||||
|
"download_helper_desktop_windows": {
|
||||||
|
"title_x64": "Windows 64-bit",
|
||||||
|
"title_arm64": "Windows on ARM",
|
||||||
|
"description_x64": "Kompatibel mit Intel- oder AMD-Geräten unter Windows 10 und 11.",
|
||||||
|
"description_arm64": "Kompatibel mit ARM-Geräten (z. B. mit Qualcomm Snapdragon).",
|
||||||
|
"quick_start": "Installation über Winget:",
|
||||||
|
"download_exe": "Download Installer (.exe)",
|
||||||
|
"download_zip": "Portable (.zip)",
|
||||||
|
"download_scoop": "Scoop"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,13 @@
|
|||||||
"sync_title": "동기화",
|
"sync_title": "동기화",
|
||||||
"sync_content": "자체 호스팅 또는 클라우드 인스턴스를 이용하여 여러 기기 사이에서 노트를 쉽게 동기화하고 PWA를 통해 모바일 폰에서 접근할 수 있습니다.",
|
"sync_content": "자체 호스팅 또는 클라우드 인스턴스를 이용하여 여러 기기 사이에서 노트를 쉽게 동기화하고 PWA를 통해 모바일 폰에서 접근할 수 있습니다.",
|
||||||
"protected_notes_title": "보호된 노트",
|
"protected_notes_title": "보호된 노트",
|
||||||
"protected_notes_content": "노트를 암호화하고 비밀번호로 보호되는 세션 뒤에 잠궈 민감한 개인 정보를 보호하세요."
|
"protected_notes_content": "노트를 암호화하고 비밀번호로 보호되는 세션 뒤에 잠궈 민감한 개인 정보를 보호하세요.",
|
||||||
|
"jump_to_title": "빠른 검색 및 명령어",
|
||||||
|
"jump_to_content": "제목을 검색하고 오타나 약간의 차이를 설명하기 위해 퍼지 매칭을 통해 계층 전반에 걸쳐 노트나 UI 명령으로 빠르게 이동하세요.",
|
||||||
|
"search_title": "상세 검색",
|
||||||
|
"search_content": "또는 노트 내부에서 문자를 검색하거나 부모 노트 또는 단계별로 필터링 하는 등 검색 범위를 조정하세요.",
|
||||||
|
"web_clipper_title": "웹 클리퍼",
|
||||||
|
"web_clipper_content": "웹 클리퍼 확장 프로그램을 사용하여 웹 페이지(또는 스크린샷)를 Trilium으로 가져와 문서에 사용하세요."
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"get-started": "시작하기",
|
"get-started": "시작하기",
|
||||||
|
|||||||
@ -131,7 +131,7 @@ To do so, create a shared text note and apply the `shareIndex` label. When viewe
|
|||||||
|
|
||||||
## Attribute reference
|
## Attribute reference
|
||||||
|
|
||||||
<table class="ck-table-resized"><colgroup><col style="width:18.38%;"><col style="width:81.62%;"></colgroup><thead><tr><th>Attribute</th><th>Description</th></tr></thead><tbody><tr><td><code>#shareHiddenFromTree</code></td><td>this note is hidden from left navigation tree, but still accessible with its URL</td></tr><tr><td><code>#shareExternalLink</code></td><td>note will act as a link to an external website in the share tree</td></tr><tr><td><code>#shareAlias</code></td><td>define an alias using which the note will be available under <code>https://your_trilium_host/share/[your_alias]</code></td></tr><tr><td><code>#shareOmitDefaultCss</code></td><td>default share page CSS will be omitted. Use when you make extensive styling changes.</td></tr><tr><td><code>#shareRoot</code></td><td>marks note which is served on /share root.</td></tr><tr><td><code>#shareDescription</code></td><td>define text to be added to the HTML meta tag for description</td></tr><tr><td><code>#shareRaw</code></td><td>Note will be served in its raw format, without HTML wrapper. See also <a class="reference-link" href="Sharing/Serving%20directly%20the%20content%20o.md">Serving directly the content of a note</a> for an alternative method without setting an attribute.</td></tr><tr><td><code>#shareDisallowRobotIndexing</code></td><td><p>Indicates to web crawlers that the page should not be indexed of this note by:</p><ul><li data-list-item-id="e6baa9f60bf59d085fd31aa2cce07a0e7">Setting the <code>X-Robots-Tag: noindex</code> HTTP header.</li><li data-list-item-id="ec0d067db136ef9794e4f1033405880b7">Setting the <code>noindex, follow</code> meta tag.</li></ul></td></tr><tr><td><code>#shareCredentials</code></td><td>require credentials to access this shared note. Value is expected to be in format <code>username:password</code>. Don't forget to make this inheritable to apply to child-notes/images.</td></tr><tr><td><code>#shareIndex</code></td><td>Note with this label will list all roots of shared notes.</td></tr><tr><td><code>#shareHtmlLocation</code></td><td>defines where custom HTML injected via <code>~shareHtml</code> relation should be placed. Applied to the HTML snippet note itself. Format: <code>location:position</code> where location is <code>head</code>, <code>body</code>, or <code>content</code> and position is <code>start</code> or <code>end</code>. Defaults to <code>content:end</code>.</td></tr></tbody></table>
|
<table class="ck-table-resized"><colgroup><col style="width:18.38%;"><col style="width:81.62%;"></colgroup><thead><tr><th>Attribute</th><th>Description</th></tr></thead><tbody><tr><td><code>#shareHiddenFromTree</code></td><td>this note is hidden from left navigation tree, but still accessible with its URL</td></tr><tr><td><code>#shareTemplateNoPrevNext</code></td><td>hide bottom page navigation prev and next page.</td></tr><tr><td><code>#shareTemplateNoLeftPanel</code></td><td>hide left panel fully.</td></tr><tr><td><code>#shareExclude</code></td><td>this note will be excluded from share, not accessible via direct URL (implemented to hide scripts from share)</td></tr><tr><td><code>#shareContentAccess</code></td><td>method for attachments authorization in case when note protected with login and password (#shareCredentials). Could be cookie (the cookie will be provided when page loads) / query (every url will be updated with token) / basic (only basic header authorization)). By default for browser used cookie.</td></tr><tr><td><code>#shareAccessTokenTimeout</code></td><td>token expiration timeout in seconds, by default 10 minutes. While token not expired user could download attachment, after that he will get message `Access is expired. Return back and update the page.`</td></tr><tr><td><code>#shareExternalLink</code></td><td>note will act as a link to an external website in the share tree</td></tr><tr><td><code>#shareAlias</code></td><td>define an alias using which the note will be available under <code>https://your_trilium_host/share/[your_alias]</code></td></tr><tr><td><code>#shareOmitDefaultCss</code></td><td>default share page CSS will be omitted. Use when you make extensive styling changes.</td></tr><tr><td><code>#shareRoot</code></td><td>marks note which is served on /share root.</td></tr><tr><td><code>#shareDescription</code></td><td>define text to be added to the HTML meta tag for description</td></tr><tr><td><code>#shareRaw</code></td><td>Note will be served in its raw format, without HTML wrapper. See also <a class="reference-link" href="Sharing/Serving%20directly%20the%20content%20o.md">Serving directly the content of a note</a> for an alternative method without setting an attribute.</td></tr><tr><td><code>#shareDisallowRobotIndexing</code></td><td><p>Indicates to web crawlers that the page should not be indexed of this note by:</p><ul><li data-list-item-id="e6baa9f60bf59d085fd31aa2cce07a0e7">Setting the <code>X-Robots-Tag: noindex</code> HTTP header.</li><li data-list-item-id="ec0d067db136ef9794e4f1033405880b7">Setting the <code>noindex, follow</code> meta tag.</li></ul></td></tr><tr><td><code>#shareCredentials</code></td><td>require credentials to access this shared note. Value is expected to be in format <code>username:password</code>. Don't forget to make this inheritable to apply to child-notes/images.</td></tr><tr><td><code>#shareIndex</code></td><td>Note with this label will list all roots of shared notes.</td></tr><tr><td><code>#shareHtmlLocation</code></td><td>defines where custom HTML injected via <code>~shareHtml</code> relation should be placed. Applied to the HTML snippet note itself. Format: <code>location:position</code> where location is <code>head</code>, <code>body</code>, or <code>content</code> and position is <code>start</code> or <code>end</code>. Defaults to <code>content:end</code>.</td></tr></tbody></table>
|
||||||
|
|
||||||
### Customizing logo
|
### Customizing logo
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "14.1.1",
|
"http-server": "14.1.1",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"stylelint": "16.26.0",
|
"stylelint": "16.26.1",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "14.1.1",
|
"http-server": "14.1.1",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"stylelint": "16.26.0",
|
"stylelint": "16.26.1",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "14.1.1",
|
"http-server": "14.1.1",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"stylelint": "16.26.0",
|
"stylelint": "16.26.1",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "14.1.1",
|
"http-server": "14.1.1",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"stylelint": "16.26.0",
|
"stylelint": "16.26.1",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "14.1.1",
|
"http-server": "14.1.1",
|
||||||
"lint-staged": "16.2.7",
|
"lint-staged": "16.2.7",
|
||||||
"stylelint": "16.26.0",
|
"stylelint": "16.26.1",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "10.9.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
|
|||||||
@ -50,7 +50,7 @@
|
|||||||
let openGraphImage = subRoot.note.getLabelValue("shareOpenGraphImage");
|
let openGraphImage = subRoot.note.getLabelValue("shareOpenGraphImage");
|
||||||
// Relation takes priority and requires some altering
|
// Relation takes priority and requires some altering
|
||||||
if (subRoot.note.hasRelation("shareOpenGraphImage")) {
|
if (subRoot.note.hasRelation("shareOpenGraphImage")) {
|
||||||
openGraphImage = `api/images/${subRoot.note.getRelation("shareOpenGraphImage").value}/image.png`;
|
openGraphImage = `api/images/${subRoot.note.getRelation("shareOpenGraphImage").value}/image.png${addContentAccessQuery()}`;
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
<title><%= pageTitle %></title>
|
<title><%= pageTitle %></title>
|
||||||
@ -109,40 +109,43 @@ content = content.replaceAll(headingRe, (...match) => {
|
|||||||
<button aria-label="Show Mobile Menu" id="show-menu-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"></path></svg></button>
|
<button aria-label="Show Mobile Menu" id="show-menu-button"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"></path></svg></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="split-pane">
|
<div id="split-pane">
|
||||||
<div id="left-pane">
|
<% if (!note.isLabelTruthy("shareTemplateNoLeftPanel")) { %>
|
||||||
<div id="navigation">
|
<div id="left-pane">
|
||||||
<div id="site-header">
|
<div id="navigation">
|
||||||
<a href="<%= shareRootLink %>">
|
<div id="site-header">
|
||||||
<img src="<%= logoUrl %>" width="<%= logoWidth %>" height="<%= logoHeight %>" alt="Logo" />
|
<a href="<%= shareRootLink %>">
|
||||||
<%= subRoot.note.title %>
|
<img src="<%= logoUrl %>" width="<%= logoWidth %>" height="<%= logoHeight %>" alt="Logo" />
|
||||||
</a>
|
<%= subRoot.note.title %>
|
||||||
<div class="theme-selection">
|
</a>
|
||||||
<span id="sitetheme"><%= t("share_theme.site-theme") %></span>
|
<div class="theme-selection">
|
||||||
<label class="switch">
|
<span id="sitetheme"><%= t("share_theme.site-theme") %></span>
|
||||||
<input type="checkbox" aria-labelledby="sitetheme">
|
<label class="switch">
|
||||||
<span class="slider"></span>
|
<input type="checkbox" aria-labelledby="sitetheme">
|
||||||
<svg class="dark-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20.742 13.045a8.088 8.088 0 0 1-2.077.271c-2.135 0-4.14-.83-5.646-2.336a8.025 8.025 0 0 1-2.064-7.723A1 1 0 0 0 9.73 2.034a10.014 10.014 0 0 0-4.489 2.582c-3.898 3.898-3.898 10.243 0 14.143a9.937 9.937 0 0 0 7.072 2.93 9.93 9.93 0 0 0 7.07-2.929 10.007 10.007 0 0 0 2.583-4.491 1.001 1.001 0 0 0-1.224-1.224zm-2.772 4.301a7.947 7.947 0 0 1-5.656 2.343 7.953 7.953 0 0 1-5.658-2.344c-3.118-3.119-3.118-8.195 0-11.314a7.923 7.923 0 0 1 2.06-1.483 10.027 10.027 0 0 0 2.89 7.848 9.972 9.972 0 0 0 7.848 2.891 8.036 8.036 0 0 1-1.484 2.059z"></path></svg>
|
<span class="slider"></span>
|
||||||
<svg class="light-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M6.993 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007S14.761 6.993 12 6.993 6.993 9.239 6.993 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19h2v3h-2zm0-17h2v3h-2zm-9 9h3v2h-3zm17 0h3v2h-3zM4.219 18.363l2.12-2.122 1.415 1.414-2.12 2.122zM16.24 6.344l2.122-2.122 1.414 1.414-2.122 2.122zM6.342 7.759 4.22 5.637l1.415-1.414 2.12 2.122zm13.434 10.605-1.414 1.414-2.122-2.122 1.414-1.414z"></path></svg>
|
<svg class="dark-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20.742 13.045a8.088 8.088 0 0 1-2.077.271c-2.135 0-4.14-.83-5.646-2.336a8.025 8.025 0 0 1-2.064-7.723A1 1 0 0 0 9.73 2.034a10.014 10.014 0 0 0-4.489 2.582c-3.898 3.898-3.898 10.243 0 14.143a9.937 9.937 0 0 0 7.072 2.93 9.93 9.93 0 0 0 7.07-2.929 10.007 10.007 0 0 0 2.583-4.491 1.001 1.001 0 0 0-1.224-1.224zm-2.772 4.301a7.947 7.947 0 0 1-5.656 2.343 7.953 7.953 0 0 1-5.658-2.344c-3.118-3.119-3.118-8.195 0-11.314a7.923 7.923 0 0 1 2.06-1.483 10.027 10.027 0 0 0 2.89 7.848 9.972 9.972 0 0 0 7.848 2.891 8.036 8.036 0 0 1-1.484 2.059z"></path></svg>
|
||||||
</label>
|
<svg class="light-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M6.993 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007S14.761 6.993 12 6.993 6.993 9.239 6.993 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19h2v3h-2zm0-17h2v3h-2zm-9 9h3v2h-3zm17 0h3v2h-3zM4.219 18.363l2.12-2.122 1.415 1.414-2.12 2.122zM16.24 6.344l2.122-2.122 1.414 1.414-2.122 2.122zM6.342 7.759 4.22 5.637l1.415-1.414 2.12 2.122zm13.434 10.605-1.414 1.414-2.122-2.122 1.414-1.414z"></path></svg>
|
||||||
<script>
|
</label>
|
||||||
const el = document.querySelector(".theme-selection input");
|
<script>
|
||||||
el.checked = (glob.theme === "dark");
|
const el = document.querySelector(".theme-selection input");
|
||||||
</script>
|
el.checked = (glob.theme === "dark");
|
||||||
</div>
|
</script>
|
||||||
<% if (hasTree) { %>
|
|
||||||
<div class="search-item">
|
|
||||||
<svg class="search-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M10 18a7.952 7.952 0 0 0 4.897-1.688l4.396 4.396 1.414-1.414-4.396-4.396A7.952 7.952 0 0 0 18 10c0-4.411-3.589-8-8-8s-8 3.589-8 8 3.589 8 8 8zm0-14c3.309 0 6 2.691 6 6s-2.691 6-6 6-6-2.691-6-6 2.691-6 6-6z"></path></svg>
|
|
||||||
<input type="text" class="search-input" placeholder="<%= t("share_theme.search_placeholder") %>">
|
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% if (hasTree) { %>
|
||||||
|
<div class="search-item">
|
||||||
|
<svg class="search-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M10 18a7.952 7.952 0 0 0 4.897-1.688l4.396 4.396 1.414-1.414-4.396-4.396A7.952 7.952 0 0 0 18 10c0-4.411-3.589-8-8-8s-8 3.589-8 8 3.589 8 8 8zm0-14c3.309 0 6 2.691 6 6s-2.691 6-6 6-6-2.691-6-6 2.691-6 6-6z"></path></svg>
|
||||||
|
<input type="text" class="search-input" placeholder="<%= t("share_theme.search_placeholder") %>">
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% if (hasTree) { %>
|
||||||
|
<nav id="menu">
|
||||||
|
<%- include("tree_item", {note: subRoot.note, activeNote: note, subRoot: subRoot, ancestors}) %>
|
||||||
|
</nav>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
<% if (hasTree) { %>
|
|
||||||
<nav id="menu">
|
|
||||||
<%- include("tree_item", {note: subRoot.note, activeNote: note, subRoot: subRoot, ancestors}) %>
|
|
||||||
</nav>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% } %>
|
||||||
|
|
||||||
<div id="right-pane">
|
<div id="right-pane">
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<div id="content" class="type-<%= note.type %><% if (note.type === "text") { %> ck-content<% } %><% if (isEmpty) { %> no-content<% } %>">
|
<div id="content" class="type-<%= note.type %><% if (note.type === "text") { %> ck-content<% } %><% if (isEmpty) { %> no-content<% } %>">
|
||||||
@ -152,7 +155,9 @@ content = content.replaceAll(headingRe, (...match) => {
|
|||||||
<p>This note has no content.</p>
|
<p>This note has no content.</p>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<%
|
<%
|
||||||
content = content.replace(/<img /g, `<img alt="${t("share_theme.image_alt")}" loading="lazy" `);
|
content = content
|
||||||
|
.replace(/<img /g, `<img alt="${t("share_theme.image_alt")}" loading="lazy" `)
|
||||||
|
.replace(/src="(api\/[^"]+)"/g, (m, url) => `src="${url}${addContentAccessQuery(url.includes('?'))}"`);
|
||||||
%>
|
%>
|
||||||
<%- content %>
|
<%- content %>
|
||||||
<% } %>
|
<% } %>
|
||||||
@ -189,7 +194,7 @@ content = content.replaceAll(headingRe, (...match) => {
|
|||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (hasTree) { %>
|
<% if (hasTree && !note.isLabelTruthy("shareTemplateNoPrevNext")) { %>
|
||||||
<%- include("prev_next", { note: note, subRoot: subRoot }) %>
|
<%- include("prev_next", { note: note, subRoot: subRoot }) %>
|
||||||
<% } %>
|
<% } %>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
110
pnpm-lock.yaml
generated
110
pnpm-lock.yaml
generated
@ -369,8 +369,8 @@ importers:
|
|||||||
specifier: 2.1.3
|
specifier: 2.1.3
|
||||||
version: 2.1.3(electron@38.7.2)
|
version: 2.1.3(electron@38.7.2)
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: 12.4.6
|
specifier: 12.5.0
|
||||||
version: 12.4.6
|
version: 12.5.0
|
||||||
electron-debug:
|
electron-debug:
|
||||||
specifier: 4.1.0
|
specifier: 4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
@ -433,8 +433,8 @@ importers:
|
|||||||
apps/dump-db:
|
apps/dump-db:
|
||||||
dependencies:
|
dependencies:
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: 12.4.6
|
specifier: 12.5.0
|
||||||
version: 12.4.6
|
version: 12.5.0
|
||||||
mime-types:
|
mime-types:
|
||||||
specifier: 3.0.2
|
specifier: 3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
@ -464,8 +464,8 @@ importers:
|
|||||||
specifier: 7.0.1
|
specifier: 7.0.1
|
||||||
version: 7.0.1
|
version: 7.0.1
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: 12.4.6
|
specifier: 12.5.0
|
||||||
version: 12.4.6
|
version: 12.5.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@triliumnext/client':
|
'@triliumnext/client':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@ -489,8 +489,8 @@ importers:
|
|||||||
apps/server:
|
apps/server:
|
||||||
dependencies:
|
dependencies:
|
||||||
better-sqlite3:
|
better-sqlite3:
|
||||||
specifier: 12.4.6
|
specifier: 12.5.0
|
||||||
version: 12.4.6
|
version: 12.5.0
|
||||||
html-to-text:
|
html-to-text:
|
||||||
specifier: 9.0.5
|
specifier: 9.0.5
|
||||||
version: 9.0.5
|
version: 9.0.5
|
||||||
@ -915,11 +915,11 @@ importers:
|
|||||||
specifier: 16.2.7
|
specifier: 16.2.7
|
||||||
version: 16.2.7
|
version: 16.2.7
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: 16.26.0
|
specifier: 16.26.1
|
||||||
version: 16.26.0(typescript@5.9.3)
|
version: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-ckeditor5:
|
stylelint-config-ckeditor5:
|
||||||
specifier: '>=9.1.0'
|
specifier: '>=9.1.0'
|
||||||
version: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
version: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: 10.9.2
|
specifier: 10.9.2
|
||||||
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
||||||
@ -975,11 +975,11 @@ importers:
|
|||||||
specifier: 16.2.7
|
specifier: 16.2.7
|
||||||
version: 16.2.7
|
version: 16.2.7
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: 16.26.0
|
specifier: 16.26.1
|
||||||
version: 16.26.0(typescript@5.9.3)
|
version: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-ckeditor5:
|
stylelint-config-ckeditor5:
|
||||||
specifier: '>=9.1.0'
|
specifier: '>=9.1.0'
|
||||||
version: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
version: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: 10.9.2
|
specifier: 10.9.2
|
||||||
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
||||||
@ -1035,11 +1035,11 @@ importers:
|
|||||||
specifier: 16.2.7
|
specifier: 16.2.7
|
||||||
version: 16.2.7
|
version: 16.2.7
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: 16.26.0
|
specifier: 16.26.1
|
||||||
version: 16.26.0(typescript@5.9.3)
|
version: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-ckeditor5:
|
stylelint-config-ckeditor5:
|
||||||
specifier: '>=9.1.0'
|
specifier: '>=9.1.0'
|
||||||
version: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
version: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: 10.9.2
|
specifier: 10.9.2
|
||||||
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
||||||
@ -1102,11 +1102,11 @@ importers:
|
|||||||
specifier: 16.2.7
|
specifier: 16.2.7
|
||||||
version: 16.2.7
|
version: 16.2.7
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: 16.26.0
|
specifier: 16.26.1
|
||||||
version: 16.26.0(typescript@5.9.3)
|
version: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-ckeditor5:
|
stylelint-config-ckeditor5:
|
||||||
specifier: '>=9.1.0'
|
specifier: '>=9.1.0'
|
||||||
version: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
version: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: 10.9.2
|
specifier: 10.9.2
|
||||||
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
||||||
@ -1169,11 +1169,11 @@ importers:
|
|||||||
specifier: 16.2.7
|
specifier: 16.2.7
|
||||||
version: 16.2.7
|
version: 16.2.7
|
||||||
stylelint:
|
stylelint:
|
||||||
specifier: 16.26.0
|
specifier: 16.26.1
|
||||||
version: 16.26.0(typescript@5.9.3)
|
version: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-ckeditor5:
|
stylelint-config-ckeditor5:
|
||||||
specifier: '>=9.1.0'
|
specifier: '>=9.1.0'
|
||||||
version: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
version: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: 10.9.2
|
specifier: 10.9.2
|
||||||
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
version: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.9.3)
|
||||||
@ -2151,6 +2151,10 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@csstools/css-tokenizer': ^3.0.4
|
'@csstools/css-tokenizer': ^3.0.4
|
||||||
|
|
||||||
|
'@csstools/css-syntax-patches-for-csstree@1.0.19':
|
||||||
|
resolution: {integrity: sha512-QW5/SM2ARltEhoKcmRI1LoLf3/C7dHGswwCnfLcoMgqurBT4f8GvwXMgAbK/FwcxthmJRK5MGTtddj0yQn0J9g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@csstools/css-tokenizer@3.0.4':
|
'@csstools/css-tokenizer@3.0.4':
|
||||||
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
|
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@ -6367,8 +6371,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
ajv: 4.11.8 - 8
|
ajv: 4.11.8 - 8
|
||||||
|
|
||||||
better-sqlite3@12.4.6:
|
better-sqlite3@12.5.0:
|
||||||
resolution: {integrity: sha512-gaYt9yqTbQ1iOxLpJA8FPR5PiaHP+jlg8I5EX0Rs2KFwNzhBsF40KzMZS5FwelY7RG0wzaucWdqSAJM3uNCPCg==}
|
resolution: {integrity: sha512-WwCZ/5Diz7rsF29o27o0Gcc1Du+l7Zsv7SYtVPG0X3G/uUI1LqdxrQI7c9Hs2FWpqXXERjW9hp6g3/tH7DlVKg==}
|
||||||
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x}
|
engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x}
|
||||||
|
|
||||||
bezier-easing@2.1.0:
|
bezier-easing@2.1.0:
|
||||||
@ -13615,8 +13619,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
stylelint: '>=16.0.0'
|
stylelint: '>=16.0.0'
|
||||||
|
|
||||||
stylelint@16.26.0:
|
stylelint@16.26.1:
|
||||||
resolution: {integrity: sha512-Y/3AVBefrkqqapVYH3LBF5TSDZ1kw+0XpdKN2KchfuhMK6lQ85S4XOG4lIZLcrcS4PWBmvcY6eS2kCQFz0jukQ==}
|
resolution: {integrity: sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==}
|
||||||
engines: {node: '>=18.12.0'}
|
engines: {node: '>=18.12.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
@ -15778,8 +15782,6 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-core': 47.2.0
|
'@ckeditor/ckeditor5-core': 47.2.0
|
||||||
'@ckeditor/ckeditor5-utils': 47.2.0
|
'@ckeditor/ckeditor5-utils': 47.2.0
|
||||||
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
'@ckeditor/ckeditor5-code-block@47.2.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)':
|
'@ckeditor/ckeditor5-code-block@47.2.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -16454,8 +16456,8 @@ snapshots:
|
|||||||
process: 0.11.10
|
process: 0.11.10
|
||||||
raw-loader: 4.0.2(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
raw-loader: 4.0.2(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
||||||
style-loader: 2.0.0(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
style-loader: 2.0.0(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
||||||
stylelint: 16.26.0(typescript@5.0.4)
|
stylelint: 16.26.1(typescript@5.0.4)
|
||||||
stylelint-config-ckeditor5: 2.0.1(stylelint@16.26.0(typescript@5.9.3))
|
stylelint-config-ckeditor5: 2.0.1(stylelint@16.26.1(typescript@5.9.3))
|
||||||
terser-webpack-plugin: 5.3.14(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
terser-webpack-plugin: 5.3.14(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
||||||
ts-loader: 9.5.4(typescript@5.0.4)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
ts-loader: 9.5.4(typescript@5.0.4)(webpack@5.101.3(@swc/core@1.11.29(@swc/helpers@0.5.17))(esbuild@0.27.0))
|
||||||
ts-node: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.0.4)
|
ts-node: 10.9.2(@swc/core@1.11.29(@swc/helpers@0.5.17))(@types/node@24.10.1)(typescript@5.0.4)
|
||||||
@ -16550,8 +16552,6 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-ui': 47.2.0
|
'@ckeditor/ckeditor5-ui': 47.2.0
|
||||||
'@ckeditor/ckeditor5-utils': 47.2.0
|
'@ckeditor/ckeditor5-utils': 47.2.0
|
||||||
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
ckeditor5: 47.2.0(patch_hash=8331a09d41443b39ea1c784daaccfeb0da4f9065ed556e7de92e9c77edd9eb41)
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
|
|
||||||
'@ckeditor/ckeditor5-restricted-editing@47.2.0':
|
'@ckeditor/ckeditor5-restricted-editing@47.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -16749,6 +16749,8 @@ snapshots:
|
|||||||
'@ckeditor/ckeditor5-icons': 47.2.0
|
'@ckeditor/ckeditor5-icons': 47.2.0
|
||||||
'@ckeditor/ckeditor5-ui': 47.2.0
|
'@ckeditor/ckeditor5-ui': 47.2.0
|
||||||
'@ckeditor/ckeditor5-utils': 47.2.0
|
'@ckeditor/ckeditor5-utils': 47.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@ckeditor/ckeditor5-upload@47.2.0':
|
'@ckeditor/ckeditor5-upload@47.2.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -16981,6 +16983,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-tokenizer': 3.0.4
|
'@csstools/css-tokenizer': 3.0.4
|
||||||
|
|
||||||
|
'@csstools/css-syntax-patches-for-csstree@1.0.19': {}
|
||||||
|
|
||||||
'@csstools/css-tokenizer@3.0.4': {}
|
'@csstools/css-tokenizer@3.0.4': {}
|
||||||
|
|
||||||
'@csstools/media-query-list-parser@3.0.1(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
|
'@csstools/media-query-list-parser@3.0.1(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
|
||||||
@ -20241,7 +20245,7 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@stylistic/stylelint-plugin@3.1.3(stylelint@16.26.0(typescript@5.9.3))':
|
'@stylistic/stylelint-plugin@3.1.3(stylelint@16.26.1(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
||||||
'@csstools/css-tokenizer': 3.0.4
|
'@csstools/css-tokenizer': 3.0.4
|
||||||
@ -20251,7 +20255,7 @@ snapshots:
|
|||||||
postcss-selector-parser: 6.1.2
|
postcss-selector-parser: 6.1.2
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
style-search: 0.1.0
|
style-search: 0.1.0
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
|
|
||||||
'@swc/core-darwin-arm64@1.11.29':
|
'@swc/core-darwin-arm64@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
@ -21874,7 +21878,7 @@ snapshots:
|
|||||||
jsonpointer: 5.0.1
|
jsonpointer: 5.0.1
|
||||||
leven: 3.1.0
|
leven: 3.1.0
|
||||||
|
|
||||||
better-sqlite3@12.4.6:
|
better-sqlite3@12.5.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bindings: 1.5.0
|
bindings: 1.5.0
|
||||||
prebuild-install: 7.1.3
|
prebuild-install: 7.1.3
|
||||||
@ -30767,33 +30771,34 @@ snapshots:
|
|||||||
postcss: 8.5.6
|
postcss: 8.5.6
|
||||||
postcss-selector-parser: 7.1.0
|
postcss-selector-parser: 7.1.0
|
||||||
|
|
||||||
stylelint-config-ckeditor5@13.0.0(stylelint@16.26.0(typescript@5.9.3)):
|
stylelint-config-ckeditor5@13.0.0(stylelint@16.26.1(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@stylistic/stylelint-plugin': 3.1.3(stylelint@16.26.0(typescript@5.9.3))
|
'@stylistic/stylelint-plugin': 3.1.3(stylelint@16.26.1(typescript@5.9.3))
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-recommended: 16.0.0(stylelint@16.26.0(typescript@5.9.3))
|
stylelint-config-recommended: 16.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@16.26.0(typescript@5.9.3))
|
stylelint-plugin-ckeditor5-rules: 13.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
|
|
||||||
stylelint-config-ckeditor5@2.0.1(stylelint@16.26.0(typescript@5.9.3)):
|
stylelint-config-ckeditor5@2.0.1(stylelint@16.26.1(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
stylelint-config-recommended: 3.0.0(stylelint@16.26.0(typescript@5.9.3))
|
stylelint-config-recommended: 3.0.0(stylelint@16.26.1(typescript@5.9.3))
|
||||||
|
|
||||||
stylelint-config-recommended@16.0.0(stylelint@16.26.0(typescript@5.9.3)):
|
stylelint-config-recommended@16.0.0(stylelint@16.26.1(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
|
|
||||||
stylelint-config-recommended@3.0.0(stylelint@16.26.0(typescript@5.9.3)):
|
stylelint-config-recommended@3.0.0(stylelint@16.26.1(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
|
|
||||||
stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@16.26.0(typescript@5.9.3)):
|
stylelint-plugin-ckeditor5-rules@13.0.0(stylelint@16.26.1(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
stylelint: 16.26.0(typescript@5.9.3)
|
stylelint: 16.26.1(typescript@5.9.3)
|
||||||
|
|
||||||
stylelint@16.26.0(typescript@5.0.4):
|
stylelint@16.26.1(typescript@5.0.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
||||||
|
'@csstools/css-syntax-patches-for-csstree': 1.0.19
|
||||||
'@csstools/css-tokenizer': 3.0.4
|
'@csstools/css-tokenizer': 3.0.4
|
||||||
'@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
|
'@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
|
||||||
'@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0)
|
'@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0)
|
||||||
@ -30835,9 +30840,10 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
stylelint@16.26.0(typescript@5.9.3):
|
stylelint@16.26.1(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
|
||||||
|
'@csstools/css-syntax-patches-for-csstree': 1.0.19
|
||||||
'@csstools/css-tokenizer': 3.0.4
|
'@csstools/css-tokenizer': 3.0.4
|
||||||
'@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
|
'@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
|
||||||
'@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0)
|
'@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user