Merge branch 'develop' into note-create
@ -1 +1,6 @@
|
|||||||
VITE_CKEDITOR_ENABLE_INSPECTOR=false
|
VITE_CKEDITOR_ENABLE_INSPECTOR=false
|
||||||
|
|
||||||
|
# The development license key for premium CKEditor features.
|
||||||
|
# Note: This key must only be used for the Trilium Notes project.
|
||||||
|
# Expires on: 2025-09-13
|
||||||
|
VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3NTc3MjE1OTksImp0aSI6ImFiN2E0NjZmLWJlZGMtNDNiYy1iMzU4LTk0NGQ0YWJhY2I3ZiIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsic2giLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkNNVCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJTRUUiLCJFQ0giLCJFSVMiXSwidmMiOiI1MzlkOWY5YyJ9.2rvKPql4hmukyXhEtWPZ8MLxKvzPIwzCdykO653g7IxRRZy2QJpeRszElZx9DakKYZKXekVRAwQKgHxwkgbE_w
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
import debounce from "debounce";
|
||||||
|
import froca from "../../../services/froca.js";
|
||||||
|
import type LoadResults from "../../../services/load_results.js";
|
||||||
|
import search from "../../../services/search.js";
|
||||||
|
import type { TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
|
import appContext from "../../../components/app_context.js";
|
||||||
|
import TemplateIcon from "@ckeditor/ckeditor5-icons/theme/icons/template.svg?raw";
|
||||||
|
import type FNote from "../../../entities/fnote.js";
|
||||||
|
|
||||||
|
interface TemplateData {
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
content?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
let templateCache: Map<string, TemplateData> = new Map();
|
||||||
|
const debouncedHandleContentUpdate = debounce(handleContentUpdate, 1000);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the list of snippets based on the user's notes to be passed down to the CKEditor configuration.
|
||||||
|
*
|
||||||
|
* @returns the list of templates.
|
||||||
|
*/
|
||||||
|
export default async function getTemplates() {
|
||||||
|
// Build the definitions and populate the cache.
|
||||||
|
const snippets = await search.searchForNotes("#textSnippet");
|
||||||
|
const definitions: TemplateDefinition[] = [];
|
||||||
|
for (const snippet of snippets) {
|
||||||
|
const { description } = await invalidateCacheFor(snippet);
|
||||||
|
|
||||||
|
definitions.push({
|
||||||
|
title: snippet.title,
|
||||||
|
data: () => templateCache.get(snippet.noteId)?.content ?? "",
|
||||||
|
icon: TemplateIcon,
|
||||||
|
description
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return definitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function invalidateCacheFor(snippet: FNote) {
|
||||||
|
const description = snippet.getLabelValue("textSnippetDescription");
|
||||||
|
const data: TemplateData = {
|
||||||
|
title: snippet.title,
|
||||||
|
description: description ?? undefined,
|
||||||
|
content: await snippet.getContent()
|
||||||
|
};
|
||||||
|
templateCache.set(snippet.noteId, data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFullReload() {
|
||||||
|
console.warn("Full text editor reload needed");
|
||||||
|
appContext.triggerCommand("reloadTextEditor");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleContentUpdate(affectedNoteIds: string[]) {
|
||||||
|
const updatedNoteIds = new Set(affectedNoteIds);
|
||||||
|
const templateNoteIds = new Set(templateCache.keys());
|
||||||
|
const affectedTemplateNoteIds = templateNoteIds.intersection(updatedNoteIds);
|
||||||
|
|
||||||
|
await froca.getNotes(affectedNoteIds);
|
||||||
|
|
||||||
|
let fullReloadNeeded = false;
|
||||||
|
for (const affectedTemplateNoteId of affectedTemplateNoteIds) {
|
||||||
|
try {
|
||||||
|
const template = await froca.getNote(affectedTemplateNoteId);
|
||||||
|
if (!template) {
|
||||||
|
console.warn("Unable to obtain template with ID ", affectedTemplateNoteId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTitle = template.title;
|
||||||
|
if (templateCache.get(affectedTemplateNoteId)?.title !== newTitle) {
|
||||||
|
fullReloadNeeded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await invalidateCacheFor(template);
|
||||||
|
} catch (e) {
|
||||||
|
// If a note was not found while updating the cache, it means we need to do a full reload.
|
||||||
|
fullReloadNeeded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullReloadNeeded) {
|
||||||
|
handleFullReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTemplateCache(loadResults: LoadResults): boolean {
|
||||||
|
const affectedNoteIds = loadResults.getNoteIds();
|
||||||
|
|
||||||
|
// React to creation or deletion of text snippets.
|
||||||
|
if (loadResults.getAttributeRows().find((attr) =>
|
||||||
|
attr.type === "label" &&
|
||||||
|
(attr.name === "textSnippet" || attr.name === "textSnippetDescription"))) {
|
||||||
|
handleFullReload();
|
||||||
|
} else if (affectedNoteIds.length > 0) {
|
||||||
|
// Update content and titles if one of the template notes were updated.
|
||||||
|
debouncedHandleContentUpdate(affectedNoteIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
52
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Sharing.html
generated
vendored
22
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text.html
generated
vendored
|
After Width: | Height: | Size: 377 B |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
@ -0,0 +1,34 @@
|
|||||||
|
import { HiddenSubtreeItem } from "@triliumnext/commons";
|
||||||
|
|
||||||
|
export default function buildHiddenSubtreeTemplates() {
|
||||||
|
const templates: HiddenSubtreeItem = {
|
||||||
|
id: "_templates",
|
||||||
|
title: "Built-in templates",
|
||||||
|
type: "book",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
id: "_template_text_snippet",
|
||||||
|
type: "text",
|
||||||
|
title: "Text Snippet",
|
||||||
|
icon: "bx-align-left",
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
name: "template",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "textSnippet",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "label:textSnippetDescription",
|
||||||
|
type: "label",
|
||||||
|
value: "promoted,alias=Description,single,text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
@ -1,2 +1,10 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@plugin '@tailwindcss/typography';
|
@plugin '@tailwindcss/typography';
|
||||||
|
|
||||||
|
main a {
|
||||||
|
text-decoration: revert;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.rounded-full, a.rounded-xl {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
export let imgSrc = "/404.png";
|
||||||
|
export let imgAlt = "screenshot";
|
||||||
|
export let title = "title";
|
||||||
|
export let text = "text";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-white dark:bg-gray-900 rounded-xl shadow overflow-hidden">
|
||||||
|
<img src="{imgSrc}" alt="{imgAlt}" class="w-full h-56 object-cover object-top">
|
||||||
|
<div class="p-6">
|
||||||
|
<h3 class="text-xl font-semibold mb-2">{title}</h3>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300">{text}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 40 B |
@ -0,0 +1 @@
|
|||||||
|
../../../apps/client/src/assets/icon.png
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 40 B |
|
After Width: | Height: | Size: 804 KiB |
|
After Width: | Height: | Size: 785 KiB |
@ -0,0 +1 @@
|
|||||||
|
../../../../docs/User Guide/User Guide/Advanced Usage/1_Metrics_image.png
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
# Nix flake
|
||||||
|
Since TriliumNext 0.94.1, the desktop and server applications can be built using [Nix](https://nixos.org/).
|
||||||
|
|
||||||
|
## System requirements
|
||||||
|
|
||||||
|
Installation of Nix on Mac or Linux ([download page](https://nixos.org/download/)). About 3-4 gigabytes of additional storage space, for build artifacts.
|
||||||
|
|
||||||
|
## Run directly
|
||||||
|
|
||||||
|
Using [nix run](https://nix.dev/manual/nix/stable/command-ref/new-cli/nix3-run.html), the desktop app can be started as: `nix run github:TriliumNext/Notes/v0.95.0`
|
||||||
|
|
||||||
|
Running the server requires explicitly specifying the desired package: `nix run github:TriliumNext/Notes/v0.95.0#server`
|
||||||
|
|
||||||
|
Instead of a version (`v0.95.0` above), you can also specify a commit hash (or a branch name). This makes it easy to test development builds.
|
||||||
|
|
||||||
|
## Install on NixOS
|
||||||
|
|
||||||
|
Add to your `flake.nix`:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = # ...;
|
||||||
|
trilium-notes = {
|
||||||
|
url = "github:TriliumNext/Notes/v0.95.0";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
# ...
|
||||||
|
trilium-notes,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
nixosConfigurations = {
|
||||||
|
"nixos" = nixpkgs.lib.nixosSystem {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
modules = [
|
||||||
|
./configuration.nix
|
||||||
|
];
|
||||||
|
specialArgs = {
|
||||||
|
inherit
|
||||||
|
trilium-notes
|
||||||
|
;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Add to your `configuration.nix`:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
# ...
|
||||||
|
trilium-notes,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
# ...
|
||||||
|
|
||||||
|
services.trilium-server.package = trilium-notes.packages.x86_64-linux.server;
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
trilium-notes.packages.x86_64-linux.desktop
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The flake aims to be compatible with the latest NixOS stable and unstable.
|
||||||
@ -1,4 +1,4 @@
|
|||||||
# Build information
|
# Build information
|
||||||
* Provides context about when the build was made and the corresponding Git revision.
|
* Provides context about when the build was made and the corresponding Git revision.
|
||||||
* The information is displayed to the client when going in the about dialog.
|
* The information is displayed to the client when going in the about dialog.
|
||||||
* The build information is hard-coded in `src/services/build.ts`. This file is generated automatically via `npm run update-build-info` which itself is run automatically whenever making a build in the CI, or a [local delivery](../Build%20deliveries%20locally.md).
|
* The build information is hard-coded in `src/services/build.ts`. This file is generated automatically via `npm run update-build-info` which itself is run automatically whenever making a build in the CI, or a [local delivery](../Old%20documentation/Build%20deliveries%20locally.md).
|
||||||
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 233 KiB |
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 233 KiB |
|
Before Width: | Height: | Size: 748 KiB After Width: | Height: | Size: 748 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 250 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 251 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 716 KiB After Width: | Height: | Size: 716 KiB |
|
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 336 KiB |