mirror of
https://github.com/zadam/trilium.git
synced 2025-11-08 06:15:48 +01:00
Compare commits
14 Commits
feat/ui-im
...
d992a5e4a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d992a5e4a2 | ||
|
|
58c225237c | ||
|
|
d074841885 | ||
|
|
06b2d71b27 | ||
|
|
0afb8a11c8 | ||
|
|
f529ddc601 | ||
|
|
8572f82e0a | ||
|
|
b09a2c386d | ||
|
|
7c5553bd4b | ||
|
|
37d0136c50 | ||
|
|
5b79e0d71e | ||
|
|
053f722cb8 | ||
|
|
21aaec2c38 | ||
|
|
1db4971da6 |
2
.github/actions/build-server/action.yml
vendored
2
.github/actions/build-server/action.yml
vendored
@@ -12,7 +12,7 @@ runs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
|
||||
79
.github/workflows/deploy-docs.yml
vendored
79
.github/workflows/deploy-docs.yml
vendored
@@ -1,4 +1,6 @@
|
||||
name: Deploy Documentation
|
||||
# GitHub Actions workflow for deploying MkDocs documentation to Cloudflare Pages
|
||||
# This workflow builds and deploys your MkDocs site when changes are pushed to main
|
||||
name: Deploy MkDocs Documentation
|
||||
|
||||
on:
|
||||
# Trigger on push to main branch
|
||||
@@ -9,9 +11,11 @@ on:
|
||||
# Only run when docs files change
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'apps/edit-docs/**'
|
||||
- 'apps/build-docs/**'
|
||||
- 'packages/share-theme/**'
|
||||
- 'README.md' # README is synced to docs/index.md
|
||||
- 'mkdocs.yml'
|
||||
- 'requirements-docs.txt'
|
||||
- '.github/workflows/deploy-docs.yml'
|
||||
- 'scripts/fix-mkdocs-structure.ts'
|
||||
|
||||
# Allow manual triggering from Actions tab
|
||||
workflow_dispatch:
|
||||
@@ -23,13 +27,15 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'apps/edit-docs/**'
|
||||
- 'apps/build-docs/**'
|
||||
- 'packages/share-theme/**'
|
||||
- 'README.md' # README is synced to docs/index.md
|
||||
- 'mkdocs.yml'
|
||||
- 'requirements-docs.txt'
|
||||
- '.github/workflows/deploy-docs.yml'
|
||||
- 'scripts/fix-mkdocs-structure.ts'
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Build and Deploy Documentation
|
||||
name: Build and Deploy MkDocs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -43,27 +49,72 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for git info and mkdocs-git-revision-date plugin
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.14'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements-docs.txt'
|
||||
|
||||
- name: Install MkDocs and Dependencies
|
||||
run: |
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements-docs.txt
|
||||
env:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||
|
||||
# Setup pnpm before fixing docs structure
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
# Setup Node.js with pnpm
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '22'
|
||||
cache: 'pnpm'
|
||||
|
||||
# Install Node.js dependencies for the TypeScript script
|
||||
- name: Install Dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
- name: Trigger build of documentation
|
||||
run: pnpm docs:build
|
||||
- name: Fix Documentation Structure
|
||||
run: |
|
||||
# Fix duplicate navigation entries by moving overview pages to index.md
|
||||
pnpm run chore:fix-mkdocs-structure
|
||||
|
||||
- name: Build MkDocs Site
|
||||
run: |
|
||||
# Build with strict mode but allow expected warnings
|
||||
mkdocs build --verbose || {
|
||||
EXIT_CODE=$?
|
||||
# Check if the only issue is expected warnings
|
||||
if mkdocs build 2>&1 | grep -E "WARNING.*(README|not found)" && \
|
||||
[ $(mkdocs build 2>&1 | grep -c "ERROR") -eq 0 ]; then
|
||||
echo "✅ Build succeeded with expected warnings"
|
||||
mkdocs build --verbose
|
||||
else
|
||||
echo "❌ Build failed with unexpected errors"
|
||||
exit $EXIT_CODE
|
||||
fi
|
||||
}
|
||||
|
||||
- name: Fix HTML Links
|
||||
run: |
|
||||
# Remove .md extensions from links in generated HTML
|
||||
pnpm tsx ./scripts/fix-html-links.ts site
|
||||
|
||||
- name: Validate Built Site
|
||||
run: |
|
||||
# Basic validation that important files exist
|
||||
test -f site/index.html || (echo "ERROR: site/index.html not found" && exit 1)
|
||||
test -f site/developer-guide/index.html || (echo "ERROR: site/developer-guide/index.html not found" && exit 1)
|
||||
echo "✓ User Guide and Developer Guide built successfully"
|
||||
test -f site/sitemap.xml || (echo "ERROR: site/sitemap.xml not found" && exit 1)
|
||||
test -d site/assets || (echo "ERROR: site/assets directory not found" && exit 1)
|
||||
echo "✅ Site validation passed"
|
||||
|
||||
- name: Deploy
|
||||
uses: ./.github/actions/deploy-to-cloudflare-pages
|
||||
|
||||
2
.github/workflows/dev.yml
vendored
2
.github/workflows/dev.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
|
||||
16
.github/workflows/main-docker.yml
vendored
16
.github/workflows/main-docker.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install npm dependencies
|
||||
@@ -86,12 +86,12 @@ jobs:
|
||||
|
||||
- name: Upload Playwright trace
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Playwright trace (${{ matrix.dockerfile }})
|
||||
path: test-output/playwright/output
|
||||
|
||||
- uses: actions/upload-artifact@v5
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: Playwright report (${{ matrix.dockerfile }})
|
||||
@@ -116,10 +116,10 @@ jobs:
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm64
|
||||
image: ubuntu-24.04-arm
|
||||
- dockerfile: Dockerfile.legacy
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm/v7
|
||||
image: ubuntu-24.04-arm
|
||||
- dockerfile: Dockerfile.legacy
|
||||
- dockerfile: Dockerfile
|
||||
platform: linux/arm/v8
|
||||
image: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.image }}
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }}
|
||||
path: /tmp/digests/*
|
||||
@@ -223,7 +223,7 @@ jobs:
|
||||
- build
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
|
||||
4
.github/workflows/nightly.yml
vendored
4
.github/workflows/nightly.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
name: Nightly Build
|
||||
|
||||
- name: Publish artifacts
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
||||
|
||||
4
.github/workflows/playwright.yml
vendored
4
.github/workflows/playwright.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: Upload test report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e report
|
||||
path: apps/server-e2e/test-output
|
||||
|
||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
||||
|
||||
- name: Upload the artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-desktop-${{ matrix.os.name }}-${{ matrix.arch }}
|
||||
path: apps/desktop/upload/*.*
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Upload the artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-server-linux-${{ matrix.arch }}
|
||||
path: upload/*.*
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
docs/Release Notes
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
merge-multiple: true
|
||||
pattern: release-*
|
||||
|
||||
2
.github/workflows/website.yml
vendored
2
.github/workflows/website.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -37,18 +37,20 @@
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.56.1",
|
||||
"@stylistic/eslint-plugin": "5.5.0",
|
||||
"@types/express": "5.0.5",
|
||||
"@types/node": "24.10.0",
|
||||
"@types/yargs": "17.0.34",
|
||||
"@types/express": "5.0.3",
|
||||
"@types/node": "22.18.12",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"eslint": "9.39.1",
|
||||
"eslint": "9.38.0",
|
||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
||||
"esm": "3.2.25",
|
||||
"jsdoc": "4.0.5",
|
||||
"lorem-ipsum": "2.0.8",
|
||||
"rcedit": "4.0.1",
|
||||
"rimraf": "6.1.0",
|
||||
"tslib": "2.8.1"
|
||||
"rimraf": "6.0.1",
|
||||
"tslib": "2.8.1",
|
||||
"typedoc": "0.28.14",
|
||||
"typedoc-plugin-missing-exports": "4.1.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"appdmg": "0.6.6"
|
||||
|
||||
15
_regroup/typedoc.json
Normal file
15
_regroup/typedoc.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"entryPoints": [
|
||||
"src/services/backend_script_entrypoint.ts",
|
||||
"src/public/app/services/frontend_script_entrypoint.ts"
|
||||
],
|
||||
"plugin": [
|
||||
"typedoc-plugin-missing-exports"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "html",
|
||||
"path": "./docs/Script API"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "build-docs",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/main.ts",
|
||||
"scripts": {
|
||||
"start": "tsx ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Elian Doran <contact@eliandoran.me>",
|
||||
"license": "AGPL-3.0-only",
|
||||
"packageManager": "pnpm@10.20.0",
|
||||
"devDependencies": {
|
||||
"@redocly/cli": "2.11.0",
|
||||
"archiver": "7.0.1",
|
||||
"fs-extra": "11.3.2",
|
||||
"react": "19.2.0",
|
||||
"react-dom": "19.2.0",
|
||||
"typedoc": "0.28.14",
|
||||
"typedoc-plugin-missing-exports": "4.1.2"
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* The backend script API is accessible to code notes with the "JS (backend)" language.
|
||||
*
|
||||
* The entire API is exposed as a single global: {@link api}
|
||||
*
|
||||
* @module Backend Script API
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file creates the entrypoint for TypeDoc that simulates the context from within a
|
||||
* script note on the server side.
|
||||
*
|
||||
* Make sure to keep in line with backend's `script_context.ts`.
|
||||
*/
|
||||
|
||||
export type { default as AbstractBeccaEntity } from "../../server/src/becca/entities/abstract_becca_entity.js";
|
||||
export type { default as BAttachment } from "../../server/src/becca/entities/battachment.js";
|
||||
export type { default as BAttribute } from "../../server/src/becca/entities/battribute.js";
|
||||
export type { default as BBranch } from "../../server/src/becca/entities/bbranch.js";
|
||||
export type { default as BEtapiToken } from "../../server/src/becca/entities/betapi_token.js";
|
||||
export type { BNote };
|
||||
export type { default as BOption } from "../../server/src/becca/entities/boption.js";
|
||||
export type { default as BRecentNote } from "../../server/src/becca/entities/brecent_note.js";
|
||||
export type { default as BRevision } from "../../server/src/becca/entities/brevision.js";
|
||||
|
||||
import BNote from "../../server/src/becca/entities/bnote.js";
|
||||
import BackendScriptApi, { type Api } from "../../server/src/services/backend_script_api.js";
|
||||
|
||||
export type { Api };
|
||||
|
||||
const fakeNote = new BNote();
|
||||
|
||||
/**
|
||||
* The `api` global variable allows access to the backend script API, which is documented in {@link Api}.
|
||||
*/
|
||||
export const api: Api = new BackendScriptApi(fakeNote, {});
|
||||
@@ -1,147 +0,0 @@
|
||||
process.env.TRILIUM_INTEGRATION_TEST = "memory-no-store";
|
||||
process.env.TRILIUM_RESOURCE_DIR = "../server/src";
|
||||
process.env.NODE_ENV = "development";
|
||||
|
||||
import cls from "@triliumnext/server/src/services/cls.js";
|
||||
import { dirname, join, resolve } from "path";
|
||||
import * as fs from "fs/promises";
|
||||
import * as fsExtra from "fs-extra";
|
||||
import archiver from "archiver";
|
||||
import { WriteStream } from "fs";
|
||||
import { execSync } from "child_process";
|
||||
import BuildContext from "./context.js";
|
||||
|
||||
const DOCS_ROOT = "../../../docs";
|
||||
const OUTPUT_DIR = "../../site";
|
||||
|
||||
async function importAndExportDocs(sourcePath: string, outputSubDir: string) {
|
||||
const note = await importData(sourcePath);
|
||||
|
||||
// Use a meaningful name for the temporary zip file
|
||||
const zipName = outputSubDir || "user-guide";
|
||||
const zipFilePath = `output-${zipName}.zip`;
|
||||
try {
|
||||
const { exportToZip } = (await import("@triliumnext/server/src/services/export/zip.js")).default;
|
||||
const branch = note.getParentBranches()[0];
|
||||
const taskContext = new (await import("@triliumnext/server/src/services/task_context.js")).default(
|
||||
"no-progress-reporting",
|
||||
"export",
|
||||
null
|
||||
);
|
||||
const fileOutputStream = fsExtra.createWriteStream(zipFilePath);
|
||||
await exportToZip(taskContext, branch, "share", fileOutputStream);
|
||||
await waitForStreamToFinish(fileOutputStream);
|
||||
|
||||
// Output to root directory if outputSubDir is empty, otherwise to subdirectory
|
||||
const outputPath = outputSubDir ? join(OUTPUT_DIR, outputSubDir) : OUTPUT_DIR;
|
||||
await extractZip(zipFilePath, outputPath);
|
||||
} finally {
|
||||
if (await fsExtra.exists(zipFilePath)) {
|
||||
await fsExtra.rm(zipFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function buildDocsInner() {
|
||||
const i18n = await import("@triliumnext/server/src/services/i18n.js");
|
||||
await i18n.initializeTranslations();
|
||||
|
||||
const sqlInit = (await import("../../server/src/services/sql_init.js")).default;
|
||||
await sqlInit.createInitialDatabase(true);
|
||||
|
||||
// Wait for becca to be loaded before importing data
|
||||
const beccaLoader = await import("../../server/src/becca/becca_loader.js");
|
||||
await beccaLoader.beccaLoaded;
|
||||
|
||||
// Build User Guide
|
||||
console.log("Building User Guide...");
|
||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "User Guide"), "user-guide");
|
||||
|
||||
// Build Developer Guide
|
||||
console.log("Building Developer Guide...");
|
||||
await importAndExportDocs(join(__dirname, DOCS_ROOT, "Developer Guide"), "developer-guide");
|
||||
|
||||
// Copy favicon.
|
||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "favicon.ico"));
|
||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "user-guide", "favicon.ico"));
|
||||
await fs.copyFile("../../apps/website/src/assets/favicon.ico", join(OUTPUT_DIR, "developer-guide", "favicon.ico"));
|
||||
|
||||
console.log("Documentation built successfully!");
|
||||
}
|
||||
|
||||
export async function importData(path: string) {
|
||||
const buffer = await createImportZip(path);
|
||||
const importService = (await import("../../server/src/services/import/zip.js")).default;
|
||||
const TaskContext = (await import("../../server/src/services/task_context.js")).default;
|
||||
const context = new TaskContext("no-progress-reporting", "importNotes", null);
|
||||
const becca = (await import("../../server/src/becca/becca.js")).default;
|
||||
|
||||
const rootNote = becca.getRoot();
|
||||
if (!rootNote) {
|
||||
throw new Error("Missing root note for import.");
|
||||
}
|
||||
return await importService.importZip(context, buffer, rootNote, {
|
||||
preserveIds: true
|
||||
});
|
||||
}
|
||||
|
||||
async function createImportZip(path: string) {
|
||||
const inputFile = "input.zip";
|
||||
const archive = archiver("zip", {
|
||||
zlib: { level: 0 }
|
||||
});
|
||||
|
||||
console.log("Archive path is ", resolve(path))
|
||||
archive.directory(path, "/");
|
||||
|
||||
const outputStream = fsExtra.createWriteStream(inputFile);
|
||||
archive.pipe(outputStream);
|
||||
archive.finalize();
|
||||
await waitForStreamToFinish(outputStream);
|
||||
|
||||
try {
|
||||
return await fsExtra.readFile(inputFile);
|
||||
} finally {
|
||||
await fsExtra.rm(inputFile);
|
||||
}
|
||||
}
|
||||
|
||||
function waitForStreamToFinish(stream: WriteStream) {
|
||||
return new Promise<void>((res, rej) => {
|
||||
stream.on("finish", () => res());
|
||||
stream.on("error", (err) => rej(err));
|
||||
});
|
||||
}
|
||||
|
||||
export async function extractZip(zipFilePath: string, outputPath: string, ignoredFiles?: Set<string>) {
|
||||
const { readZipFile, readContent } = (await import("@triliumnext/server/src/services/import/zip.js"));
|
||||
await readZipFile(await fs.readFile(zipFilePath), async (zip, entry) => {
|
||||
// We ignore directories since they can appear out of order anyway.
|
||||
if (!entry.fileName.endsWith("/") && !ignoredFiles?.has(entry.fileName)) {
|
||||
const destPath = join(outputPath, entry.fileName);
|
||||
const fileContent = await readContent(zip, entry);
|
||||
|
||||
await fsExtra.mkdirs(dirname(destPath));
|
||||
await fs.writeFile(destPath, fileContent);
|
||||
}
|
||||
|
||||
zip.readEntry();
|
||||
});
|
||||
}
|
||||
|
||||
export default async function buildDocs({ gitRootDir }: BuildContext) {
|
||||
// Build the share theme.
|
||||
execSync(`pnpm run --filter share-theme build`, {
|
||||
stdio: "inherit",
|
||||
cwd: gitRootDir
|
||||
});
|
||||
|
||||
// Trigger the actual build.
|
||||
await new Promise((res, rej) => {
|
||||
cls.init(() => {
|
||||
buildDocsInner()
|
||||
.catch(rej)
|
||||
.then(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export default interface BuildContext {
|
||||
gitRootDir: string;
|
||||
baseDir: string;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* The front script API is accessible to code notes with the "JS (frontend)" language.
|
||||
*
|
||||
* The entire API is exposed as a single global: {@link api}
|
||||
*
|
||||
* @module Frontend Script API
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file creates the entrypoint for TypeDoc that simulates the context from within a
|
||||
* script note.
|
||||
*
|
||||
* Make sure to keep in line with frontend's `script_context.ts`.
|
||||
*/
|
||||
|
||||
export type { default as BasicWidget } from "../../client/src/widgets/basic_widget.js";
|
||||
export type { default as FAttachment } from "../../client/src/entities/fattachment.js";
|
||||
export type { default as FAttribute } from "../../client/src/entities/fattribute.js";
|
||||
export type { default as FBranch } from "../../client/src/entities/fbranch.js";
|
||||
export type { default as FNote } from "../../client/src/entities/fnote.js";
|
||||
export type { Api } from "../../client/src/services/frontend_script_api.js";
|
||||
export type { default as NoteContextAwareWidget } from "../../client/src/widgets/note_context_aware_widget.js";
|
||||
export type { default as RightPanelWidget } from "../../client/src/widgets/right_panel_widget.js";
|
||||
|
||||
import FrontendScriptApi, { type Api } from "../../client/src/services/frontend_script_api.js";
|
||||
|
||||
//@ts-expect-error
|
||||
export const api: Api = new FrontendScriptApi();
|
||||
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=/user-guide">
|
||||
<title>Redirecting...</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>If you are not redirected automatically, <a href="/user-guide">click here</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,30 +0,0 @@
|
||||
import { join } from "path";
|
||||
import BuildContext from "./context";
|
||||
import buildSwagger from "./swagger";
|
||||
import { cpSync, existsSync, mkdirSync, rmSync } from "fs";
|
||||
import buildDocs from "./build-docs";
|
||||
import buildScriptApi from "./script-api";
|
||||
|
||||
const context: BuildContext = {
|
||||
gitRootDir: join(__dirname, "../../../"),
|
||||
baseDir: join(__dirname, "../../../site")
|
||||
};
|
||||
|
||||
async function main() {
|
||||
// Clean input dir.
|
||||
if (existsSync(context.baseDir)) {
|
||||
rmSync(context.baseDir, { recursive: true });
|
||||
}
|
||||
mkdirSync(context.baseDir);
|
||||
|
||||
// Start building.
|
||||
await buildDocs(context);
|
||||
buildSwagger(context);
|
||||
buildScriptApi(context);
|
||||
|
||||
// Copy index and 404 files.
|
||||
cpSync(join(__dirname, "index.html"), join(context.baseDir, "index.html"));
|
||||
cpSync(join(context.baseDir, "user-guide/404.html"), join(context.baseDir, "404.html"));
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,15 +0,0 @@
|
||||
import { execSync } from "child_process";
|
||||
import BuildContext from "./context";
|
||||
import { join } from "path";
|
||||
|
||||
export default function buildScriptApi({ baseDir, gitRootDir }: BuildContext) {
|
||||
// Generate types
|
||||
execSync(`pnpm typecheck`, { stdio: "inherit", cwd: gitRootDir });
|
||||
|
||||
for (const config of [ "backend", "frontend" ]) {
|
||||
const outDir = join(baseDir, "script-api", config);
|
||||
execSync(`pnpm typedoc --options typedoc.${config}.json --html "${outDir}"`, {
|
||||
stdio: "inherit"
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import BuildContext from "./context";
|
||||
import { join } from "path";
|
||||
import { execSync } from "child_process";
|
||||
import { mkdirSync } from "fs";
|
||||
|
||||
interface BuildInfo {
|
||||
specPath: string;
|
||||
outDir: string;
|
||||
}
|
||||
|
||||
const DIR_PREFIX = "rest-api";
|
||||
|
||||
const buildInfos: BuildInfo[] = [
|
||||
{
|
||||
// Paths are relative to Git root.
|
||||
specPath: "apps/server/internal.openapi.yaml",
|
||||
outDir: `${DIR_PREFIX}/internal`
|
||||
},
|
||||
{
|
||||
specPath: "apps/server/etapi.openapi.yaml",
|
||||
outDir: `${DIR_PREFIX}/etapi`
|
||||
}
|
||||
];
|
||||
|
||||
export default function buildSwagger({ baseDir, gitRootDir }: BuildContext) {
|
||||
for (const { specPath, outDir } of buildInfos) {
|
||||
const absSpecPath = join(gitRootDir, specPath);
|
||||
const targetDir = join(baseDir, outDir);
|
||||
mkdirSync(targetDir, { recursive: true });
|
||||
execSync(`pnpm redocly build-docs ${absSpecPath} -o ${targetDir}/index.html`, { stdio: "inherit" });
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"target": "ES2020",
|
||||
"outDir": "dist",
|
||||
"strict": false,
|
||||
"types": [
|
||||
"node",
|
||||
"express"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"../server/src/*.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"eslint.config.js",
|
||||
"eslint.config.cjs",
|
||||
"eslint.config.mjs"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../server/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "../desktop/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "../client/tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "../server"
|
||||
},
|
||||
{
|
||||
"path": "../client"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"name": "Trilium Backend API",
|
||||
"entryPoints": [
|
||||
"src/backend_script_entrypoint.ts"
|
||||
],
|
||||
"plugin": [
|
||||
"typedoc-plugin-missing-exports"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"name": "Trilium Frontend API",
|
||||
"entryPoints": [
|
||||
"src/frontend_script_entrypoint.ts"
|
||||
],
|
||||
"plugin": [
|
||||
"typedoc-plugin-missing-exports"
|
||||
]
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "9.39.1",
|
||||
"@eslint/js": "9.38.0",
|
||||
"@excalidraw/excalidraw": "0.18.0",
|
||||
"@fullcalendar/core": "6.1.19",
|
||||
"@fullcalendar/daygrid": "6.1.19",
|
||||
@@ -37,12 +37,12 @@
|
||||
"bootstrap": "5.3.8",
|
||||
"boxicons": "2.1.4",
|
||||
"color": "5.0.2",
|
||||
"dayjs": "1.11.19",
|
||||
"dayjs": "1.11.18",
|
||||
"dayjs-plugin-utc": "0.1.2",
|
||||
"debounce": "3.0.0",
|
||||
"debounce": "2.2.0",
|
||||
"draggabilly": "3.0.0",
|
||||
"force-graph": "1.51.0",
|
||||
"globals": "16.5.0",
|
||||
"globals": "16.4.0",
|
||||
"i18next": "25.6.0",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"jquery": "3.7.1",
|
||||
@@ -54,12 +54,12 @@
|
||||
"leaflet-gpx": "2.2.0",
|
||||
"mark.js": "8.11.1",
|
||||
"marked": "16.4.1",
|
||||
"mermaid": "11.12.1",
|
||||
"mind-elixir": "5.3.5",
|
||||
"mermaid": "11.12.0",
|
||||
"mind-elixir": "5.3.3",
|
||||
"normalize.css": "8.0.1",
|
||||
"panzoom": "9.4.3",
|
||||
"preact": "10.27.2",
|
||||
"react-i18next": "16.2.4",
|
||||
"react-i18next": "16.1.2",
|
||||
"reveal.js": "5.2.1",
|
||||
"svg-pan-zoom": "3.6.2",
|
||||
"tabulator-tables": "6.3.1",
|
||||
@@ -74,9 +74,9 @@
|
||||
"@types/leaflet-gpx": "1.3.8",
|
||||
"@types/mark.js": "8.11.12",
|
||||
"@types/reveal.js": "5.2.1",
|
||||
"@types/tabulator-tables": "6.3.0",
|
||||
"@types/tabulator-tables": "6.2.11",
|
||||
"copy-webpack-plugin": "13.0.1",
|
||||
"happy-dom": "20.0.10",
|
||||
"happy-dom": "20.0.7",
|
||||
"script-loader": "0.7.2",
|
||||
"vite-plugin-static-copy": "3.1.4"
|
||||
}
|
||||
|
||||
@@ -218,12 +218,12 @@ export type CommandMappings = {
|
||||
/** Works only in the electron context menu. */
|
||||
replaceMisspelling: CommandData;
|
||||
|
||||
importMarkdownInline: CommandData;
|
||||
showPasswordNotSet: CommandData;
|
||||
showProtectedSessionPasswordDialog: CommandData;
|
||||
showUploadAttachmentsDialog: CommandData & { noteId: string };
|
||||
showIncludeNoteDialog: CommandData & { textTypeWidget: EditableTextTypeWidget };
|
||||
showAddLinkDialog: CommandData & { textTypeWidget: EditableTextTypeWidget, text: string };
|
||||
showPasteMarkdownDialog: CommandData & { textTypeWidget: EditableTextTypeWidget };
|
||||
closeProtectedSessionPasswordDialog: CommandData;
|
||||
copyImageReferenceToClipboard: CommandData;
|
||||
copyImageToClipboard: CommandData;
|
||||
@@ -270,7 +270,6 @@ export type CommandMappings = {
|
||||
closeThisNoteSplit: CommandData;
|
||||
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
|
||||
jumpToNote: CommandData;
|
||||
openTodayNote: CommandData;
|
||||
commandPalette: CommandData;
|
||||
|
||||
// Keyboard shortcuts
|
||||
|
||||
@@ -159,16 +159,6 @@ export default class Entrypoints extends Component {
|
||||
this.openInWindowCommand({ notePath: "", hoistedNoteId: "root" });
|
||||
}
|
||||
|
||||
async openTodayNoteCommand() {
|
||||
const todayNote = await dateNoteService.getTodayNote();
|
||||
if (!todayNote) {
|
||||
console.warn("Missing today note.");
|
||||
return;
|
||||
}
|
||||
|
||||
await appContext.tabManager.openInSameTab(todayNote.noteId);
|
||||
}
|
||||
|
||||
async runActiveNoteCommand() {
|
||||
const noteContext = appContext.tabManager.getActiveContext();
|
||||
if (!noteContext) {
|
||||
|
||||
@@ -417,7 +417,7 @@ export default class FNote {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
getSortedNotePathRecords(hoistedNoteId = "root", activeNotePath: string | null = null): NotePathRecord[] {
|
||||
getSortedNotePathRecords(hoistedNoteId = "root"): NotePathRecord[] {
|
||||
const isHoistedRoot = hoistedNoteId === "root";
|
||||
|
||||
const notePaths: NotePathRecord[] = this.getAllNotePaths().map((path) => ({
|
||||
@@ -428,23 +428,7 @@ export default class FNote {
|
||||
isHidden: path.includes("_hidden")
|
||||
}));
|
||||
|
||||
// Calculate the length of the prefix match between two arrays
|
||||
const prefixMatchLength = (path: string[], target: string[]) => {
|
||||
const diffIndex = path.findIndex((seg, i) => seg !== target[i]);
|
||||
return diffIndex === -1 ? Math.min(path.length, target.length) : diffIndex;
|
||||
};
|
||||
|
||||
notePaths.sort((a, b) => {
|
||||
if (activeNotePath) {
|
||||
const activeSegments = activeNotePath.split('/');
|
||||
const aOverlap = prefixMatchLength(a.notePath, activeSegments);
|
||||
const bOverlap = prefixMatchLength(b.notePath, activeSegments);
|
||||
// Paths with more matching prefix segments are prioritized
|
||||
// when the match count is equal, other criteria are used for sorting
|
||||
if (bOverlap !== aOverlap) {
|
||||
return bOverlap - aOverlap;
|
||||
}
|
||||
}
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
@@ -465,11 +449,10 @@ export default class FNote {
|
||||
* Returns the note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @param {string|null} [activeNotePath=null]
|
||||
* @return {string[]} array of noteIds constituting the particular note path
|
||||
*/
|
||||
getBestNotePath(hoistedNoteId = "root", activeNotePath: string | null = null) {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId, activeNotePath)[0]?.notePath;
|
||||
getBestNotePath(hoistedNoteId = "root") {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId)[0]?.notePath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
import { applyModals } from "./layout_commons.js";
|
||||
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
||||
import ApiLog from "../widgets/api_log.jsx";
|
||||
import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
|
||||
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
|
||||
import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
|
||||
import FindWidget from "../widgets/find.js";
|
||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||
import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
||||
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
|
||||
import HighlightsListWidget from "../widgets/highlights_list.js";
|
||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||
import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
|
||||
import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js";
|
||||
import MovePaneButton from "../widgets/buttons/move_pane_button.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import NoteIconWidget from "../widgets/note_icon.jsx";
|
||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||
import NoteTitleWidget from "../widgets/note_title.jsx";
|
||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import options from "../services/options.js";
|
||||
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||
import ReadOnlyNoteInfoBar from "../widgets/read_only_note_info_bar.jsx";
|
||||
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
|
||||
import RightPaneContainer from "../widgets/containers/right_pane_container.js";
|
||||
import RootContainer from "../widgets/containers/root_container.js";
|
||||
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||
import ScrollPadding from "../widgets/scroll_padding.js";
|
||||
import SearchResult from "../widgets/search_result.jsx";
|
||||
import SharedInfo from "../widgets/shared_info.jsx";
|
||||
import SpacerWidget from "../widgets/spacer.js";
|
||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||
import SqlResults from "../widgets/sql_result.js";
|
||||
import SqlTableSchemas from "../widgets/sql_table_schemas.js";
|
||||
import TabRowWidget from "../widgets/tab_row.js";
|
||||
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
|
||||
import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
|
||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import NoteTitleWidget from "../widgets/note_title.jsx";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import NoteIconWidget from "../widgets/note_icon.jsx";
|
||||
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||
import RootContainer from "../widgets/containers/root_container.js";
|
||||
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
|
||||
import SpacerWidget from "../widgets/spacer.js";
|
||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
|
||||
import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
|
||||
import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
|
||||
import RightPaneContainer from "../widgets/containers/right_pane_container.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import FindWidget from "../widgets/find.js";
|
||||
import TocWidget from "../widgets/toc.js";
|
||||
import HighlightsListWidget from "../widgets/highlights_list.js";
|
||||
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
|
||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||
import MovePaneButton from "../widgets/buttons/move_pane_button.js";
|
||||
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
|
||||
import ScrollPadding from "../widgets/scroll_padding.js";
|
||||
import options from "../services/options.js";
|
||||
import utils from "../services/utils.js";
|
||||
import type { AppContext } from "../components/app_context.js";
|
||||
import type { WidgetsByParent } from "../services/bundle.js";
|
||||
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
|
||||
import utils from "../services/utils.js";
|
||||
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
|
||||
import { applyModals } from "./layout_commons.js";
|
||||
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
|
||||
import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
||||
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
||||
import SearchResult from "../widgets/search_result.jsx";
|
||||
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
|
||||
import SqlResults from "../widgets/sql_result.js";
|
||||
import SqlTableSchemas from "../widgets/sql_table_schemas.js";
|
||||
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
|
||||
import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js";
|
||||
import ApiLog from "../widgets/api_log.jsx";
|
||||
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
|
||||
import SharedInfo from "../widgets/shared_info.jsx";
|
||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||
|
||||
export default class DesktopLayout {
|
||||
|
||||
@@ -131,13 +130,11 @@ export default class DesktopLayout {
|
||||
)
|
||||
.child(<Ribbon />)
|
||||
.child(<SharedInfo />)
|
||||
.child(<ReadOnlyNoteInfoBar />)
|
||||
.child(new WatchedFileUpdateStatusWidget())
|
||||
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
|
||||
.child(
|
||||
new ScrollingContainer()
|
||||
.filling()
|
||||
.child(<ReadOnlyNoteInfoBar zenModeOnly />)
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(<SqlTableSchemas />)
|
||||
.child(new NoteDetailWidget())
|
||||
|
||||
@@ -1,33 +1,32 @@
|
||||
import { applyModals } from "./layout_commons.js";
|
||||
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
||||
import { useNoteContext } from "../widgets/react/hooks.jsx";
|
||||
import CloseZenModeButton from "../widgets/close_zen_button.js";
|
||||
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
|
||||
import FlexContainer from "../widgets/containers/flex_container.js";
|
||||
import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
||||
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
|
||||
import MobileEditorToolbar from "../widgets/type_widgets/ckeditor/mobile_editor_toolbar.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||
import NoteTitleWidget from "../widgets/note_title.js";
|
||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import QuickSearchWidget from "../widgets/quick_search.js";
|
||||
import ReadOnlyNoteInfoBar from "../widgets/read_only_note_info_bar.jsx";
|
||||
import RootContainer from "../widgets/containers/root_container.js";
|
||||
import NoteTreeWidget from "../widgets/note_tree.js";
|
||||
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
|
||||
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
|
||||
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||
import RootContainer from "../widgets/containers/root_container.js";
|
||||
import SharedInfoWidget from "../widgets/shared_info.js";
|
||||
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
|
||||
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
|
||||
import type AppContext from "../components/app_context.js";
|
||||
import TabRowWidget from "../widgets/tab_row.js";
|
||||
import MobileEditorToolbar from "../widgets/type_widgets/ckeditor/mobile_editor_toolbar.js";
|
||||
import { applyModals } from "./layout_commons.js";
|
||||
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
|
||||
import { useNoteContext } from "../widgets/react/hooks.jsx";
|
||||
import FloatingButtons from "../widgets/FloatingButtons.jsx";
|
||||
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
|
||||
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
||||
import CloseZenModeButton from "../widgets/close_zen_button.js";
|
||||
import NoteWrapperWidget from "../widgets/note_wrapper.js";
|
||||
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
|
||||
import NoteList from "../widgets/collections/NoteList.jsx";
|
||||
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
|
||||
import SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx";
|
||||
import SearchResult from "../widgets/search_result.jsx";
|
||||
import SharedInfoWidget from "../widgets/shared_info.js";
|
||||
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
|
||||
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
|
||||
import TabRowWidget from "../widgets/tab_row.js";
|
||||
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
|
||||
import type AppContext from "../components/app_context.js";
|
||||
|
||||
const MOBILE_CSS = `
|
||||
<style>
|
||||
@@ -151,9 +150,7 @@ export default class MobileLayout {
|
||||
.child(<MobileDetailMenu />)
|
||||
)
|
||||
.child(<SharedInfoWidget />)
|
||||
.child(<ReadOnlyNoteInfoBar />)
|
||||
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
|
||||
.child(<ReadOnlyNoteInfoBar zenModeOnly />)
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(
|
||||
new ScrollingContainer()
|
||||
|
||||
@@ -137,7 +137,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
||||
command: "editBranchPrefix",
|
||||
keyboardShortcut: "editBranchPrefix",
|
||||
uiIcon: "bx bx-rename",
|
||||
enabled: isNotRoot && parentNotSearch && notOptionsOrHelp
|
||||
enabled: isNotRoot && parentNotSearch && noSelectedNotes && notOptionsOrHelp
|
||||
},
|
||||
{ title: t("tree-context-menu.convert-to-attachment"), command: "convertNoteToAttachment", uiIcon: "bx bx-paperclip", enabled: isNotRoot && !isHoisted && notOptionsOrHelp },
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "boxicons/css/boxicons.min.css";
|
||||
|
||||
:root {
|
||||
--print-font-size: 11pt;
|
||||
--ck-content-color-image-caption-background: transparent !important;
|
||||
|
||||
@@ -56,20 +56,7 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) {
|
||||
await import("@triliumnext/ckeditor5/src/theme/ck-content.css");
|
||||
}
|
||||
const { $renderedContent } = await content_renderer.getRenderedContent(note, { noChildrenList: true });
|
||||
const container = containerRef.current!;
|
||||
container.replaceChildren(...$renderedContent);
|
||||
|
||||
// Wait for all images to load.
|
||||
const images = Array.from(container.querySelectorAll("img"));
|
||||
await Promise.all(
|
||||
images.map(img => {
|
||||
if (img.complete) return Promise.resolve();
|
||||
return new Promise<void>(resolve => {
|
||||
img.addEventListener("load", () => resolve(), { once: true });
|
||||
img.addEventListener("error", () => resolve(), { once: true });
|
||||
});
|
||||
})
|
||||
);
|
||||
containerRef.current?.replaceChildren(...$renderedContent);
|
||||
}
|
||||
|
||||
load().then(() => requestAnimationFrame(onReady))
|
||||
|
||||
28
apps/client/src/services/frontend_script_entrypoint.ts
Normal file
28
apps/client/src/services/frontend_script_entrypoint.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* The front script API is accessible to code notes with the "JS (frontend)" language.
|
||||
*
|
||||
* The entire API is exposed as a single global: {@link api}
|
||||
*
|
||||
* @module Frontend Script API
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file creates the entrypoint for TypeDoc that simulates the context from within a
|
||||
* script note.
|
||||
*
|
||||
* Make sure to keep in line with frontend's `script_context.ts`.
|
||||
*/
|
||||
|
||||
export type { default as BasicWidget } from "../widgets/basic_widget.js";
|
||||
export type { default as FAttachment } from "../entities/fattachment.js";
|
||||
export type { default as FAttribute } from "../entities/fattribute.js";
|
||||
export type { default as FBranch } from "../entities/fbranch.js";
|
||||
export type { default as FNote } from "../entities/fnote.js";
|
||||
export type { Api } from "./frontend_script_api.js";
|
||||
export type { default as NoteContextAwareWidget } from "../widgets/note_context_aware_widget.js";
|
||||
export type { default as RightPanelWidget } from "../widgets/right_panel_widget.js";
|
||||
|
||||
import FrontendScriptApi, { type Api } from "./frontend_script_api.js";
|
||||
|
||||
//@ts-expect-error
|
||||
export const api: Api = new FrontendScriptApi();
|
||||
@@ -20,6 +20,9 @@ function setupGlobs() {
|
||||
window.glob.froca = froca;
|
||||
window.glob.treeCache = froca; // compatibility for CKEditor builds for a while
|
||||
|
||||
// for CKEditor integration (button on block toolbar)
|
||||
window.glob.importMarkdownInline = async () => appContext.triggerCommand("importMarkdownInline");
|
||||
|
||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||
const string = String(msg).toLowerCase();
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
|
||||
file: null,
|
||||
image: null,
|
||||
launcher: null,
|
||||
mermaid: "s1aBHPd79XYj",
|
||||
mermaid: null,
|
||||
mindMap: null,
|
||||
noteMap: null,
|
||||
relationMap: null,
|
||||
|
||||
@@ -159,7 +159,7 @@ describe("shortcuts", () => {
|
||||
expect(matchesShortcut(event, "Shift+F1")).toBeTruthy();
|
||||
|
||||
// Special keys
|
||||
for (const keyCode of [ "Delete", "Enter", "NumpadEnter" ]) {
|
||||
for (const keyCode of [ "Delete", "Enter" ]) {
|
||||
event = createKeyboardEvent({ key: keyCode, code: keyCode });
|
||||
expect(matchesShortcut(event, keyCode), `Key ${keyCode}`).toBeTruthy();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ for (let i = 1; i <= 19; i++) {
|
||||
const KEYCODES_WITH_NO_MODIFIER = new Set([
|
||||
"Delete",
|
||||
"Enter",
|
||||
"NumpadEnter",
|
||||
...functionKeyCodes
|
||||
]);
|
||||
|
||||
|
||||
@@ -26,12 +26,21 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
|
||||
}
|
||||
|
||||
const path = notePath.split("/").reverse();
|
||||
|
||||
if (!path.includes("root")) {
|
||||
path.push("root");
|
||||
}
|
||||
|
||||
const effectivePathSegments: string[] = [];
|
||||
let childNoteId: string | null = null;
|
||||
let i = 0;
|
||||
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const parentNoteId = path[i];
|
||||
while (true) {
|
||||
if (i >= path.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
const parentNoteId = path[i++];
|
||||
|
||||
if (childNoteId !== null) {
|
||||
const child = await froca.getNote(childNoteId, !logErrors);
|
||||
@@ -56,7 +65,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!parents.some(p => p.noteId === parentNoteId) || (i === path.length - 1 && parentNoteId !== 'root')) {
|
||||
if (!parents.some((p) => p.noteId === parentNoteId)) {
|
||||
if (logErrors) {
|
||||
const parent = froca.getNoteFromCache(parentNoteId);
|
||||
|
||||
@@ -68,8 +77,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
|
||||
);
|
||||
}
|
||||
|
||||
const activeNotePath = appContext.tabManager.getActiveContextNotePath();
|
||||
const bestNotePath = child.getBestNotePath(hoistedNoteId, activeNotePath);
|
||||
const bestNotePath = child.getBestNotePath(hoistedNoteId);
|
||||
|
||||
if (bestNotePath) {
|
||||
const pathToRoot = bestNotePath.reverse().slice(1);
|
||||
@@ -100,9 +108,7 @@ async function resolveNotePathToSegments(notePath: string, hoistedNoteId = "root
|
||||
if (!note) {
|
||||
throw new Error(`Unable to find note: ${notePath}.`);
|
||||
}
|
||||
|
||||
const activeNotePath = appContext.tabManager.getActiveContextNotePath();
|
||||
const bestNotePath = note.getBestNotePath(hoistedNoteId, activeNotePath);
|
||||
const bestNotePath = note.getBestNotePath(hoistedNoteId);
|
||||
|
||||
if (!bestNotePath) {
|
||||
throw new Error(`Did not find any path segments for '${note.toString()}', hoisted note '${hoistedNoteId}'`);
|
||||
|
||||
@@ -11,11 +11,7 @@ export function reloadFrontendApp(reason?: string) {
|
||||
logInfo(`Frontend app reload: ${reason}`);
|
||||
}
|
||||
|
||||
if (isElectron()) {
|
||||
dynamicRequire("@electron/remote").BrowserWindow.getFocusedWindow()?.reload();
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
export function restartDesktopApp() {
|
||||
|
||||
84
apps/client/src/share.ts
Normal file
84
apps/client/src/share.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import "normalize.css";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "@triliumnext/ckeditor5/src/theme/ck-content.css";
|
||||
import "@triliumnext/share-theme/styles/index.css";
|
||||
import "@triliumnext/share-theme/scripts/index.js";
|
||||
|
||||
async function ensureJQuery() {
|
||||
const $ = (await import("jquery")).default;
|
||||
(window as any).$ = $;
|
||||
}
|
||||
|
||||
async function applyMath() {
|
||||
const anyMathBlock = document.querySelector("#content .math-tex");
|
||||
if (!anyMathBlock) {
|
||||
return;
|
||||
}
|
||||
|
||||
const renderMathInElement = (await import("./services/math.js")).renderMathInElement;
|
||||
renderMathInElement(document.getElementById("content"));
|
||||
}
|
||||
|
||||
async function formatCodeBlocks() {
|
||||
const anyCodeBlock = document.querySelector("#content pre");
|
||||
if (!anyCodeBlock) {
|
||||
return;
|
||||
}
|
||||
await ensureJQuery();
|
||||
const { formatCodeBlocks } = await import("./services/syntax_highlight.js");
|
||||
await formatCodeBlocks($("#content"));
|
||||
}
|
||||
|
||||
async function setupTextNote() {
|
||||
formatCodeBlocks();
|
||||
applyMath();
|
||||
|
||||
const setupMermaid = (await import("./share/mermaid.js")).default;
|
||||
setupMermaid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch note with given ID from backend
|
||||
*
|
||||
* @param noteId of the given note to be fetched. If false, fetches current note.
|
||||
*/
|
||||
async function fetchNote(noteId: string | null = null) {
|
||||
if (!noteId) {
|
||||
noteId = document.body.getAttribute("data-note-id");
|
||||
}
|
||||
|
||||
const resp = await fetch(`api/notes/${noteId}`);
|
||||
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
document.addEventListener(
|
||||
"DOMContentLoaded",
|
||||
() => {
|
||||
const noteType = determineNoteType();
|
||||
|
||||
if (noteType === "text") {
|
||||
setupTextNote();
|
||||
}
|
||||
|
||||
const toggleMenuButton = document.getElementById("toggleMenuButton");
|
||||
const layout = document.getElementById("layout");
|
||||
|
||||
if (toggleMenuButton && layout) {
|
||||
toggleMenuButton.addEventListener("click", () => layout.classList.toggle("showMenu"));
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
function determineNoteType() {
|
||||
const bodyClass = document.body.className;
|
||||
const match = bodyClass.match(/type-([^\s]+)/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
// workaround to prevent webpack from removing "fetchNote" as dead code:
|
||||
// add fetchNote as property to the window object
|
||||
Object.defineProperty(window, "fetchNote", {
|
||||
value: fetchNote
|
||||
});
|
||||
@@ -1,12 +1,7 @@
|
||||
export default async function setupMermaid() {
|
||||
const mermaidEls = document.querySelectorAll("#content pre code.language-mermaid");
|
||||
if (mermaidEls.length === 0) {
|
||||
return;
|
||||
}
|
||||
import mermaid from "mermaid";
|
||||
|
||||
const mermaid = (await import("mermaid")).default;
|
||||
|
||||
for (const codeBlock of mermaidEls) {
|
||||
export default function setupMermaid() {
|
||||
for (const codeBlock of document.querySelectorAll("#content pre code.language-mermaid")) {
|
||||
const parentPre = codeBlock.parentElement;
|
||||
if (!parentPre) {
|
||||
continue;
|
||||
@@ -1809,15 +1809,12 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
}
|
||||
|
||||
.note-split {
|
||||
/* Limits the maximum width of the note */
|
||||
--max-content-width: var(--preferred-max-content-width);
|
||||
|
||||
margin-inline-start: auto;
|
||||
margin-inline-end: auto;
|
||||
}
|
||||
|
||||
.note-split.full-content-width {
|
||||
--max-content-width: unset;
|
||||
max-width: 999999px;
|
||||
}
|
||||
|
||||
button.close:hover {
|
||||
@@ -2037,17 +2034,13 @@ body.zen #right-pane,
|
||||
body.zen #mobile-sidebar-wrapper,
|
||||
body.zen .tab-row-container,
|
||||
body.zen .tab-row-widget,
|
||||
body.zen .shared-info-widget,
|
||||
body.zen .ribbon-container:not(:has(.classic-toolbar-widget)),
|
||||
body.zen .ribbon-container:has(.classic-toolbar-widget) .ribbon-top-row,
|
||||
body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget)),
|
||||
body.zen .ribbon-container:not(:has(.classic-toolbar-widget.visible)),
|
||||
body.zen .ribbon-container:has(.classic-toolbar-widget.visible) .ribbon-top-row,
|
||||
body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget.visible)),
|
||||
body.zen .note-icon-widget,
|
||||
body.zen .title-row .icon-action,
|
||||
body.zen .read-only-note-info-bar-widget:not(.zen-mode-only),
|
||||
body.zen .promoted-attributes-widget,
|
||||
body.zen .floating-buttons-children > *:not(.bx-edit-alt),
|
||||
body.zen .action-button,
|
||||
body.zen .note-list-widget:not(.full-height) {
|
||||
body.zen .action-button {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -2091,116 +2084,12 @@ body.zen .note-title-widget,
|
||||
body.zen .note-title-widget input {
|
||||
font-size: 1rem !important;
|
||||
background: transparent !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
body.zen #detail-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.zen .note-split:not(.full-content-width) .scrolling-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
scroll-behavior: unset !important;
|
||||
}
|
||||
|
||||
body.zen .note-split:not(.full-content-width) .note-detail {
|
||||
margin: auto;
|
||||
padding-bottom: 25vh;
|
||||
max-width: var(--max-content-width);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.zen .note-split:not(.full-content-width) .scroll-padding-widget {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.zen .note-split.type-text {
|
||||
position: relative;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
|
||||
body.zen:not(.backdrop-effects-disabled) .note-split.type-text .title-row {
|
||||
--start-color: var(--main-background-color);
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background: linear-gradient(var(--start-color) 30%, transparent 100%);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@supports (background: color-mix(in srgb, white, transparent)) {
|
||||
body.zen .note-split.type-text .title-row {
|
||||
--start-color: color-mix(in srgb, var(--main-background-color), transparent 10%);
|
||||
}
|
||||
}
|
||||
|
||||
body.zen .note-split.type-text .scrolling-container {
|
||||
--padding-bottom: 130px; /* Should be enough to avoid caret being hidden by the formatting toolbar */
|
||||
|
||||
/* (Usually) keeps the caret above the fixed toolbar */
|
||||
scroll-padding-bottom: var(--padding-bottom);
|
||||
}
|
||||
|
||||
body.zen:not(.backdrop-effects-disabled) .note-split.type-text .scrolling-container {
|
||||
--padding-top: 50px; /* Should be enough to cover the title row */
|
||||
|
||||
padding-top: var(--padding-top);
|
||||
scroll-padding-top: var(--padding-top);
|
||||
}
|
||||
|
||||
/* Fixed formatting toolbar */
|
||||
|
||||
body.zen .note-split .ribbon-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 20px;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
opacity: 0; /* Hidden unless the current note split is focused */
|
||||
pointer-events: none;
|
||||
transition: opacity 100ms linear;
|
||||
}
|
||||
|
||||
body.zen .note-split:focus-within .ribbon-container {
|
||||
opacity: 1; /* Show when the note split is focused */
|
||||
}
|
||||
|
||||
body.zen .note-split .ribbon-container .ribbon-body {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
body.zen .note-split .ribbon-container .classic-toolbar-widget {
|
||||
margin: auto;
|
||||
width: fit-content;
|
||||
box-shadow: 0px 10px 20px rgba(0, 0, 0, .1);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--main-border-color);
|
||||
padding: 4px;
|
||||
background: var(--menu-background-color);
|
||||
}
|
||||
|
||||
body.zen .note-split:focus-within .ribbon-container .classic-toolbar-widget {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
body.zen .note-split .ribbon-container .classic-toolbar-widget {
|
||||
/* Set the toolbar to full with */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,
|
||||
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw,
|
||||
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw,
|
||||
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme,
|
||||
body.zen .classic-toolbar-widget .ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s {
|
||||
/* Force toolbar items overflow dropdowns open upwards */
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Content renderer */
|
||||
|
||||
footer.file-footer,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
--native-titlebar-background: #00000000;
|
||||
--window-background-color-bgfx: transparent; /* When background effects enabled */
|
||||
|
||||
--main-background-color: #242424;
|
||||
--main-background-color: #272727;
|
||||
--main-text-color: #ccc;
|
||||
--main-border-color: #454545;
|
||||
--subtle-border-color: #313131;
|
||||
@@ -166,9 +166,6 @@
|
||||
--protected-session-active-icon-color: #8edd8e;
|
||||
--sync-status-error-pulse-color: #f47871;
|
||||
|
||||
--center-pane-vert-layout-background-color-bgfx: #0c0c0c69;
|
||||
--center-pane-horiz-layout-background-color-bgfx: #1e1e1ec7;
|
||||
|
||||
--right-pane-heading-color: gray;
|
||||
|
||||
--root-background: var(--left-pane-background-color);
|
||||
@@ -195,9 +192,9 @@
|
||||
--badge-background-color: #ffffff1a;
|
||||
--badge-text-color: var(--muted-text-color);
|
||||
|
||||
--promoted-attribute-card-background-color: #ffffff21;
|
||||
--promoted-attribute-card-shadow: none;
|
||||
|
||||
--promoted-attribute-card-background-color: var(--card-background-color);
|
||||
--promoted-attribute-card-shadow-color: #000000b3;
|
||||
|
||||
--floating-button-shadow-color: #00000080;
|
||||
--floating-button-background-color: #494949d2;
|
||||
--floating-button-color: var(--button-text-color);
|
||||
@@ -211,8 +208,6 @@
|
||||
--floating-button-hide-button-background: #00000029;
|
||||
--floating-button-hide-button-color: #ffffff63;
|
||||
|
||||
--right-pane-background-color: var(--main-background-color);
|
||||
--right-pane-background-color-bgfx: #0c0c0c24; /* Only for the vertical layout */
|
||||
--right-pane-item-hover-background: #ffffff26;
|
||||
--right-pane-item-hover-color: white;
|
||||
|
||||
@@ -232,8 +227,8 @@
|
||||
--card-background-color: #ffffff12;
|
||||
--card-background-hover-color: #3c3c3c;
|
||||
--card-background-press-color: #464646;
|
||||
--card-border-color: transparent;
|
||||
--card-box-shadow: none;
|
||||
--card-border-color: #222222;
|
||||
--card-box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
|
||||
|
||||
--calendar-color: var(--menu-text-color);
|
||||
--calendar-weekday-labels-color: var(--muted-text-color);
|
||||
@@ -299,10 +294,4 @@ body ::-webkit-calendar-picker-indicator {
|
||||
|
||||
body .todo-list input[type="checkbox"]:not(:checked):before {
|
||||
border-color: var(--muted-text-color) !important;
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 8.8%, 11.2%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 9.4%, 25.1%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 13.2%, 20.8%);
|
||||
}
|
||||
@@ -159,9 +159,6 @@
|
||||
--protected-session-active-icon-color: #16b516;
|
||||
--sync-status-error-pulse-color: #ff5528;
|
||||
|
||||
--center-pane-vert-layout-background-color-bgfx: #ffffff75;
|
||||
--center-pane-horiz-layout-background-color-bgfx: #ffffffd6;
|
||||
|
||||
--right-pane-heading-color: gray;
|
||||
|
||||
--root-background: var(--left-pane-background-color);
|
||||
@@ -183,13 +180,13 @@
|
||||
--inactive-tab-hover-background-color: #00000016;
|
||||
--inactive-tab-text-color: #4e4e4e;
|
||||
|
||||
--alert-bar-background: #f9cf2b29;
|
||||
--alert-bar-background: #32637b29;
|
||||
|
||||
--badge-background-color: #00000011;
|
||||
--badge-text-color: var(--muted-text-color);
|
||||
|
||||
--promoted-attribute-card-background-color: #00000014;
|
||||
--promoted-attribute-card-shadow: none;
|
||||
--promoted-attribute-card-background-color: var(--card-background-color);
|
||||
--promoted-attribute-card-shadow-color: #00000033;
|
||||
|
||||
--floating-button-shadow-color: #00000042;
|
||||
--floating-button-background-color: #eaeaeacc;
|
||||
@@ -210,8 +207,6 @@
|
||||
--new-tab-button-hover-background: white;
|
||||
--new-tab-button-hover-color: black;
|
||||
|
||||
--right-pane-background-color: var(--main-background-color);
|
||||
--right-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx); /* Only for the vertical layout */
|
||||
--right-pane-item-hover-background: #ececec;
|
||||
--right-pane-item-hover-color: inherit;
|
||||
|
||||
@@ -228,12 +223,12 @@
|
||||
|
||||
--code-block-box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1), 0px 0px 2px rgba(0, 0, 0, 0.2);
|
||||
|
||||
--card-background-color: #0000000d;
|
||||
--card-background-color: var(--accented-background-color);
|
||||
--card-background-hover-color: #f9f9f9;
|
||||
--card-background-press-color: #efefef;
|
||||
--card-border-color: transparent;
|
||||
--card-border-color: #eaeaea;
|
||||
--card-shadow-color: rgba(0, 0, 0, 0.1);
|
||||
--card-box-shadow: none;
|
||||
--card-box-shadow: 0 0 12px var(--card-shadow-color);
|
||||
|
||||
--calendar-color: var(--menu-text-color);
|
||||
--calendar-weekday-labels-color: var(--muted-text-color);
|
||||
@@ -275,10 +270,4 @@
|
||||
* The --custom-color-hue variable contains the hue of the user-selected note color.
|
||||
* This value is unset for gray tones. */
|
||||
--custom-bg-color: hsl(var(--custom-color-hue), 37%, 89%, 1);
|
||||
}
|
||||
|
||||
.tinted-quick-edit-dialog {
|
||||
--modal-background-color: hsl(var(--custom-color-hue), 56%, 96%);
|
||||
--modal-border-color: hsl(var(--custom-color-hue), 33%, 41%);
|
||||
--promoted-attribute-card-background-color: hsl(var(--custom-color-hue), 40%, 88%);
|
||||
}
|
||||
@@ -82,7 +82,6 @@
|
||||
|
||||
/* Theme capabilities */
|
||||
--tab-note-icons: true;
|
||||
--allow-background-effects: true;
|
||||
|
||||
/* To ensure that a tree item's custom color remains sufficiently contrasted and readable,
|
||||
* the color is adjusted based on the current color scheme (light or dark). The lightness
|
||||
@@ -132,8 +131,7 @@ body.mobile .dropdown-menu .dropdown-menu {
|
||||
|
||||
body.desktop .dropdown-menu::before,
|
||||
:root .ck.ck-dropdown__panel::before,
|
||||
:root .excalidraw .popover::before,
|
||||
body.zen .note-split .ribbon-container .classic-toolbar-widget::before {
|
||||
:root .excalidraw .popover::before {
|
||||
content: "";
|
||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||
border-radius: var(--dropdown-border-radius);
|
||||
|
||||
@@ -148,7 +148,7 @@ div.note-detail-empty {
|
||||
--options-card-min-width: 500px;
|
||||
--options-card-max-width: 900px;
|
||||
--options-card-padding: 17px;
|
||||
--options-title-font-size: .75rem;
|
||||
--options-title-font-size: 1rem;
|
||||
--options-title-offset: 13px;
|
||||
}
|
||||
/* Create a gap at the top of the option pages */
|
||||
@@ -173,19 +173,16 @@ div.note-detail-empty {
|
||||
}
|
||||
|
||||
.options-section:not(.tn-no-card) {
|
||||
margin-bottom: calc(var(--options-title-offset) + 26px) !important;
|
||||
box-shadow: var(--card-box-shadow);
|
||||
margin: auto;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--card-border-color) !important;
|
||||
border-radius: 8px;
|
||||
box-shadow: var(--card-box-shadow);
|
||||
background: var(--card-background-color);
|
||||
padding: var(--options-card-padding);
|
||||
margin-bottom: calc(var(--options-title-offset) + 26px) !important;
|
||||
}
|
||||
|
||||
body.prefers-centered-content .options-section:not(.tn-no-card) {
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
body.desktop .options-section:not(.tn-no-card) {
|
||||
body.desktop .option-section:not(.tn-no-card) {
|
||||
min-width: var(--options-card-min-width);
|
||||
max-width: var(--options-card-max-width);
|
||||
}
|
||||
@@ -196,16 +193,9 @@ body.desktop .options-section:not(.tn-no-card) {
|
||||
padding-bottom: var(--default-padding);
|
||||
}
|
||||
|
||||
.options-section:not(.tn-no-card) h4,
|
||||
.options-section:not(.tn-no-card) h5 {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .4pt;
|
||||
}
|
||||
|
||||
|
||||
.options-section:not(.tn-no-card) h4 {
|
||||
font-size: var(--options-title-font-size);
|
||||
font-weight: 600;
|
||||
font-weight: bold;
|
||||
color: var(--launcher-pane-text-color);
|
||||
margin-top: calc(-1 * var(--options-card-padding) - var(--options-title-font-size) - var(--options-title-offset)) !important;
|
||||
margin-bottom: calc(var(--options-title-offset) + var(--options-card-padding)) !important;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
div.promoted-attributes-container {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
margin-inline-start: 12px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--dropdown-backdrop-filter: blur(20px) saturate(6);
|
||||
--dropdown-backdrop-filter: blur(10px) saturate(6);
|
||||
--dropdown-border-radius: 10px;
|
||||
}
|
||||
|
||||
@@ -35,52 +35,30 @@ body.mobile {
|
||||
}
|
||||
|
||||
/* #region Mica */
|
||||
|
||||
body.background-effects.platform-win32 {
|
||||
/* Quirk: --background-material is read before "theme-supports-background-effects" class
|
||||
* is applied. Apply the matterial even if the theme doesn't support it. */
|
||||
--background-material: tabbed;
|
||||
}
|
||||
|
||||
body.background-effects.theme-supports-background-effects.platform-win32 {
|
||||
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
|
||||
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
|
||||
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx);
|
||||
--tab-background-color: var(--window-background-color-bgfx);
|
||||
--new-tab-button-background: var(--window-background-color-bgfx);
|
||||
--active-tab-background-color: var(--launcher-pane-horiz-background-color);
|
||||
--root-background: transparent;
|
||||
}
|
||||
|
||||
body.background-effects.platform-win32.layout-vertical {
|
||||
--left-pane-background-color: var(--window-background-color-bgfx);
|
||||
--background-material: mica;
|
||||
}
|
||||
|
||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical {
|
||||
--left-pane-background-color: var(--window-background-color-bgfx);
|
||||
--center-pane-background-color-bgfx: var(--center-pane-vert-layout-background-color-bgfx);
|
||||
--right-pane-background-color: var(--right-pane-background-color-bgfx);
|
||||
}
|
||||
|
||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal {
|
||||
--center-pane-background-color-bgfx: var(--center-pane-horiz-layout-background-color-bgfx);
|
||||
}
|
||||
|
||||
body.background-effects.theme-supports-background-effects.platform-win32,
|
||||
body.background-effects.theme-supports-background-effects.platform-win32 #root-widget {
|
||||
body.background-effects.platform-win32,
|
||||
body.background-effects.platform-win32 #root-widget {
|
||||
background: var(--window-background-color-bgfx) !important;
|
||||
}
|
||||
|
||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-horizontal #horizontal-main-container,
|
||||
body.background-effects.theme-supports-background-effects.platform-win32.layout-vertical #vertical-main-container {
|
||||
body.background-effects.platform-win32.layout-horizontal #horizontal-main-container,
|
||||
body.background-effects.platform-win32.layout-vertical #vertical-main-container {
|
||||
background-color: var(--root-background);
|
||||
}
|
||||
|
||||
/* Note split with background effects */
|
||||
body.background-effects.theme-supports-background-effects.platform-win32 #center-pane .note-split.bgfx {
|
||||
--note-split-background-color: var(--center-pane-background-color-bgfx);
|
||||
}
|
||||
|
||||
/* #endregion */
|
||||
|
||||
/* Matches when the left pane is collapsed */
|
||||
@@ -94,21 +72,9 @@ body.layout-vertical #horizontal-main-container.left-pane-hidden #launcher-pane.
|
||||
border-inline-end: 2px solid var(--left-pane-collapsed-border-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Zen mode
|
||||
*/
|
||||
|
||||
@keyframes zen-formatting-toolbar-entrance {
|
||||
from {
|
||||
transform: translateY(200%);
|
||||
} to {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
body.zen .note-split .ribbon-container .classic-toolbar-widget {
|
||||
position: relative;
|
||||
animation: zen-formatting-toolbar-entrance 300ms ease-out;
|
||||
body.background-effects.zen #root-widget {
|
||||
--main-background-color: transparent;
|
||||
--root-background: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1205,18 +1171,23 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
|
||||
* CENTER PANE
|
||||
*/
|
||||
|
||||
/* The first visible note split */
|
||||
.vertical-layout #center-pane .note-split:not(.visible ~ .visible) {
|
||||
#center-pane {
|
||||
background: var(--main-background-color);
|
||||
}
|
||||
|
||||
.vertical-layout #center-pane {
|
||||
border-radius: var(--center-pane-border-radius) 0 0 0;
|
||||
}
|
||||
|
||||
#center-pane .note-split {
|
||||
.note-split {
|
||||
padding-top: 2px;
|
||||
background-color: var(--note-split-background-color, var(--main-background-color));
|
||||
animation: note-entrance 100ms linear;
|
||||
/* will-change: opacity; -- causes some weird artifacts to the note menu in split view */
|
||||
}
|
||||
|
||||
body:not(.background-effects) #center-pane .note-split {
|
||||
animation: note-entrance 100ms linear;
|
||||
.split-note-container-widget > .gutter {
|
||||
background: var(--root-background) !important;
|
||||
transition: background 150ms ease-out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1229,9 +1200,9 @@ body:not(.background-effects) #center-pane .note-split {
|
||||
|
||||
@keyframes note-entrance {
|
||||
from {
|
||||
filter: opacity(0);
|
||||
opacity: 0;
|
||||
} to {
|
||||
filter: opacity(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,14 +1299,6 @@ body.mobile .note-title {
|
||||
border-bottom: 2px solid #0000001c !important;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-only note info bar
|
||||
*/
|
||||
|
||||
.read-only-note-info-bar-widget {
|
||||
--link-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
/*
|
||||
* Promoted attributes
|
||||
*/
|
||||
@@ -1365,7 +1328,8 @@ div.promoted-attribute-cell {
|
||||
--pa-card-padding-inline-end: 2px;
|
||||
--input-background-color: transparent;
|
||||
|
||||
box-shadow: var(--promoted-attribute-card-shadow);
|
||||
box-shadow: 1px 1px 2px var(--promoted-attribute-card-shadow-color);
|
||||
|
||||
display: inline-flex;
|
||||
margin: 0;
|
||||
border-radius: 8px;
|
||||
@@ -1752,7 +1716,7 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
|
||||
*/
|
||||
|
||||
#right-pane {
|
||||
background: var(--right-pane-background-color);
|
||||
background: var(--main-background-color);
|
||||
}
|
||||
|
||||
#right-pane div.card-header {
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "خطأ فادح"
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "فشل في البدء بعنصر الواجهة"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
@@ -29,8 +26,7 @@
|
||||
"edit_branch_prefix": "تعديل بادئة الفرع",
|
||||
"prefix": "البادئة: ",
|
||||
"save": "حفظ",
|
||||
"help_on_tree_prefix": "مساعدة حول بادئة الشجرة",
|
||||
"branch_prefix_saved": "تم حفظ بادئة الفرع."
|
||||
"help_on_tree_prefix": "مساعدة حول بادئة الشجرة"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "اجراءات جماعية",
|
||||
@@ -87,8 +83,7 @@
|
||||
"workspace_calendar_root": "تحديد جذر التقويم لكل مساحة عمل",
|
||||
"hide_highlight_widget": "اخفاء عنصر واجهة قائمة التمييزات",
|
||||
"is_owned_by_note": "تخص الملاحظة",
|
||||
"and_more": "... و {{count}}مرات اكثر.",
|
||||
"related_notes_title": "ملاحظات اخرى بنفس التسمية"
|
||||
"and_more": "... و {{count}}مرات اكثر."
|
||||
},
|
||||
"rename_label": {
|
||||
"to": "الى",
|
||||
@@ -132,9 +127,7 @@
|
||||
"delete_attachment": "حذف المرفق",
|
||||
"upload_new_revision": "رفع مراجعة جديدة",
|
||||
"copy_link_to_clipboard": "نسخ الرابط الى الحافظة",
|
||||
"convert_attachment_into_note": "تحويل المرفق الى ملاحظة",
|
||||
"delete_success": "تم حذف المرفق \"{{title}}\" .",
|
||||
"enter_new_name": "ادخل اسم مرفق جديد"
|
||||
"convert_attachment_into_note": "تحويل المرفق الى ملاحظة"
|
||||
},
|
||||
"calendar": {
|
||||
"week": "أسبوع",
|
||||
@@ -266,8 +259,7 @@
|
||||
"note_paths": {
|
||||
"search": "بحث",
|
||||
"archived": "مؤرشف",
|
||||
"title": "مسارات الملاحظة",
|
||||
"clone_button": "جار نسخ الملاحظة الى مكان جديد..."
|
||||
"title": "مسارات الملاحظة"
|
||||
},
|
||||
"script_executor": {
|
||||
"query": "استعلام",
|
||||
@@ -380,8 +372,7 @@
|
||||
"export_note_title": "تصدير الملاحظة",
|
||||
"export_status": "حالة التصدير",
|
||||
"export_finished_successfully": "اكتمل التصدير بنجاح.",
|
||||
"export_in_progress": "جار التصدير: {{progressCount}}",
|
||||
"choose_export_type": "اختر نوع التصدير اولا من فضلك"
|
||||
"export_in_progress": "جار التصدير: {{progressCount}}"
|
||||
},
|
||||
"help": {
|
||||
"troubleshooting": "أستكشاف الاخطاء واصلاحها",
|
||||
@@ -411,10 +402,7 @@
|
||||
"movingCloningNotes": "نقل/ استنساخ الملاحظات",
|
||||
"deleteNotes": "حذف الملاحظة/ الشجرة الفرعية",
|
||||
"collapseWholeTree": "طي شجرة الملاحظة باكملها",
|
||||
"followLink": "اتبع تلرابط تحت المؤشر",
|
||||
"onlyInDesktop": "في سطح المكتب فقط(Electron build)",
|
||||
"createEditLink": "انشاء/ تحرير رابط خارجي",
|
||||
"quickSearch": "الانتقال الى مربع البحث السريع"
|
||||
"followLink": "اتبع تلرابط تحت المؤشر"
|
||||
},
|
||||
"import": {
|
||||
"options": "خيارات",
|
||||
@@ -477,13 +465,7 @@
|
||||
"delete_all_button": "حذف كل المراجعات",
|
||||
"settings": "اعدادات مراجعة الملاحظة",
|
||||
"diff_not_available": "المقارنة غير متوفرة.",
|
||||
"help_title": "مساعدة حول مراجعات الملاحظة",
|
||||
"diff_off_hint": "انقر لعرض محتويات الملاحظة",
|
||||
"revisions_deleted": "تم حذف جميع نسخ المراجعات للملاحظة.",
|
||||
"revision_restored": "تم استعادة نسخ المراجعة للملاحظة.",
|
||||
"revision_deleted": "تم حذف مراجعة الملاحظة.",
|
||||
"snapshot_interval": "فاصل زمني لحفظ لقطات اصدارات المراجعة: {{seconds}}",
|
||||
"maximum_revisions": "حد عدد لقطات اصدارات الملاحظة: {{number}}"
|
||||
"help_title": "مساعدة حول مراجعات الملاحظة"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"title": "عنوان",
|
||||
@@ -497,15 +479,13 @@
|
||||
"sorting_direction": "اتجاه الترتيب",
|
||||
"natural_sort": "الترتيب الطبيعي",
|
||||
"natural_sort_language": "لغات الترتيب الطبيعي",
|
||||
"sort_children_by": "ترتيب العناصر الفرعية حسب...",
|
||||
"sort_folders_at_top": "ترتيب المجلدات في الاعلى"
|
||||
"sort_children_by": "ترتيب العناصر الفرعية حسب..."
|
||||
},
|
||||
"recent_changes": {
|
||||
"undelete_link": "الغاء الحذف",
|
||||
"title": "التغيرات الاخيرة",
|
||||
"no_changes_message": "لايوجد تغيير لحد الان...",
|
||||
"erase_notes_button": "مسح الملاحظات المحذوفة الان",
|
||||
"deleted_notes_message": "تم حذف الملاحظات نهائيا."
|
||||
"erase_notes_button": "مسح الملاحظات المحذوفة الان"
|
||||
},
|
||||
"edited_notes": {
|
||||
"deleted": "(حذف)",
|
||||
@@ -520,7 +500,9 @@
|
||||
"max_content_width": {
|
||||
"max_width_unit": "بكسل",
|
||||
"title": "عرض المحتوى",
|
||||
"max_width_label": "اقصى عرض للمحتوى"
|
||||
"reload_button": "اعادة تحميل الواجهة",
|
||||
"max_width_label": "اقصى عرض للمحتوى",
|
||||
"reload_description": "تغييرات من خيارات المظهر"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"enabled": "مفعل",
|
||||
@@ -714,6 +696,7 @@
|
||||
"backup_database_now": "نسخ اختياطي لقاعدة البيانات الان"
|
||||
},
|
||||
"etapi": {
|
||||
"wiki": "ويكي",
|
||||
"created": "تم الأنشاء",
|
||||
"actions": "أجراءات",
|
||||
"title": "ETAPI",
|
||||
@@ -722,9 +705,7 @@
|
||||
"default_token_name": "رمز جديد",
|
||||
"rename_token_title": "اعادة تسمية الرمز",
|
||||
"rename_token": "اعادة تسمية هذا الرمز",
|
||||
"create_token": "انشاء رمز PEAPI جديد",
|
||||
"new_token_title": "رمز ETAPI جديد",
|
||||
"token_created_title": "انشاء رمز ETAPI"
|
||||
"create_token": "انشاء رمز PEAPI جديد"
|
||||
},
|
||||
"password": {
|
||||
"heading": "كلمة المرور",
|
||||
@@ -830,8 +811,7 @@
|
||||
"help_on_links": "مساعدة حول الارتباطات التشعبية",
|
||||
"notes_to_clone": "ملاحظات للنسخ",
|
||||
"target_parent_note": "الملاحظة الاصلية الهدف",
|
||||
"clone_to_selected_note": "استنساخ الى الملاحظة المحددة",
|
||||
"no_path_to_clone_to": "لايوجد مسار لنسخ المحتوى الية."
|
||||
"clone_to_selected_note": "استنساخ الى الملاحظة المحددة"
|
||||
},
|
||||
"table_of_contents": {
|
||||
"unit": "عناوين",
|
||||
@@ -1049,8 +1029,7 @@
|
||||
},
|
||||
"delete_note": {
|
||||
"delete_note": "حذف الملاحظة",
|
||||
"delete_matched_notes": "حف الملاحظات المطابقة",
|
||||
"delete_matched_notes_description": "سوف يؤدي هذا الى حذف الملاحظات المطابقة."
|
||||
"delete_matched_notes": "حف الملاحظات المطابقة"
|
||||
},
|
||||
"rename_note": {
|
||||
"rename_note": "اعادة تسمية الملاحظة",
|
||||
@@ -1333,8 +1312,7 @@
|
||||
"notes_to_move": "الملاحظات المراد نقلها",
|
||||
"target_parent_note": "ملاحظة الاصل الهدف",
|
||||
"dialog_title": "انقل الملاحظات الى...",
|
||||
"move_button": "نقل الىالملاحظة المحددة",
|
||||
"error_no_path": "لايوجد مسار لنقل العنصر الية."
|
||||
"move_button": "نقل الىالملاحظة المحددة"
|
||||
},
|
||||
"delete_revisions": {
|
||||
"delete_note_revisions": "حذف مراجعات الملاحظة"
|
||||
@@ -1385,8 +1363,7 @@
|
||||
"save_attributes": "حفظ السمات <enter>",
|
||||
"add_a_new_attribute": "اضافة سمة جديدة",
|
||||
"add_new_label_definition": "اضافة تعريف لتسمية جديدة",
|
||||
"add_new_relation_definition": "اضافة تعريف لعلاقة جديدة",
|
||||
"add_new_relation": "اضافة علاقة جديدة <kbd data-command=\"addNewRelation\">"
|
||||
"add_new_relation_definition": "اضافة تعريف لعلاقة جديدة"
|
||||
},
|
||||
"zen_mode": {
|
||||
"button_exit": "الخروج من وضع Zen"
|
||||
@@ -1457,8 +1434,5 @@
|
||||
},
|
||||
"png_export_button": {
|
||||
"button_title": "تصدير المخطط كملف PNG"
|
||||
},
|
||||
"protected_session_status": {
|
||||
"inactive": "انقر للدخول الى جلسة محمية"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"bulk_actions_executed": "批量操作已成功执行。",
|
||||
"none_yet": "暂无操作 ... 通过点击上方的可用操作添加一个操作。",
|
||||
"labels": "标签",
|
||||
"relations": "关系",
|
||||
"relations": "关联关系",
|
||||
"notes": "笔记",
|
||||
"other": "其它"
|
||||
},
|
||||
@@ -104,8 +104,7 @@
|
||||
"export_status": "导出状态",
|
||||
"export_in_progress": "导出进行中:{{progressCount}}",
|
||||
"export_finished_successfully": "导出成功完成。",
|
||||
"format_pdf": "PDF - 用于打印或共享目的。",
|
||||
"share-format": "HTML 网页发布——采用与共享笔记相同的主题,但可发布为静态网站。"
|
||||
"format_pdf": "PDF - 用于打印或共享目的。"
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "笔记导航",
|
||||
@@ -185,8 +184,7 @@
|
||||
},
|
||||
"import-status": "导入状态",
|
||||
"in-progress": "导入进行中:{{progress}}",
|
||||
"successful": "导入成功完成。",
|
||||
"importZipRecommendation": "导入 ZIP 文件时,笔记层级将反映压缩文件内的子目录结构。"
|
||||
"successful": "导入成功完成。"
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "包含笔记",
|
||||
@@ -261,6 +259,7 @@
|
||||
"delete_all_revisions": "删除此笔记的所有修订版本",
|
||||
"delete_all_button": "删除所有修订版本",
|
||||
"help_title": "关于笔记修订版本的帮助",
|
||||
"revision_last_edited": "此修订版本上次编辑于 {{date}}",
|
||||
"confirm_delete_all": "您是否要删除此笔记的所有修订版本?",
|
||||
"no_revisions": "此笔记暂无修订版本...",
|
||||
"restore_button": "恢复",
|
||||
@@ -1107,6 +1106,9 @@
|
||||
"title": "内容宽度",
|
||||
"default_description": "Trilium默认会限制内容的最大宽度以提高在宽屏中全屏时的可读性。",
|
||||
"max_width_label": "内容最大宽度(像素)",
|
||||
"apply_changes_description": "要应用内容宽度更改,请点击",
|
||||
"reload_button": "重载前端",
|
||||
"reload_description": "来自外观选项的更改",
|
||||
"max_width_unit": "像素"
|
||||
},
|
||||
"native_title_bar": {
|
||||
@@ -1286,6 +1288,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI 是一个 REST API,用于以编程方式访问 Trilium 实例,而无需 UI。",
|
||||
"see_more": "有关更多详细信息,请参见 {{- link_to_wiki}} 和 {{- link_to_openapi_spec}} 或 {{- link_to_swagger_ui}}。",
|
||||
"wiki": "维基",
|
||||
"openapi_spec": "ETAPI OpenAPI 规范",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "创建新的 ETAPI 令牌",
|
||||
"existing_tokens": "现有令牌",
|
||||
"no_tokens_yet": "目前还没有令牌。点击上面的按钮创建一个。",
|
||||
@@ -1552,9 +1558,7 @@
|
||||
"window-on-top": "保持此窗口置顶"
|
||||
},
|
||||
"note_detail": {
|
||||
"could_not_find_typewidget": "找不到类型为 '{{type}}' 的 typeWidget",
|
||||
"printing": "正在打印…",
|
||||
"printing_pdf": "正在导出为PDF…"
|
||||
"could_not_find_typewidget": "找不到类型为 '{{type}}' 的 typeWidget"
|
||||
},
|
||||
"note_title": {
|
||||
"placeholder": "请输入笔记标题..."
|
||||
@@ -1914,7 +1918,7 @@
|
||||
},
|
||||
"custom_date_time_format": {
|
||||
"title": "自定义日期/时间格式",
|
||||
"description": "自定义通过 <shortcut /> 或工具栏插入的日期和时间格式。有关日期/时间格式字符串中各个字符的含义,请参阅<doc>Day.js docs</doc>。",
|
||||
"description": "通过<shortcut />或工具栏的方式可自定义日期和时间格式,有关日期/时间格式字符串中各个字符的含义,请参阅<doc>Day.js docs</doc>。",
|
||||
"format_string": "日期/时间格式字符串:",
|
||||
"formatted_time": "格式化后日期/时间:"
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "Startseite:",
|
||||
"app_version": "App-Version:",
|
||||
"db_version": "DB-Version:",
|
||||
"sync_version": "Sync-Version:",
|
||||
"sync_version": "Synch-version:",
|
||||
"build_date": "Build-Datum:",
|
||||
"build_revision": "Build-Revision:",
|
||||
"data_directory": "Datenverzeichnis:"
|
||||
@@ -104,8 +104,7 @@
|
||||
"export_status": "Exportstatus",
|
||||
"export_in_progress": "Export läuft: {{progressCount}}",
|
||||
"export_finished_successfully": "Der Export wurde erfolgreich abgeschlossen.",
|
||||
"format_pdf": "PDF - für Ausdrucke oder Teilen.",
|
||||
"share-format": "HTML für die Web-Veröffentlichung – verwendet dasselbe Theme wie bei freigegebenen Notizen, kann jedoch als statische Website veröffentlicht werden."
|
||||
"format_pdf": "PDF - für Ausdrucke oder Teilen."
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "Notiz Navigation",
|
||||
@@ -185,8 +184,7 @@
|
||||
},
|
||||
"import-status": "Importstatus",
|
||||
"in-progress": "Import läuft: {{progress}}",
|
||||
"successful": "Import erfolgreich abgeschlossen.",
|
||||
"importZipRecommendation": "Beim Import einer ZIP-Datei wird die Notizhierarchie aus der Ordnerstruktur im Archiv übernommen."
|
||||
"successful": "Import erfolgreich abgeschlossen."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Notiz beifügen",
|
||||
@@ -261,6 +259,7 @@
|
||||
"delete_all_revisions": "Lösche alle Revisionen dieser Notiz",
|
||||
"delete_all_button": "Alle Revisionen löschen",
|
||||
"help_title": "Hilfe zu Notizrevisionen",
|
||||
"revision_last_edited": "Diese Revision wurde zuletzt am {{date}} bearbeitet",
|
||||
"confirm_delete_all": "Möchtest du alle Revisionen dieser Notiz löschen?",
|
||||
"no_revisions": "Für diese Notiz gibt es noch keine Revisionen...",
|
||||
"confirm_restore": "Möchtest du diese Revision wiederherstellen? Dadurch werden der aktuelle Titel und Inhalt der Notiz mit dieser Revision überschrieben.",
|
||||
@@ -648,8 +647,7 @@
|
||||
"logout": "Abmelden",
|
||||
"show-cheatsheet": "Cheatsheet anzeigen",
|
||||
"toggle-zen-mode": "Zen Modus",
|
||||
"new-version-available": "Neues Update verfügbar",
|
||||
"download-update": "Version {{latestVersion}} herunterladen"
|
||||
"new-version-available": "Neues Update verfügbar"
|
||||
},
|
||||
"sync_status": {
|
||||
"unknown": "<p>Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.</p><p>Klicke, um eine Synchronisierung jetzt auszulösen.</p>",
|
||||
@@ -991,7 +989,7 @@
|
||||
"enter_password_instruction": "Um die geschützte Notiz anzuzeigen, musst du dein Passwort eingeben:",
|
||||
"start_session_button": "Starte eine geschützte Sitzung <kbd>Eingabetaste</kbd>",
|
||||
"started": "Geschützte Sitzung gestartet.",
|
||||
"wrong_password": "Passwort falsch.",
|
||||
"wrong_password": "Passwort flasch.",
|
||||
"protecting-finished-successfully": "Geschützt erfolgreich beendet.",
|
||||
"unprotecting-finished-successfully": "Ungeschützt erfolgreich beendet.",
|
||||
"protecting-in-progress": "Schützen läuft: {{count}}",
|
||||
@@ -1104,6 +1102,9 @@
|
||||
"title": "Inhaltsbreite",
|
||||
"default_description": "Trilium begrenzt standardmäßig die maximale Inhaltsbreite, um die Lesbarkeit für maximierte Bildschirme auf Breitbildschirmen zu verbessern.",
|
||||
"max_width_label": "Maximale Inhaltsbreite in Pixel",
|
||||
"apply_changes_description": "Um Änderungen an der Inhaltsbreite anzuwenden, klicke auf",
|
||||
"reload_button": "Frontend neu laden",
|
||||
"reload_description": "Änderungen an den Darstellungsoptionen",
|
||||
"max_width_unit": "Pixel"
|
||||
},
|
||||
"native_title_bar": {
|
||||
@@ -1283,6 +1284,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI ist eine REST-API, die für den programmgesteuerten Zugriff auf die Trilium-Instanz ohne Benutzeroberfläche verwendet wird.",
|
||||
"see_more": "Weitere Details können im {{- link_to_wiki}} und in der {{- link_to_openapi_spec}} oder der {{- link_to_swagger_ui }} gefunden werden.",
|
||||
"wiki": "Wiki",
|
||||
"openapi_spec": "ETAPI OpenAPI-Spezifikation",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Erstelle ein neues ETAPI-Token",
|
||||
"existing_tokens": "Vorhandene Token",
|
||||
"no_tokens_yet": "Es sind noch keine Token vorhanden. Klicke auf die Schaltfläche oben, um eine zu erstellen.",
|
||||
@@ -1516,9 +1521,7 @@
|
||||
"window-on-top": "Dieses Fenster immer oben halten"
|
||||
},
|
||||
"note_detail": {
|
||||
"could_not_find_typewidget": "Konnte typeWidget für Typ ‚{{type}}‘ nicht finden",
|
||||
"printing": "Druckvorgang läuft…",
|
||||
"printing_pdf": "PDF-Export läuft…"
|
||||
"could_not_find_typewidget": "Konnte typeWidget für Typ ‚{{type}}‘ nicht finden"
|
||||
},
|
||||
"note_title": {
|
||||
"placeholder": "Titel der Notiz hier eingeben…"
|
||||
@@ -1651,7 +1654,7 @@
|
||||
"add-term-to-dictionary": "Begriff \"{{term}}\" zum Wörterbuch hinzufügen",
|
||||
"cut": "Ausschneiden",
|
||||
"copy": "Kopieren",
|
||||
"copy-link": "Link kopieren",
|
||||
"copy-link": "Link opieren",
|
||||
"paste": "Einfügen",
|
||||
"paste-as-plain-text": "Als unformatierten Text einfügen",
|
||||
"search_online": "Suche nach \"{{term}}\" mit {{searchEngine}} starten"
|
||||
@@ -2076,7 +2079,6 @@
|
||||
},
|
||||
"presentation_view": {
|
||||
"edit-slide": "Folie bearbeiten",
|
||||
"start-presentation": "Präsentation starten",
|
||||
"slide-overview": "Übersicht der Folien ein-/ausblenden"
|
||||
"start-presentation": "Präsentation starten"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,13 +36,10 @@
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Edit branch prefix",
|
||||
"edit_branch_prefix_multiple": "Edit branch prefix for {{count}} branches",
|
||||
"help_on_tree_prefix": "Help on Tree prefix",
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Save",
|
||||
"branch_prefix_saved": "Branch prefix has been saved.",
|
||||
"branch_prefix_saved_multiple": "Branch prefix has been saved for {{count}} branches.",
|
||||
"affected_branches": "Affected branches ({{count}}):"
|
||||
"branch_prefix_saved": "Branch prefix has been saved."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Bulk actions",
|
||||
@@ -107,8 +104,7 @@
|
||||
"export_status": "Export status",
|
||||
"export_in_progress": "Export in progress: {{progressCount}}",
|
||||
"export_finished_successfully": "Export finished successfully.",
|
||||
"format_pdf": "PDF - for printing or sharing purposes.",
|
||||
"share-format": "HTML for web publishing - uses the same theme that is used shared notes, but can be published as a static website."
|
||||
"format_pdf": "PDF - for printing or sharing purposes."
|
||||
},
|
||||
"help": {
|
||||
"title": "Cheatsheet",
|
||||
@@ -264,6 +260,7 @@
|
||||
"delete_all_revisions": "Delete all revisions of this note",
|
||||
"delete_all_button": "Delete all revisions",
|
||||
"help_title": "Help on Note Revisions",
|
||||
"revision_last_edited": "This revision was last edited on {{date}}",
|
||||
"confirm_delete_all": "Do you want to delete all revisions of this note?",
|
||||
"no_revisions": "No revisions for this note yet...",
|
||||
"restore_button": "Restore",
|
||||
@@ -1111,7 +1108,9 @@
|
||||
"default_description": "Trilium by default limits max content width to improve readability for maximized screens on wide screens.",
|
||||
"max_width_label": "Max content width",
|
||||
"max_width_unit": "pixels",
|
||||
"centerContent": "Keep content centered"
|
||||
"apply_changes_description": "To apply content width changes, click on",
|
||||
"reload_button": "reload frontend",
|
||||
"reload_description": "changes from appearance options"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Native Title Bar (requires app restart)",
|
||||
@@ -1454,6 +1453,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI is a REST API used to access Trilium instance programmatically, without UI.",
|
||||
"see_more": "See more details in the {{- link_to_wiki}} and the {{- link_to_openapi_spec}} or the {{- link_to_swagger_ui }}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "ETAPI OpenAPI spec",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Create new ETAPI token",
|
||||
"existing_tokens": "Existing tokens",
|
||||
"no_tokens_yet": "There are no tokens yet. Click on the button above to create one.",
|
||||
@@ -1637,12 +1640,6 @@
|
||||
"shared_locally": "This note is shared locally on {{- link}}.",
|
||||
"help_link": "For help visit <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
|
||||
},
|
||||
"read-only-info": {
|
||||
"read-only-note": "Currently viewing a read-only note.",
|
||||
"auto-read-only-note": "This note is shown in a read-only mode for faster loading.",
|
||||
"auto-read-only-learn-more": "Learn more",
|
||||
"edit-note": "Edit note"
|
||||
},
|
||||
"note_types": {
|
||||
"text": "Text",
|
||||
"code": "Code",
|
||||
@@ -2041,9 +2038,6 @@
|
||||
"start-presentation": "Start presentation",
|
||||
"slide-overview": "Toggle an overview of the slides"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "Delete note..."
|
||||
},
|
||||
"command_palette": {
|
||||
"tree-action-name": "Tree: {{name}}",
|
||||
"export_note_title": "Export Note",
|
||||
|
||||
@@ -104,8 +104,7 @@
|
||||
"export_status": "Estado de exportación",
|
||||
"export_in_progress": "Exportación en curso: {{progressCount}}",
|
||||
"export_finished_successfully": "La exportación finalizó exitosamente.",
|
||||
"format_pdf": "PDF - para propósitos de impresión o compartición.",
|
||||
"share-format": "HTML para publicación web: utiliza el mismo tema que se utiliza en las notas compartidas, pero se puede publicar como un sitio web estático."
|
||||
"format_pdf": "PDF - para propósitos de impresión o compartición."
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "Navegación de notas",
|
||||
@@ -185,8 +184,7 @@
|
||||
},
|
||||
"import-status": "Estado de importación",
|
||||
"in-progress": "Importación en progreso: {{progress}}",
|
||||
"successful": "Importación finalizada exitosamente.",
|
||||
"importZipRecommendation": "Al importar un archivo ZIP, la jerarquía de notas reflejará la estructura de subdirectorios dentro del archivo comprimido."
|
||||
"successful": "Importación finalizada exitosamente."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Incluir nota",
|
||||
@@ -261,6 +259,7 @@
|
||||
"delete_all_revisions": "Eliminar todas las revisiones de esta nota",
|
||||
"delete_all_button": "Eliminar todas las revisiones",
|
||||
"help_title": "Ayuda sobre revisiones de notas",
|
||||
"revision_last_edited": "Esta revisión se editó por última vez en {{date}}",
|
||||
"confirm_delete_all": "¿Quiere eliminar todas las revisiones de esta nota?",
|
||||
"no_revisions": "Aún no hay revisiones para esta nota...",
|
||||
"restore_button": "Restaurar",
|
||||
@@ -1107,7 +1106,10 @@
|
||||
"title": "Ancho del contenido",
|
||||
"default_description": "Trilium limita de forma predeterminada el ancho máximo del contenido para mejorar la legibilidad de ventanas maximizadas en pantallas anchas.",
|
||||
"max_width_label": "Ancho máximo del contenido en píxeles",
|
||||
"max_width_unit": "píxeles"
|
||||
"max_width_unit": "píxeles",
|
||||
"apply_changes_description": "Para aplicar cambios en el ancho del contenido, haga clic en",
|
||||
"reload_button": "recargar la interfaz",
|
||||
"reload_description": "cambios desde las opciones de apariencia"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Barra de título nativa (requiere reiniciar la aplicación)",
|
||||
@@ -1443,6 +1445,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI es una REST API que se utiliza para acceder a la instancia de Trilium mediante programación, sin interfaz de usuario.",
|
||||
"see_more": "Véa más detalles en el {{- link_to_wiki}} y el {{- link_to_openapi_spec}} o el {{- link_to_swagger_ui }}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "Especificación ETAPI OpenAPI",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Crear nuevo token ETAPI",
|
||||
"existing_tokens": "Tokens existentes",
|
||||
"no_tokens_yet": "Aún no hay tokens. Dé clic en el botón de arriba para crear uno.",
|
||||
@@ -1589,7 +1595,7 @@
|
||||
"tree-context-menu": {
|
||||
"open-in-a-new-tab": "Abrir en nueva pestaña",
|
||||
"open-in-a-new-split": "Abrir en nueva división",
|
||||
"insert-note-after": "Insertar nota contigua",
|
||||
"insert-note-after": "Insertar nota después de",
|
||||
"insert-child-note": "Insertar subnota",
|
||||
"delete": "Eliminar",
|
||||
"search-in-subtree": "Buscar en subárbol",
|
||||
@@ -1709,9 +1715,7 @@
|
||||
"window-on-top": "Mantener esta ventana en la parte superior"
|
||||
},
|
||||
"note_detail": {
|
||||
"could_not_find_typewidget": "No se pudo encontrar typeWidget para el tipo '{{type}}'",
|
||||
"printing": "Impresión en curso...",
|
||||
"printing_pdf": "Exportando a PDF en curso.."
|
||||
"could_not_find_typewidget": "No se pudo encontrar typeWidget para el tipo '{{type}}'"
|
||||
},
|
||||
"note_title": {
|
||||
"placeholder": "escriba el título de la nota aquí..."
|
||||
|
||||
@@ -260,6 +260,7 @@
|
||||
"delete_all_revisions": "Supprimer toutes les versions de cette note",
|
||||
"delete_all_button": "Supprimer toutes les versions",
|
||||
"help_title": "Aide sur les versions de notes",
|
||||
"revision_last_edited": "Cette version a été modifiée pour la dernière fois le {{date}}",
|
||||
"confirm_delete_all": "Voulez-vous supprimer toutes les versions de cette note ?",
|
||||
"no_revisions": "Aucune version pour cette note pour l'instant...",
|
||||
"confirm_restore": "Voulez-vous restaurer cette version ? Le titre et le contenu actuels de la note seront écrasés par cette version.",
|
||||
@@ -1106,6 +1107,9 @@
|
||||
"title": "Largeur du contenu",
|
||||
"default_description": "Trilium limite par défaut la largeur maximale du contenu pour améliorer la lisibilité sur des écrans larges.",
|
||||
"max_width_label": "Largeur maximale du contenu en pixels",
|
||||
"apply_changes_description": "Pour appliquer les modifications de largeur du contenu, cliquez sur",
|
||||
"reload_button": "recharger l'interface",
|
||||
"reload_description": "changements par rapport aux options d'apparence",
|
||||
"max_width_unit": "Pixels"
|
||||
},
|
||||
"native_title_bar": {
|
||||
@@ -1285,6 +1289,8 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI est une API REST utilisée pour accéder à l'instance Trilium par programme, sans interface utilisateur.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "Spec ETAPI OpenAPI",
|
||||
"create_token": "Créer un nouveau jeton ETAPI",
|
||||
"existing_tokens": "Jetons existants",
|
||||
"no_tokens_yet": "Il n'y a pas encore de jetons. Cliquez sur le bouton ci-dessus pour en créer un.",
|
||||
@@ -1301,7 +1307,9 @@
|
||||
"delete_token": "Supprimer/désactiver ce token",
|
||||
"rename_token_title": "Renommer le jeton",
|
||||
"rename_token_message": "Veuillez saisir le nom du nouveau jeton",
|
||||
"delete_token_confirmation": "Êtes-vous sûr de vouloir supprimer le jeton ETAPI « {{name}} » ?"
|
||||
"delete_token_confirmation": "Êtes-vous sûr de vouloir supprimer le jeton ETAPI « {{name}} » ?",
|
||||
"see_more": "Voir plus de détails dans le {{- link_to_wiki}} et le {{- link_to_openapi_spec}} ou le {{- link_to_swagger_ui }}.",
|
||||
"swagger_ui": "Interface utilisateur ETAPI Swagger"
|
||||
},
|
||||
"options_widget": {
|
||||
"options_status": "Statut des options",
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "ट्रिलियम नोट्स के बारें में"
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "A Trilium Notes-ról",
|
||||
"homepage": "Kezdőlap:",
|
||||
"app_version": "Alkalmazás verziója:",
|
||||
"db_version": "Adatbázis verzió:",
|
||||
"sync_version": "Verzió szinkronizálás :",
|
||||
"build_revision": "Build revízió:",
|
||||
"data_directory": "Adatkönyvtár:",
|
||||
"build_date": "Build dátum:"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Kritikus hiba",
|
||||
"message": "Kritikus hiba történt, amely megakadályozza a kliensalkalmazás indítását:\n\n{{message}}\n\nEzt valószínűleg egy váratlan szkripthiba okozza. Próbálja meg biztonságos módban elindítani az alkalmazást, és hárítsa el a problémát."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Nem sikerült inicializálni egy widgetet",
|
||||
"message-custom": "A(z) \"{{id}}\" azonosítójú, \"{{title}}\" című jegyzetből származó egyéni widget inicializálása sikertelen volt a következő ok miatt:\n\n{{message}}",
|
||||
"message-unknown": "Ismeretlen widget inicializálása sikertelen volt a következő ok miatt:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Nem sikerült betölteni az egyéni szkriptet",
|
||||
"message": "A(z) \"{{id}}\" azonosítójú, \"{{title}}\" című jegyzetből származó szkript nem hajtható végre a következő ok miatt:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Link hozzáadása",
|
||||
"help_on_links": "Segítség a linkekhez",
|
||||
"note": "Jegyzet",
|
||||
"search_note": "név szerinti jegyzetkeresés",
|
||||
"link_title_mirrors": "A link cím tükrözi a jegyzet aktuális címét",
|
||||
"link_title_arbitrary": "link cím önkényesen módosítható",
|
||||
"link_title": "Link cím",
|
||||
"button_add_link": "Link hozzáadása"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Az elágazás előtagjának szerkesztése",
|
||||
"help_on_tree_prefix": "Segítség a fa előtagján",
|
||||
"prefix": "Az előtag: ",
|
||||
"save": "Mentés"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Tömeges akciók",
|
||||
"affected_notes": "Érintett jegyzetek",
|
||||
"labels": "Címkék",
|
||||
"relations": "Kapcsolatok",
|
||||
"notes": "Jegyzetek"
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
@@ -109,8 +109,7 @@
|
||||
"export_type_single": "Solo questa nota, senza le sottostanti",
|
||||
"format_opml": "OPML - formato per scambio informazioni outline. Formattazione, immagini e files non sono inclusi.",
|
||||
"opml_version_1": "OPML v.1.0 - solo testo semplice",
|
||||
"opml_version_2": "OPML v2.0 - supporta anche HTML",
|
||||
"share-format": "HTML per la pubblicazione sul web - utilizza lo stesso tema utilizzato per le note condivise, ma può essere pubblicato come sito web statico."
|
||||
"opml_version_2": "OPML v2.0 - supporta anche HTML"
|
||||
},
|
||||
"password_not_set": {
|
||||
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
|
||||
@@ -133,6 +132,10 @@
|
||||
"new_token_message": "Inserisci il nome del nuovo token",
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI è un'API REST utilizzata per accedere alle istanze di Trilium in modo programmatico, senza interfaccia utente.",
|
||||
"see_more": "Per maggiori dettagli consulta {{- link_to_wiki}} e {{- link_to_openapi_spec}} o {{- link_to_swagger_ui}}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "Specifiche ETAPI OpenAPI",
|
||||
"swagger_ui": "Interfaccia utente ETAPI Swagger",
|
||||
"create_token": "Crea un nuovo token ETAPI",
|
||||
"existing_tokens": "Token esistenti",
|
||||
"no_tokens_yet": "Non ci sono ancora token. Clicca sul pulsante qui sopra per crearne uno.",
|
||||
@@ -864,6 +867,7 @@
|
||||
"delete_all_revisions": "Elimina tutte le revisioni di questa nota",
|
||||
"delete_all_button": "Elimina tutte le revisioni",
|
||||
"help_title": "Aiuto sulle revisioni delle note",
|
||||
"revision_last_edited": "Questa revisione è stata modificata l'ultima volta il {{date}}",
|
||||
"confirm_delete_all": "Vuoi eliminare tutte le revisioni di questa nota?",
|
||||
"no_revisions": "Ancora nessuna revisione per questa nota...",
|
||||
"restore_button": "Ripristina",
|
||||
@@ -1570,7 +1574,10 @@
|
||||
"title": "Larghezza del contenuto",
|
||||
"default_description": "Per impostazione predefinita, Trilium limita la larghezza massima del contenuto per migliorare la leggibilità sugli schermi più grandi.",
|
||||
"max_width_label": "Larghezza massima del contenuto",
|
||||
"max_width_unit": "pixel"
|
||||
"max_width_unit": "pixel",
|
||||
"apply_changes_description": "Per applicare le modifiche alla larghezza del contenuto, fare clic su",
|
||||
"reload_button": "ricarica frontend",
|
||||
"reload_description": "modifiche dalle opzioni di aspetto"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Barra del titolo nativa (richiede il riavvio dell'app)",
|
||||
|
||||
@@ -39,10 +39,7 @@
|
||||
"edit_branch_prefix": "ブランチ接頭辞の編集",
|
||||
"help_on_tree_prefix": "ツリー接頭辞に関するヘルプ",
|
||||
"prefix": "接頭辞: ",
|
||||
"branch_prefix_saved": "ブランチの接頭辞が保存されました。",
|
||||
"edit_branch_prefix_multiple": "{{count}} ブランチのブランチ接頭辞を編集",
|
||||
"branch_prefix_saved_multiple": "{{count}} 個のブランチのブランチ接頭辞が保存されました。",
|
||||
"affected_branches": "影響を受けるブランチ {{count}}:"
|
||||
"branch_prefix_saved": "ブランチの接頭辞が保存されました。"
|
||||
},
|
||||
"global_menu": {
|
||||
"menu": "メニュー",
|
||||
@@ -257,8 +254,7 @@
|
||||
"export_status": "エクスポート状況",
|
||||
"export_in_progress": "エクスポート処理中: {{progressCount}}",
|
||||
"export_finished_successfully": "エクスポートが正常に完了しました。",
|
||||
"format_pdf": "PDF - 印刷または共有目的に。",
|
||||
"share-format": "Web 公開用の HTML - 共有ノートで使用されるのと同じテーマを使用しますが、静的 Web サイトとして公開できます。"
|
||||
"format_pdf": "PDF - 印刷または共有目的に。"
|
||||
},
|
||||
"help": {
|
||||
"title": "チートシート",
|
||||
@@ -614,6 +610,7 @@
|
||||
"delete_all_revisions": "このノートの変更履歴をすべて削除",
|
||||
"delete_all_button": "変更履歴をすべて削除",
|
||||
"help_title": "変更履歴のヘルプ",
|
||||
"revision_last_edited": "この変更は{{date}}に行われました",
|
||||
"confirm_delete_all": "このノートのすべての変更履歴を削除しますか?",
|
||||
"no_revisions": "このノートに変更履歴はまだありません...",
|
||||
"restore_button": "復元",
|
||||
@@ -660,6 +657,10 @@
|
||||
"created": "作成日時",
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI は、Trilium インスタンスに UI なしでプログラム的にアクセスするための REST API です。",
|
||||
"see_more": "詳細は{{- link_to_wiki}}と{{- link_to_openapi_spec}}または{{- link_to_swagger_ui }}を参照してください。",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "ETAPI OpenAPIの仕様",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "新しくETAPIトークンを作成",
|
||||
"existing_tokens": "既存のトークン",
|
||||
"no_tokens_yet": "トークンはまだありません。上のボタンをクリックして作成してください。",
|
||||
@@ -833,10 +834,13 @@
|
||||
"theme_defined": "テーマが定義されました"
|
||||
},
|
||||
"max_content_width": {
|
||||
"reload_button": "フロントエンドをリロード",
|
||||
"title": "コンテンツ幅",
|
||||
"default_description": "Triliumは、ワイドスクリーンで最大化された画面での可読性を向上させるために、デフォルトでコンテンツの最大幅を制限しています。",
|
||||
"max_width_label": "最大コンテンツ幅",
|
||||
"max_width_unit": "ピクセル"
|
||||
"max_width_unit": "ピクセル",
|
||||
"apply_changes_description": "コンテンツ幅の変更を適用するには、クリックしてください",
|
||||
"reload_description": "外観設定から変更"
|
||||
},
|
||||
"theme": {
|
||||
"title": "アプリのテーマ",
|
||||
@@ -2079,8 +2083,5 @@
|
||||
"edit-slide": "このスライドを編集",
|
||||
"start-presentation": "プレゼンテーションを開始",
|
||||
"slide-overview": "スライドの概要を切り替え"
|
||||
},
|
||||
"calendar_view": {
|
||||
"delete_note": "ノートを削除..."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,6 @@
|
||||
"critical-error": {
|
||||
"title": "Kritische Error",
|
||||
"message": "Een kritieke fout heeft plaatsgevonden waardoor de cliënt zich aanmeldt vanaf het begin:\n\n84X\n\nDit is waarschijnlijk veroorzaakt door een script dat op een onverwachte manier faalt. Probeer de sollicitatie in veilige modus te starten en de kwestie aan te spreken."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Starten widget mislukt",
|
||||
"message-unknown": "Onbekende widget kan niet gestart worden omdat:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Custom script laden mislukt"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
|
||||
@@ -912,6 +912,7 @@
|
||||
"delete_all_revisions": "Usuń wszystkie wersje tej notatki",
|
||||
"delete_all_button": "Usuń wszystkie wersje",
|
||||
"help_title": "Pomoc dotycząca wersji notatki",
|
||||
"revision_last_edited": "Ta wersja była ostatnio edytowana {{date}}",
|
||||
"confirm_delete_all": "Czy chcesz usunąć wszystkie wersje tej notatki?",
|
||||
"no_revisions": "Brak wersji dla tej notatki...",
|
||||
"restore_button": "Przywróć",
|
||||
@@ -1464,7 +1465,10 @@
|
||||
"title": "Szerokość zawartości",
|
||||
"default_description": "Trilium domyślnie ogranicza maksymalną szerokość zawartości, aby poprawić czytelność na zmaksymalizowanych ekranach o dużej szerokości.",
|
||||
"max_width_label": "Maksymalna szerokość zawartości",
|
||||
"max_width_unit": "piksele"
|
||||
"max_width_unit": "piksele",
|
||||
"apply_changes_description": "Aby zastosować zmiany szerokości zawartości, kliknij na",
|
||||
"reload_button": "przeładuj frontend",
|
||||
"reload_description": "zmiany z opcji wyglądu"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Natywny pasek tytułu (wymaga ponownego uruchomienia aplikacji)",
|
||||
@@ -1660,6 +1664,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI to interfejs API REST używany do programowego dostępu do instancji Trilium, bez interfejsu użytkownika.",
|
||||
"see_more": "Zobacz więcej szczegółów w {{- link_to_wiki}} oraz w {{- link_to_openapi_spec}} lub {{- link_to_swagger_ui }}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "specyfikacja ETAPI OpenAPI",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Utwórz nowy token ETAPI",
|
||||
"existing_tokens": "Istniejące tokeny",
|
||||
"no_tokens_yet": "Nie ma jeszcze żadnych tokenów. Kliknij przycisk powyżej, aby utworzyć jeden.",
|
||||
|
||||
@@ -259,6 +259,7 @@
|
||||
"delete_all_revisions": "Apagar todas as versões desta nota",
|
||||
"delete_all_button": "Apagar todas as versões",
|
||||
"help_title": "Ajuda sobre as versões da nota",
|
||||
"revision_last_edited": "Esta versão foi editada pela última vez em {{date}}",
|
||||
"confirm_delete_all": "Quer apagar todas as versões desta nota?",
|
||||
"no_revisions": "Ainda não há versões para esta nota...",
|
||||
"restore_button": "Recuperar",
|
||||
@@ -1082,7 +1083,10 @@
|
||||
"title": "Largura do Conteúdo",
|
||||
"default_description": "Por padrão, o Trilium limita a largura máxima do conteúdo para melhorar a legibilidade em janelas maximizadas em ecrãs largos.",
|
||||
"max_width_label": "Largura máxima do conteúdo",
|
||||
"max_width_unit": "pixels"
|
||||
"max_width_unit": "pixels",
|
||||
"apply_changes_description": "Para aplicar as alterações de largura do conteúdo, clique em",
|
||||
"reload_button": "recarregar frontend",
|
||||
"reload_description": "alterações de opções de aparência"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Barra de Título Nativa (requer recarregar a app)",
|
||||
@@ -1419,6 +1423,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI é uma API REST usada para aceder a instância do Trilium programaticamente, sem interface gráfica.",
|
||||
"see_more": "Veja mais pormenores no {{- link_to_wiki}}, na {{- link_to_openapi_spec}} ou na {{- link_to_swagger_ui}}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "Especificação OpenAPI do ETAPI",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Criar token ETAPI",
|
||||
"existing_tokens": "Tokens existentes",
|
||||
"no_tokens_yet": "Ainda não existem tokens. Clique no botão acima para criar um.",
|
||||
|
||||
@@ -415,6 +415,7 @@
|
||||
"delete_all_revisions": "Excluir todas as versões desta nota",
|
||||
"delete_all_button": "Excluir todas as versões",
|
||||
"help_title": "Ajuda sobre as versões da nota",
|
||||
"revision_last_edited": "Esta versão foi editada pela última vez em {{date}}",
|
||||
"confirm_delete_all": "Você quer excluir todas as versões desta nota?",
|
||||
"no_revisions": "Ainda não há versões para esta nota...",
|
||||
"restore_button": "Recuperar",
|
||||
@@ -1304,6 +1305,9 @@
|
||||
"title": "Largura do Conteúdo",
|
||||
"max_width_label": "Largura máxima do conteúdo",
|
||||
"max_width_unit": "pixels",
|
||||
"apply_changes_description": "Para aplicar as alterações de largura do conteúdo, clique em",
|
||||
"reload_button": "recarregar frontend",
|
||||
"reload_description": "alterações de opções de aparência",
|
||||
"default_description": "Por padrão, o Trilium limita a largura máxima do conteúdo para melhorar a legibilidade em janelas maximizadas em telas wide."
|
||||
},
|
||||
"native_title_bar": {
|
||||
@@ -1929,6 +1933,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI é uma API REST usada para acessar a instância do Trilium programaticamente, sem interface gráfica.",
|
||||
"see_more": "Veja mais detalhes no {{- link_to_wiki}}, na {{- link_to_openapi_spec}} ou na {{- link_to_swagger_ui}}.",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "Especificação OpenAPI do ETAPI",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Criar novo token ETAPI",
|
||||
"existing_tokens": "Tokens existentes",
|
||||
"no_tokens_yet": "Ainda não existem tokens. Clique no botão acima para criar um.",
|
||||
|
||||
@@ -507,13 +507,17 @@
|
||||
"new_token_message": "Introduceți denumirea noului token",
|
||||
"new_token_title": "Token ETAPI nou",
|
||||
"no_tokens_yet": "Nu există încă token-uri. Clic pe butonul de deasupra pentru a crea una.",
|
||||
"openapi_spec": "Specificația OpenAPI pentru ETAPI",
|
||||
"swagger_ui": "UI-ul Swagger pentru ETAPI",
|
||||
"rename_token": "Redenumește token-ul",
|
||||
"rename_token_message": "Introduceți denumirea noului token",
|
||||
"rename_token_title": "Redenumire token",
|
||||
"see_more": "Vedeți mai multe detalii în {{- link_to_wiki}} și în {{- link_to_openapi_spec}} sau în {{- link_to_swagger_ui }}.",
|
||||
"title": "ETAPI",
|
||||
"token_created_message": "Copiați token-ul creat în clipboard. Trilium stochează token-ul ca hash așadar această valoare poate fi văzută doar acum.",
|
||||
"token_created_title": "Token ETAPI creat",
|
||||
"token_name": "Denumire token"
|
||||
"token_name": "Denumire token",
|
||||
"wiki": "wiki"
|
||||
},
|
||||
"execute_script": {
|
||||
"example_1": "De exemplu, pentru a adăuga un șir de caractere la titlul unei notițe, se poate folosi acest mic script:",
|
||||
@@ -796,9 +800,12 @@
|
||||
"modal_body_text": "Din cauza limitărilor la nivel de navigator, nu este posibilă citirea clipboard-ului din JavaScript. Inserați Markdown-ul pentru a-l importa în caseta de mai jos și dați clic pe butonul Import"
|
||||
},
|
||||
"max_content_width": {
|
||||
"apply_changes_description": "Pentru a aplica schimbările de lățime a conținutului, dați click pe",
|
||||
"default_description": "În mod implicit Trilium limitează lățimea conținutului pentru a îmbunătăți lizibilitatea pentru ferestrele maximizate pe ecrane late.",
|
||||
"max_width_label": "Lungimea maximă a conținutului",
|
||||
"max_width_unit": "pixeli",
|
||||
"reload_button": "reîncarcă interfața",
|
||||
"reload_description": "schimbări din opțiunile de afișare",
|
||||
"title": "Lățime conținut"
|
||||
},
|
||||
"mobile_detail_menu": {
|
||||
@@ -1083,6 +1090,7 @@
|
||||
"preview_not_available": "Nu este disponibilă o previzualizare pentru acest tip de notiță.",
|
||||
"restore_button": "Restaurează",
|
||||
"revision_deleted": "Revizia notiței a fost ștearsă.",
|
||||
"revision_last_edited": "Revizia a fost ultima oară modificată pe {{date}}",
|
||||
"revision_restored": "Revizia notiței a fost restaurată.",
|
||||
"revisions_deleted": "Notița reviziei a fost ștearsă.",
|
||||
"maximum_revisions": "Numărul maxim de revizii pentru notița curentă: {{number}}.",
|
||||
|
||||
@@ -320,8 +320,7 @@
|
||||
"explodeArchivesTooltip": "Если этот флажок установлен, Trilium будет читать файлы <code>.zip</code>, <code>.enex</code> и <code>.opml</code> и создавать заметки из файлов внутри этих архивов. Если флажок не установлен, Trilium будет прикреплять сами архивы к заметке.",
|
||||
"explodeArchives": "Прочитать содержимое архивов <code>.zip</code>, <code>.enex</code> и <code>.opml</code>.",
|
||||
"shrinkImagesTooltip": "<p>Если этот параметр включен, Trilium попытается уменьшить размер импортируемых изображений путём масштабирования и оптимизации, что может повлиять на воспринимаемое качество изображения. Если этот параметр не установлен, изображения будут импортированы без изменений.</p><p>Это не относится к импорту файлов <code>.zip</code> с метаданными, поскольку предполагается, что эти файлы уже оптимизированы.</p>",
|
||||
"codeImportedAsCode": "Импортировать распознанные файлы кода (например, <code>.json</code>) в виде заметок типа \"код\", если это неясно из метаданных",
|
||||
"importZipRecommendation": "При импорте ZIP файла иерархия заметок будет отражена в структуре папок внутри архива."
|
||||
"codeImportedAsCode": "Импортировать распознанные файлы кода (например, <code>.json</code>) в виде заметок типа \"код\", если это неясно из метаданных"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Импорт Markdown",
|
||||
@@ -366,6 +365,7 @@
|
||||
"delete_all_button": "Удалить все версии",
|
||||
"help_title": "Помощь по версиям заметок",
|
||||
"confirm_delete_all": "Вы хотите удалить все версии этой заметки?",
|
||||
"revision_last_edited": "Эта версия последний раз редактировалась {{date}}",
|
||||
"confirm_restore": "Хотите восстановить эту версию? Текущее название и содержание заметки будут перезаписаны этой версией.",
|
||||
"confirm_delete": "Вы хотите удалить эту версию?",
|
||||
"revisions_deleted": "Версии заметки были удалены.",
|
||||
@@ -980,8 +980,7 @@
|
||||
"open_sql_console_history": "Открыть историю консоли SQL",
|
||||
"show_shared_notes_subtree": "Поддерево общедоступных заметок",
|
||||
"switch_to_mobile_version": "Перейти на мобильную версию",
|
||||
"switch_to_desktop_version": "Переключиться на версию для ПК",
|
||||
"new-version-available": "Доступно обновление"
|
||||
"switch_to_desktop_version": "Переключиться на версию для ПК"
|
||||
},
|
||||
"zpetne_odkazy": {
|
||||
"backlink": "{{count}} ссылки",
|
||||
@@ -1203,8 +1202,11 @@
|
||||
"max_content_width": {
|
||||
"max_width_unit": "пикселей",
|
||||
"title": "Ширина контентной области",
|
||||
"reload_button": "перезагрузить интерфейс",
|
||||
"default_description": "Trilium по умолчанию ограничивает максимальную ширину контента, чтобы улучшить читаемость на широких экранах.",
|
||||
"max_width_label": "Максимальная ширина контентной области"
|
||||
"max_width_label": "Максимальная ширина контентной области",
|
||||
"apply_changes_description": "Чтобы применить изменения, нажмите на",
|
||||
"reload_description": "изменения в параметрах внешнего вида"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"enabled": "включено",
|
||||
@@ -1437,6 +1439,7 @@
|
||||
},
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"wiki": "вики",
|
||||
"created": "Создано",
|
||||
"actions": "Действия",
|
||||
"existing_tokens": "Существующие токены",
|
||||
@@ -1444,7 +1447,10 @@
|
||||
"default_token_name": "новый токен",
|
||||
"rename_token_title": "Переименовать токен",
|
||||
"description": "ETAPI — это REST API, используемый для программного доступа к экземпляру Trilium без пользовательского интерфейса.",
|
||||
"see_more": "Более подробную информацию смотрите в {{- link_to_wiki}} и {{- link_to_openapi_spec}} или {{- link_to_swagger_ui }}.",
|
||||
"create_token": "Создать новый токен ETAPI",
|
||||
"openapi_spec": "Спецификация ETAPI OpenAPI",
|
||||
"swagger_ui": "Пользовательский интерфейс ETAPI Swagger",
|
||||
"new_token_title": "Новый токен ETAPI",
|
||||
"token_created_title": "Создан токен ETAPI",
|
||||
"rename_token": "Переименовать этот токен",
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
"delete_all_revisions": "Obriši sve revizije ove beleške",
|
||||
"delete_all_button": "Obriši sve revizije",
|
||||
"help_title": "Pomoć za Revizije beleški",
|
||||
"revision_last_edited": "Ova revizija je poslednji put izmenjena {{date}}",
|
||||
"confirm_delete_all": "Da li želite da obrišete sve revizije ove beleške?",
|
||||
"no_revisions": "Još uvek nema revizija za ovu belešku...",
|
||||
"restore_button": "Vrati",
|
||||
|
||||
@@ -104,8 +104,7 @@
|
||||
"export_in_progress": "正在匯出:{{progressCount}}",
|
||||
"export_finished_successfully": "成功匯出。",
|
||||
"format_html": "HTML - 推薦,因為它保留了所有格式",
|
||||
"format_pdf": "PDF - 用於列印或與他人分享。",
|
||||
"share-format": "HTML 網頁發佈——使用與共享筆記相同的佈景主題,但可發佈為靜態網站。"
|
||||
"format_pdf": "PDF - 用於列印或與他人分享。"
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "筆記導航",
|
||||
@@ -261,6 +260,7 @@
|
||||
"delete_all_revisions": "刪除此筆記的所有歷史版本",
|
||||
"delete_all_button": "刪除所有歷史版本",
|
||||
"help_title": "關於筆記歷史版本的說明",
|
||||
"revision_last_edited": "此歷史版本上次於 {{date}} 編輯",
|
||||
"confirm_delete_all": "您是否要刪除此筆記的所有歷史版本?",
|
||||
"no_revisions": "此筆記暫無歷史版本…",
|
||||
"confirm_restore": "您是否要還原此歷史版本?這將使用此歷史版本覆寫筆記的目前標題和內容。",
|
||||
@@ -1104,6 +1104,9 @@
|
||||
"title": "內容寬度",
|
||||
"default_description": "Trilium 預設會限制內容的最大寬度以提高在寬螢幕中全螢幕時的可讀性。",
|
||||
"max_width_label": "內容最大寬度(像素)",
|
||||
"apply_changes_description": "要套用內容寬度更改,請點擊",
|
||||
"reload_button": "重新載入前端",
|
||||
"reload_description": "來自外觀選項的更改",
|
||||
"max_width_unit": "像素"
|
||||
},
|
||||
"native_title_bar": {
|
||||
@@ -1278,6 +1281,8 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI 是一個 REST API,用於以編程方式訪問 Trilium 實例,而無需 UI。",
|
||||
"wiki": "維基",
|
||||
"openapi_spec": "ETAPI OpenAPI 規範",
|
||||
"create_token": "新增 ETAPI 令牌",
|
||||
"existing_tokens": "現有令牌",
|
||||
"no_tokens_yet": "目前還沒有令牌。點擊上面的按鈕新增一個。",
|
||||
@@ -1294,7 +1299,9 @@
|
||||
"delete_token": "刪除 / 停用此令牌",
|
||||
"rename_token_title": "重新命名令牌",
|
||||
"rename_token_message": "請輸入新的令牌名稱",
|
||||
"delete_token_confirmation": "您確定要刪除 ETAPI 令牌 \"{{name}}\" 嗎?"
|
||||
"delete_token_confirmation": "您確定要刪除 ETAPI 令牌 \"{{name}}\" 嗎?",
|
||||
"see_more": "有關更多詳細資訊,請參閱 {{- link_to_wiki}} 和 {{- link_to_openapi_spec}} 或 {{- link_to_swagger_ui}}。",
|
||||
"swagger_ui": "ETAPI Swagger UI"
|
||||
},
|
||||
"options_widget": {
|
||||
"options_status": "選項狀態",
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
"delete_all_revisions": "Видалити всі версії цієї нотатки",
|
||||
"delete_all_button": "Видалити всі версії",
|
||||
"help_title": "Довідка щодо Версій нотаток",
|
||||
"revision_last_edited": "Цю версію востаннє редагували {{date}}",
|
||||
"confirm_delete_all": "Ви хочете видалити всі версії цієї нотатки?",
|
||||
"no_revisions": "Поки що немає версій цієї нотатки...",
|
||||
"restore_button": "Відновити",
|
||||
@@ -1204,7 +1205,10 @@
|
||||
"title": "Ширина вмісту",
|
||||
"default_description": "Trilium за замовчуванням обмежує максимальну ширину вмісту, щоб поліпшити читабельність на широкоформатних екранах у режимі максимального розширення.",
|
||||
"max_width_label": "Максимальна ширина вмісту",
|
||||
"max_width_unit": "пікселів"
|
||||
"max_width_unit": "пікселів",
|
||||
"apply_changes_description": "Щоб застосувати зміни ширини вмісту, натисніть на",
|
||||
"reload_button": "перезавантажити інтерфейс",
|
||||
"reload_description": "зміни в параметрах зовнішнього вигляду"
|
||||
},
|
||||
"native_title_bar": {
|
||||
"title": "Нативний рядок заголовка (потрібен перезапуск)",
|
||||
@@ -1399,6 +1403,10 @@
|
||||
"etapi": {
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI — це REST API, який використовується для програмного доступу до екземпляра Trilium без інтерфейсу користувача.",
|
||||
"see_more": "Див. докладнішу інформацію у {{- link_to_wiki}} та {{- link_to_openapi_spec}} або {{- link_to_swagger_ui }}.",
|
||||
"wiki": "вікі",
|
||||
"openapi_spec": "ETAPI OpenAPI spec",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "Створити новий токен ETAPI",
|
||||
"existing_tokens": "Існуючі токени",
|
||||
"no_tokens_yet": "Токенів поки що немає. Натисніть кнопку вище, щоб створити його.",
|
||||
|
||||
1
apps/client/src/types.d.ts
vendored
1
apps/client/src/types.d.ts
vendored
@@ -26,6 +26,7 @@ interface CustomGlobals {
|
||||
appContext: AppContext;
|
||||
froca: Froca;
|
||||
treeCache: Froca;
|
||||
importMarkdownInline: () => Promise<unknown>;
|
||||
SEARCH_HELP_TEXT: string;
|
||||
activeDialog: JQuery<HTMLElement> | null;
|
||||
componentId: string;
|
||||
|
||||
@@ -23,24 +23,6 @@ export class CssVarReader {
|
||||
return (!isNaN(number.valueOf()) ? number.valueOf() : defaultValue)
|
||||
}
|
||||
|
||||
asBoolean(defaultValue?: boolean) {
|
||||
let value = this.value.toLocaleLowerCase().trim();
|
||||
let result: boolean | undefined;
|
||||
|
||||
switch (value) {
|
||||
case "true":
|
||||
case "1":
|
||||
result = true;
|
||||
break;
|
||||
case "false":
|
||||
case "0":
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return (result !== undefined) ? result : defaultValue;
|
||||
}
|
||||
|
||||
asEnum<T>(enumType: T, defaultValue?: T[keyof T]): T[keyof T] | undefined {
|
||||
let result: T[keyof T] | undefined;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.floating-buttons-children,
|
||||
.show-floating-buttons {
|
||||
position: absolute;
|
||||
top: var(--floating-buttons-vert-offset, 14px);
|
||||
top: var(--floating-buttons-vert-offset, 10px);
|
||||
inset-inline-end: var(--floating-buttons-horiz-offset, 10px);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -4,7 +4,7 @@ import Component from "../components/component";
|
||||
import NoteContext from "../components/note_context";
|
||||
import FNote from "../entities/fnote";
|
||||
import ActionButton, { ActionButtonProps } from "./react/ActionButton";
|
||||
import { useIsNoteReadOnly, useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks";
|
||||
import { useNoteLabelBoolean, useTriliumEvent, useTriliumOption, useWindowSize } from "./react/hooks";
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils";
|
||||
import server from "../services/server";
|
||||
@@ -13,6 +13,8 @@ import toast from "../services/toast";
|
||||
import { t } from "../services/i18n";
|
||||
import { copyImageReferenceToClipboard } from "../services/image";
|
||||
import tree from "../services/tree";
|
||||
import protected_session_holder from "../services/protected_session_holder";
|
||||
import options from "../services/options";
|
||||
import { getHelpUrlForNote } from "../services/in_app_help";
|
||||
import froca from "../services/froca";
|
||||
import NoteLink from "./react/NoteLink";
|
||||
@@ -99,26 +101,48 @@ function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingBut
|
||||
/>
|
||||
}
|
||||
|
||||
function EditButton({ note, noteContext }: FloatingButtonContext) {
|
||||
const [animationClass, setAnimationClass] = useState("");
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
|
||||
const isReadOnlyInfoBarDismissed = false; // TODO
|
||||
function EditButton({ note, noteContext, isDefaultViewMode }: FloatingButtonContext) {
|
||||
const [ animationClass, setAnimationClass ] = useState("");
|
||||
const [ isEnabled, setIsEnabled ] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isReadOnly) {
|
||||
noteContext.isReadOnly().then(isReadOnly => {
|
||||
setIsEnabled(
|
||||
isDefaultViewMode
|
||||
&& (!note.isProtected || protected_session_holder.isProtectedSessionAvailable())
|
||||
&& !options.is("databaseReadonly")
|
||||
&& isReadOnly
|
||||
);
|
||||
});
|
||||
}, [ note ]);
|
||||
|
||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({ noteContext: eventNoteContext }) => {
|
||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
||||
setIsEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
// make the edit button stand out on the first display, otherwise
|
||||
// it's difficult to notice that the note is readonly
|
||||
useEffect(() => {
|
||||
if (isEnabled) {
|
||||
setAnimationClass("bx-tada bx-lg");
|
||||
setTimeout(() => {
|
||||
setAnimationClass("");
|
||||
}, 1700);
|
||||
}
|
||||
}, [ isReadOnly ]);
|
||||
}, [ isEnabled ]);
|
||||
|
||||
return !!isReadOnly && isReadOnlyInfoBarDismissed && <FloatingButton
|
||||
return isEnabled && <FloatingButton
|
||||
text={t("edit_button.edit_this_note")}
|
||||
icon="bx bx-pencil"
|
||||
className={animationClass}
|
||||
onClick={() => enableEditing()}
|
||||
onClick={() => {
|
||||
if (noteContext.viewScope) {
|
||||
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", { noteContext });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
.note-list-widget {
|
||||
min-height: 0;
|
||||
max-width: var(--max-content-width); /* Inherited from .note-split */
|
||||
|
||||
overflow: auto;
|
||||
contain: none !important;
|
||||
}
|
||||
|
||||
body.prefers-centered-content .note-list-widget {
|
||||
/* Horizontally center the widget in its parent when the "Keep content centered" option is on */
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.note-list-widget .note-list {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import FNote from "../../../entities/fnote";
|
||||
import contextMenu, { ContextMenuEvent } from "../../../menus/context_menu";
|
||||
import link_context_menu from "../../../menus/link_context_menu";
|
||||
import branches from "../../../services/branches";
|
||||
import { t } from "../../../services/i18n";
|
||||
|
||||
export function openCalendarContextMenu(e: ContextMenuEvent, noteId: string, parentNote: FNote) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
contextMenu.show({
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [
|
||||
...link_context_menu.getItems(),
|
||||
{ kind: "separator" },
|
||||
{
|
||||
title: t("calendar_view.delete_note"),
|
||||
uiIcon: "bx bx-trash",
|
||||
handler: async () => {
|
||||
const branchId = parentNote.childToBranch[noteId];
|
||||
await branches.deleteNotes([ branchId ], false, false);
|
||||
}
|
||||
}
|
||||
],
|
||||
selectMenuItemHandler: ({ command }) => link_context_menu.handleLinkContextMenuItem(command, noteId),
|
||||
})
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import Button, { ButtonGroup } from "../../react/Button";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import { RefObject } from "preact";
|
||||
import TouchBar, { TouchBarButton, TouchBarLabel, TouchBarSegmentedControl, TouchBarSpacer } from "../../react/TouchBar";
|
||||
import { openCalendarContextMenu } from "./context_menu";
|
||||
|
||||
interface CalendarViewData {
|
||||
|
||||
@@ -107,7 +106,7 @@ export default function CalendarView({ note, noteIds }: ViewModeProps<CalendarVi
|
||||
const plugins = usePlugins(isEditable, isCalendarRoot);
|
||||
const locale = useLocale();
|
||||
|
||||
const { eventDidMount } = useEventDisplayCustomization(note);
|
||||
const { eventDidMount } = useEventDisplayCustomization();
|
||||
const editingProps = useEditing(note, isEditable, isCalendarRoot);
|
||||
|
||||
// React to changes.
|
||||
@@ -254,7 +253,7 @@ function useEditing(note: FNote, isEditable: boolean, isCalendarRoot: boolean) {
|
||||
};
|
||||
}
|
||||
|
||||
function useEventDisplayCustomization(parentNote: FNote) {
|
||||
function useEventDisplayCustomization() {
|
||||
const eventDidMount = useCallback((e: EventMountArg) => {
|
||||
const { iconClass, promotedAttributes } = e.event.extendedProps;
|
||||
|
||||
@@ -303,11 +302,6 @@ function useEventDisplayCustomization(parentNote: FNote) {
|
||||
}
|
||||
$(mainContainer ?? e.el).append($(promotedAttributesHtml));
|
||||
}
|
||||
|
||||
e.el.addEventListener("contextmenu", (contextMenuEvent) => {
|
||||
const noteId = e.event.extendedProps.noteId;
|
||||
openCalendarContextMenu(contextMenuEvent, noteId, parentNote);
|
||||
});
|
||||
}, []);
|
||||
return { eventDidMount };
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { EventData } from "../../components/app_context.js";
|
||||
import { LOCALES } from "@triliumnext/commons";
|
||||
import { readCssVar } from "../../utils/css-var.js";
|
||||
import FlexContainer from "./flex_container.js";
|
||||
import options from "../../services/options.js";
|
||||
import type BasicWidget from "../basic_widget.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import { LOCALES } from "@triliumnext/commons";
|
||||
|
||||
/**
|
||||
* The root container is the top-most widget/container, from which the entire layout derives.
|
||||
@@ -31,11 +30,9 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
|
||||
window.visualViewport?.addEventListener("resize", () => this.#onMobileResize());
|
||||
}
|
||||
|
||||
this.#setMaxContentWidth();
|
||||
this.#setMotion();
|
||||
this.#setShadows();
|
||||
this.#setBackdropEffects();
|
||||
this.#setThemeCapabilities();
|
||||
this.#setMotion(options.is("motionEnabled"));
|
||||
this.#setShadows(options.is("shadowsEnabled"));
|
||||
this.#setBackdropEffects(options.is("backdropEffectsEnabled"));
|
||||
this.#setLocaleAndDirection(options.get("locale"));
|
||||
|
||||
return super.render();
|
||||
@@ -43,21 +40,15 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
|
||||
|
||||
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||
if (loadResults.isOptionReloaded("motionEnabled")) {
|
||||
this.#setMotion();
|
||||
this.#setMotion(options.is("motionEnabled"));
|
||||
}
|
||||
|
||||
if (loadResults.isOptionReloaded("shadowsEnabled")) {
|
||||
this.#setShadows();
|
||||
this.#setShadows(options.is("shadowsEnabled"));
|
||||
}
|
||||
|
||||
if (loadResults.isOptionReloaded("backdropEffectsEnabled")) {
|
||||
this.#setBackdropEffects();
|
||||
}
|
||||
|
||||
if (loadResults.isOptionReloaded("maxContentWidth")
|
||||
|| loadResults.isOptionReloaded("centerContent")) {
|
||||
|
||||
this.#setMaxContentWidth();
|
||||
this.#setBackdropEffects(options.is("backdropEffectsEnabled"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,38 +58,19 @@ export default class RootContainer extends FlexContainer<BasicWidget> {
|
||||
this.$widget.toggleClass("virtual-keyboard-opened", isKeyboardOpened);
|
||||
}
|
||||
|
||||
#setMaxContentWidth() {
|
||||
const width = Math.max(options.getInt("maxContentWidth") || 0, 640);
|
||||
document.body.style.setProperty("--preferred-max-content-width", `${width}px`);
|
||||
|
||||
document.body.classList.toggle("prefers-centered-content", options.is("centerContent"));
|
||||
}
|
||||
|
||||
#setMotion() {
|
||||
const enabled = options.is("motionEnabled");
|
||||
#setMotion(enabled: boolean) {
|
||||
document.body.classList.toggle("motion-disabled", !enabled);
|
||||
jQuery.fx.off = !enabled;
|
||||
}
|
||||
|
||||
#setShadows() {
|
||||
const enabled = options.is("shadowsEnabled");
|
||||
#setShadows(enabled: boolean) {
|
||||
document.body.classList.toggle("shadows-disabled", !enabled);
|
||||
}
|
||||
|
||||
#setBackdropEffects() {
|
||||
const enabled = options.is("backdropEffectsEnabled");
|
||||
#setBackdropEffects(enabled: boolean) {
|
||||
document.body.classList.toggle("backdrop-effects-disabled", !enabled);
|
||||
}
|
||||
|
||||
#setThemeCapabilities() {
|
||||
// Supports background effects
|
||||
|
||||
const useBgfx = readCssVar(document.documentElement, "allow-background-effects")
|
||||
.asBoolean(false);
|
||||
|
||||
document.body.classList.toggle("theme-supports-background-effects", useBgfx);
|
||||
}
|
||||
|
||||
#setLocaleAndDirection(locale: string) {
|
||||
const correspondingLocale = LOCALES.find(l => l.id === locale);
|
||||
document.body.lang = locale;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
.branch-prefix-dialog .branch-prefix-notes-list {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.branch-prefix-dialog .branch-prefix-notes-list ul {
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.branch-prefix-dialog .branch-prefix-current {
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -10,86 +10,53 @@ import Button from "../react/Button.jsx";
|
||||
import FormGroup from "../react/FormGroup.js";
|
||||
import { useTriliumEvent } from "../react/hooks.jsx";
|
||||
import FBranch from "../../entities/fbranch.js";
|
||||
import type { ContextMenuCommandData } from "../../components/app_context.js";
|
||||
import "./branch_prefix.css";
|
||||
|
||||
// Virtual branches (e.g., from search results) start with this prefix
|
||||
const VIRTUAL_BRANCH_PREFIX = "virt-";
|
||||
|
||||
export default function BranchPrefixDialog() {
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const [ branches, setBranches ] = useState<FBranch[]>([]);
|
||||
const [ branch, setBranch ] = useState<FBranch>();
|
||||
const [ prefix, setPrefix ] = useState("");
|
||||
const branchInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
useTriliumEvent("editBranchPrefix", async (data?: ContextMenuCommandData) => {
|
||||
let branchIds: string[] = [];
|
||||
|
||||
if (data?.selectedOrActiveBranchIds && data.selectedOrActiveBranchIds.length > 0) {
|
||||
// Multi-select mode from tree context menu
|
||||
branchIds = data.selectedOrActiveBranchIds.filter((branchId) => !branchId.startsWith(VIRTUAL_BRANCH_PREFIX));
|
||||
} else {
|
||||
// Single branch mode from keyboard shortcut or when no selection
|
||||
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath);
|
||||
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const branchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!branchId) {
|
||||
return;
|
||||
}
|
||||
const parentNote = await froca.getNote(parentNoteId);
|
||||
if (!parentNote || parentNote.type === "search") {
|
||||
return;
|
||||
}
|
||||
|
||||
branchIds = [branchId];
|
||||
}
|
||||
|
||||
if (branchIds.length === 0) {
|
||||
useTriliumEvent("editBranchPrefix", async () => {
|
||||
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newBranches = branchIds
|
||||
.map(id => froca.getBranch(id))
|
||||
.filter((branch): branch is FBranch => branch !== null);
|
||||
const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath);
|
||||
|
||||
if (newBranches.length === 0) {
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
setBranches(newBranches);
|
||||
// Use the prefix of the first branch as the initial value
|
||||
setPrefix(newBranches[0]?.prefix ?? "");
|
||||
const newBranchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!newBranchId) {
|
||||
return;
|
||||
}
|
||||
const parentNote = await froca.getNote(parentNoteId);
|
||||
if (!parentNote || parentNote.type === "search") {
|
||||
return;
|
||||
}
|
||||
|
||||
const newBranch = froca.getBranch(newBranchId);
|
||||
setBranch(newBranch);
|
||||
setPrefix(newBranch?.prefix ?? "");
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
async function onSubmit() {
|
||||
if (branches.length === 0) {
|
||||
if (!branch) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (branches.length === 1) {
|
||||
await savePrefix(branches[0].branchId, prefix);
|
||||
} else {
|
||||
await savePrefixBatch(branches.map(b => b.branchId), prefix);
|
||||
}
|
||||
savePrefix(branch.branchId, prefix);
|
||||
setShown(false);
|
||||
}
|
||||
|
||||
const isSingleBranch = branches.length === 1;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="branch-prefix-dialog"
|
||||
title={isSingleBranch ? t("branch_prefix.edit_branch_prefix") : t("branch_prefix.edit_branch_prefix_multiple", { count: branches.length })}
|
||||
title={t("branch_prefix.edit_branch_prefix")}
|
||||
size="lg"
|
||||
onShown={() => branchInput.current?.focus()}
|
||||
onHidden={() => setShown(false)}
|
||||
@@ -102,27 +69,9 @@ export default function BranchPrefixDialog() {
|
||||
<div class="input-group">
|
||||
<input class="branch-prefix-input form-control" value={prefix} ref={branchInput}
|
||||
onChange={(e) => setPrefix((e.target as HTMLInputElement).value)} />
|
||||
{isSingleBranch && branches[0] && (
|
||||
<div class="branch-prefix-note-title input-group-text"> - {branches[0].getNoteFromCache().title}</div>
|
||||
)}
|
||||
<div class="branch-prefix-note-title input-group-text"> - {branch && branch.getNoteFromCache().title}</div>
|
||||
</div>
|
||||
</FormGroup>
|
||||
{!isSingleBranch && (
|
||||
<div className="branch-prefix-notes-list">
|
||||
<strong>{t("branch_prefix.affected_branches", { count: branches.length })}</strong>
|
||||
<ul>
|
||||
{branches.map((branch) => {
|
||||
const note = branch.getNoteFromCache();
|
||||
return (
|
||||
<li key={branch.branchId}>
|
||||
{branch.prefix && <span className="branch-prefix-current">{branch.prefix} - </span>}
|
||||
{note.title}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -131,8 +80,3 @@ async function savePrefix(branchId: string, prefix: string) {
|
||||
await server.put(`branches/${branchId}/set-prefix`, { prefix: prefix });
|
||||
toast.showMessage(t("branch_prefix.branch_prefix_saved"));
|
||||
}
|
||||
|
||||
async function savePrefixBatch(branchIds: string[], prefix: string) {
|
||||
await server.put("branches/set-prefix-batch", { branchIds, prefix });
|
||||
toast.showMessage(t("branch_prefix.branch_prefix_saved_multiple", { count: branchIds.length }));
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ export default function ExportDialog() {
|
||||
values={[
|
||||
{ value: "html", label: t("export.format_html_zip") },
|
||||
{ value: "markdown", label: t("export.format_markdown") },
|
||||
{ value: "share", label: t("export.share-format") },
|
||||
{ value: "opml", label: t("export.format_opml") }
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,6 @@ import utils from "../../services/utils";
|
||||
import Modal from "../react/Modal";
|
||||
import Button from "../react/Button";
|
||||
import { useTriliumEvent } from "../react/hooks";
|
||||
import EditableTextTypeWidget from "../type_widgets/editable_text";
|
||||
|
||||
interface RenderMarkdownResponse {
|
||||
htmlContent: string;
|
||||
@@ -15,34 +14,39 @@ interface RenderMarkdownResponse {
|
||||
|
||||
export default function MarkdownImportDialog() {
|
||||
const markdownImportTextArea = useRef<HTMLTextAreaElement>(null);
|
||||
const [textTypeWidget, setTextTypeWidget] = useState<EditableTextTypeWidget>();
|
||||
const [ text, setText ] = useState("");
|
||||
const [ shown, setShown ] = useState(false);
|
||||
|
||||
useTriliumEvent("showPasteMarkdownDialog", ({ textTypeWidget }) => {
|
||||
setTextTypeWidget(textTypeWidget);
|
||||
const triggerImport = useCallback(() => {
|
||||
if (appContext.tabManager.getActiveContextNoteType() !== "text") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
const { clipboard } = utils.dynamicRequire("electron");
|
||||
const text = clipboard.readText();
|
||||
|
||||
convertMarkdownToHtml(text, textTypeWidget);
|
||||
convertMarkdownToHtml(text);
|
||||
} else {
|
||||
setShown(true);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
useTriliumEvent("importMarkdownInline", triggerImport);
|
||||
useTriliumEvent("pasteMarkdownIntoText", triggerImport);
|
||||
|
||||
async function sendForm() {
|
||||
await convertMarkdownToHtml(text);
|
||||
setText("");
|
||||
setShown(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="markdown-import-dialog" title={t("markdown_import.dialog_title")} size="lg"
|
||||
footer={<Button className="markdown-import-button" text={t("markdown_import.import_button")} onClick={() => setShown(false)} keyboardShortcut="Ctrl+Enter" />}
|
||||
footer={<Button className="markdown-import-button" text={t("markdown_import.import_button")} onClick={sendForm} keyboardShortcut="Ctrl+Space" />}
|
||||
onShown={() => markdownImportTextArea.current?.focus()}
|
||||
onHidden={async () => {
|
||||
if (textTypeWidget) {
|
||||
await convertMarkdownToHtml(text, textTypeWidget);
|
||||
}
|
||||
setShown(false);
|
||||
setText("");
|
||||
}}
|
||||
onHidden={() => setShown(false) }
|
||||
show={shown}
|
||||
>
|
||||
<p>{t("markdown_import.modal_body_text")}</p>
|
||||
@@ -52,17 +56,26 @@ export default function MarkdownImportDialog() {
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" && e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
setShown(false);
|
||||
sendForm();
|
||||
}
|
||||
}}></textarea>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
async function convertMarkdownToHtml(markdownContent: string, textTypeWidget: EditableTextTypeWidget) {
|
||||
async function convertMarkdownToHtml(markdownContent: string) {
|
||||
const { htmlContent } = await server.post<RenderMarkdownResponse>("other/render-markdown", { markdownContent });
|
||||
|
||||
await textTypeWidget.addHtmlToEditor(htmlContent);
|
||||
|
||||
const textEditor = await appContext.tabManager.getActiveContext()?.getTextEditor();
|
||||
if (!textEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewFragment = textEditor.data.processor.toView(htmlContent);
|
||||
const modelFragment = textEditor.data.toModel(viewFragment);
|
||||
|
||||
textEditor.model.insertContent(modelFragment, textEditor.model.document.selection);
|
||||
textEditor.editing.view.focus();
|
||||
|
||||
toast.showMessage(t("markdown_import.import_success"));
|
||||
}
|
||||
@@ -57,19 +57,17 @@ const TPL = /*html*/`\
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="quick-edit-dialog-wrapper">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">
|
||||
<!-- This is where the first child will be injected -->
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">
|
||||
<!-- This is where the first child will be injected -->
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- This is where all but the first child will be injected. -->
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- This is where all but the first child will be injected. -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,7 +79,6 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
|
||||
private noteContext: NoteContext;
|
||||
private $modalHeader!: JQuery<HTMLElement>;
|
||||
private $modalBody!: JQuery<HTMLElement>;
|
||||
private $wrapper!: JQuery<HTMLDivElement>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -96,7 +93,6 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
|
||||
const $newWidget = $(TPL);
|
||||
this.$modalHeader = $newWidget.find(".modal-title");
|
||||
this.$modalBody = $newWidget.find(".modal-body");
|
||||
this.$wrapper = $newWidget.find(".quick-edit-dialog-wrapper");
|
||||
|
||||
const children = this.$widget.children();
|
||||
this.$modalHeader.append(children[0]);
|
||||
@@ -116,21 +112,6 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
|
||||
}
|
||||
});
|
||||
|
||||
const colorClass = this.noteContext.note?.getColorClass();
|
||||
const wrapperElement = this.$wrapper.get(0)!;
|
||||
|
||||
if (colorClass) {
|
||||
wrapperElement.className = "quick-edit-dialog-wrapper " + colorClass;
|
||||
} else {
|
||||
wrapperElement.className = "quick-edit-dialog-wrapper";
|
||||
}
|
||||
|
||||
const customHue = getComputedStyle(wrapperElement).getPropertyValue("--custom-color-hue");
|
||||
if (customHue) {
|
||||
/* Apply the tinted-dialog class only if the custom color CSS class specifies a hue */
|
||||
wrapperElement.classList.add("tinted-quick-edit-dialog");
|
||||
}
|
||||
|
||||
const activeEl = document.activeElement;
|
||||
if (activeEl && "blur" in activeEl) {
|
||||
(activeEl as HTMLElement).blur();
|
||||
@@ -174,11 +155,6 @@ export default class PopupEditorDialog extends Container<BasicWidget> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Avoid not showing recent notes when creating a new empty tab.
|
||||
if ("noteContext" in data && data.noteContext.ntxId !== "_popup-editor") {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return super.handleEventInChildren(name, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,10 +140,11 @@ function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: Re
|
||||
<FormList onSelect={onSelect} fullHeight>
|
||||
{revisions.map((item) =>
|
||||
<FormListItem
|
||||
title={t("revisions.revision_last_edited", { date: item.dateLastEdited })}
|
||||
value={item.revisionId}
|
||||
active={currentRevision && item.revisionId === currentRevision.revisionId}
|
||||
>
|
||||
{item.dateCreated && item.dateCreated.substr(0, 16)} ({item.contentLength && utils.formatSize(item.contentLength)})
|
||||
{item.dateLastEdited && item.dateLastEdited.substr(0, 16)} ({item.contentLength && utils.formatSize(item.contentLength)})
|
||||
</FormListItem>
|
||||
)}
|
||||
</FormList>);
|
||||
|
||||
@@ -147,12 +147,6 @@ const categories: Category[] = [
|
||||
];
|
||||
|
||||
const icons: Icon[] = [
|
||||
{
|
||||
name: "empty",
|
||||
slug: "empty",
|
||||
category_id: 113,
|
||||
type_of_icon: "REGULAR"
|
||||
},
|
||||
{
|
||||
name: "child",
|
||||
slug: "child-regular",
|
||||
|
||||
@@ -39,16 +39,10 @@ const TPL = /*html*/`
|
||||
<div class="note-detail">
|
||||
<style>
|
||||
.note-detail {
|
||||
max-width: var(--max-content-width); /* Inherited from .note-split */
|
||||
font-family: var(--detail-font-family);
|
||||
font-size: var(--detail-font-size);
|
||||
}
|
||||
|
||||
body.prefers-centered-content .note-detail {
|
||||
/* Horizontally center the widget in its parent when the "Keep content centered" option is on */
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.note-detail.full-height {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -56,16 +56,4 @@
|
||||
|
||||
.note-icon-widget .icon-list span:hover {
|
||||
border: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
.note-icon-widget .icon-list span.bx-empty {
|
||||
width: unset;
|
||||
}
|
||||
|
||||
.note-icon-widget .icon-list span.bx-empty::before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
border: 1px dashed var(--muted-text-color);
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
@@ -1591,20 +1591,6 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
this.clearSelectedNodes();
|
||||
}
|
||||
|
||||
async editBranchPrefixCommand({ node }: CommandListenerData<"editBranchPrefix">) {
|
||||
const branchIds = this.getSelectedOrActiveBranchIds(node).filter((branchId) => !branchId.startsWith("virt-"));
|
||||
|
||||
if (!branchIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger the event with the selected branch IDs
|
||||
appContext.triggerEvent("editBranchPrefix", {
|
||||
selectedOrActiveBranchIds: branchIds,
|
||||
node: node
|
||||
});
|
||||
}
|
||||
|
||||
canBeMovedUpOrDown(node: Fancytree.FancytreeNode) {
|
||||
if (node.data.noteId === "root") {
|
||||
return false;
|
||||
|
||||
@@ -52,7 +52,6 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
|
||||
|
||||
const note = this.noteContext?.note;
|
||||
if (!note) {
|
||||
this.$widget.addClass("bgfx");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
|
||||
|
||||
this.$widget.addClass(utils.getNoteTypeClass(note.type));
|
||||
this.$widget.addClass(utils.getMimeTypeClass(note.mime));
|
||||
this.$widget.toggleClass(["bgfx", "options"], note.isOptions());
|
||||
|
||||
this.$widget.toggleClass("protected", note.isProtected);
|
||||
|
||||
const noteLanguage = note?.getLabelValue("language");
|
||||
@@ -71,7 +70,7 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
|
||||
}
|
||||
|
||||
#isFullWidthNote(note: FNote) {
|
||||
if (["code", "image", "mermaid", "book", "render", "canvas", "webView", "mindMap"].includes(note.type)) {
|
||||
if (["image", "mermaid", "book", "render", "canvas", "webView", "mindMap"].includes(note.type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
.info-bar {
|
||||
margin-top: 4px;
|
||||
padding: 8px 20px;
|
||||
color: var(--read-only-note-info-bar-color);
|
||||
font-size: .9em;
|
||||
|
||||
}
|
||||
|
||||
.info-bar-prominent {
|
||||
background: var(--alert-bar-background, var(--accented-background-color));
|
||||
}
|
||||
|
||||
.info-bar-subtle {
|
||||
color: var(--muted-text-color);
|
||||
border-bottom: 1px solid var(--main-border-color);
|
||||
margin-block: 0;
|
||||
margin-inline: 10px;
|
||||
padding-inline: 12px;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { ComponentChildren } from "preact";
|
||||
|
||||
import "./InfoBar.css";
|
||||
|
||||
export type InfoBarParams = {
|
||||
type: "prominent" | "subtle"
|
||||
children: ComponentChildren;
|
||||
};
|
||||
|
||||
export default function InfoBar(props: InfoBarParams) {
|
||||
return <div className={`info-bar info-bar-${props.type}`}>
|
||||
{props?.children}
|
||||
</div>
|
||||
}
|
||||
|
||||
InfoBar.defaultProps = {
|
||||
type: "prominent"
|
||||
} as InfoBarParams
|
||||
@@ -1,26 +1,25 @@
|
||||
import { CSSProperties } from "preact/compat";
|
||||
import { DragData } from "../note_tree";
|
||||
import { FilterLabelsByType, KeyboardActionNames, OptionNames, RelationNames } from "@triliumnext/commons";
|
||||
import { Inputs, MutableRef, useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { CommandListenerData, EventData, EventNames } from "../../components/app_context";
|
||||
import { ParentComponent } from "./react_utils";
|
||||
import SpacedUpdate from "../../services/spaced_update";
|
||||
import { FilterLabelsByType, KeyboardActionNames, OptionNames, RelationNames } from "@triliumnext/commons";
|
||||
import options, { type OptionValue } from "../../services/options";
|
||||
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
||||
import NoteContext from "../../components/note_context";
|
||||
import BasicWidget, { ReactWrappedWidget } from "../basic_widget";
|
||||
import FNote from "../../entities/fnote";
|
||||
import attributes from "../../services/attributes";
|
||||
import FBlob from "../../entities/fblob";
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||
import { RefObject, VNode } from "preact";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import { ViewMode } from "../../services/link";
|
||||
import appContext, { CommandListenerData, EventData, EventNames } from "../../components/app_context";
|
||||
import attributes from "../../services/attributes";
|
||||
import BasicWidget, { ReactWrappedWidget } from "../basic_widget";
|
||||
import Component from "../../components/component";
|
||||
import FBlob from "../../entities/fblob";
|
||||
import FNote from "../../entities/fnote";
|
||||
import { CSSProperties } from "preact/compat";
|
||||
import keyboard_actions from "../../services/keyboard_actions";
|
||||
import Mark from "mark.js";
|
||||
import NoteContext from "../../components/note_context";
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||
import options, { type OptionValue } from "../../services/options";
|
||||
import protected_session_holder from "../../services/protected_session_holder";
|
||||
import SpacedUpdate from "../../services/spaced_update";
|
||||
import { DragData } from "../note_tree";
|
||||
import Component from "../../components/component";
|
||||
import toast, { ToastOptions } from "../../services/toast";
|
||||
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
||||
import { ViewMode } from "../../services/link";
|
||||
|
||||
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
||||
const parentComponent = useContext(ParentComponent);
|
||||
@@ -702,51 +701,3 @@ export function useResizeObserver(ref: RefObject<HTMLElement>, callback: () => v
|
||||
return () => observer.disconnect();
|
||||
}, [ callback, ref ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the current note is in read-only mode, while an editing mode is available,
|
||||
* and provides a way to switch to editing mode.
|
||||
*/
|
||||
export function useIsNoteReadOnly(note: FNote | null | undefined, noteContext: NoteContext | undefined) {
|
||||
const [isReadOnly, setIsReadOnly] = useState<boolean | undefined>(undefined);
|
||||
|
||||
const enableEditing = useCallback(() => {
|
||||
if (noteContext?.viewScope) {
|
||||
noteContext.viewScope.readOnlyTemporarilyDisabled = true;
|
||||
appContext.triggerEvent("readOnlyTemporarilyDisabled", {noteContext});
|
||||
}
|
||||
}, [noteContext]);
|
||||
|
||||
useEffect(() => {
|
||||
if (note && noteContext) {
|
||||
isNoteReadOnly(note, noteContext).then((readOnly) => {
|
||||
setIsReadOnly(readOnly);
|
||||
});
|
||||
}
|
||||
}, [note, noteContext]);
|
||||
|
||||
useTriliumEvent("readOnlyTemporarilyDisabled", ({noteContext: eventNoteContext}) => {
|
||||
if (noteContext?.ntxId === eventNoteContext.ntxId) {
|
||||
setIsReadOnly(false);
|
||||
}
|
||||
});
|
||||
|
||||
return {isReadOnly, enableEditing};
|
||||
}
|
||||
|
||||
async function isNoteReadOnly(note: FNote, noteContext: NoteContext) {
|
||||
|
||||
if (note.isProtected && !protected_session_holder.isProtectedSessionAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.is("databaseReadonly")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (noteContext.viewScope?.viewMode !== "default" || !await noteContext.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
div.read-only-note-info-bar-widget {
|
||||
contain: none;
|
||||
}
|
||||
|
||||
div.read-only-note-info-bar-widget.zen-mode-only {
|
||||
display: none;
|
||||
max-width: var(--max-content-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
div.read-only-note-info-bar-widget.zen-mode-only .info-bar {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
body.zen div.read-only-note-info-bar-widget.zen-mode-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.read-only-note-info-bar-widget-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
:root div.read-only-note-info-bar-widget button {
|
||||
white-space: nowrap;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import "./read_only_note_info_bar.css";
|
||||
import { t } from "../services/i18n";
|
||||
import { useIsNoteReadOnly, useNoteContext, useTriliumEvent } from "./react/hooks"
|
||||
import Button from "./react/Button";
|
||||
import InfoBar from "./react/InfoBar";
|
||||
|
||||
export default function ReadOnlyNoteInfoBar(props: {zenModeOnly?: boolean}) {
|
||||
const {note, noteContext} = useNoteContext();
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
const isExplicitReadOnly = note?.isLabelTruthy("readOnly");
|
||||
|
||||
return <div class={`read-only-note-info-bar-widget ${(isReadOnly) ? "visible" : ""} ${(props.zenModeOnly) ? "zen-mode-only" : ""}`}>
|
||||
{isReadOnly && <InfoBar type={(isExplicitReadOnly ? "subtle" : "prominent")}>
|
||||
<div class="read-only-note-info-bar-widget-content">
|
||||
{(isExplicitReadOnly) ? (
|
||||
<div>{t("read-only-info.read-only-note")}</div>
|
||||
) : (
|
||||
<div>
|
||||
{t("read-only-info.auto-read-only-note")}
|
||||
|
||||
<a class="tn-link"
|
||||
href="https://docs.triliumnotes.org/user-guide/concepts/notes/read-only-notes#automatic-read-only-mode">
|
||||
|
||||
{t("read-only-info.auto-read-only-learn-more")}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button text={t("read-only-info.edit-note")}
|
||||
icon="bx-pencil" onClick={() => enableEditing()} />
|
||||
</div>
|
||||
</InfoBar>}
|
||||
</div>;
|
||||
}
|
||||
@@ -13,8 +13,8 @@ export default function EditedNotesTab({ note }: TabContext) {
|
||||
useEffect(() => {
|
||||
if (!note) return;
|
||||
server.get<EditedNotesResponse>(`edited-notes/${note.getLabelValue("dateNote")}`).then(async editedNotes => {
|
||||
editedNotes = editedNotes.filter((n) => n.noteId !== note.noteId);
|
||||
const noteIds = editedNotes.flatMap((n) => n.noteId);
|
||||
editedNotes = editedNotes.filter((n) => n.noteId !== note.noteId);
|
||||
const noteIds = editedNotes.flatMap((n) => n.noteId);
|
||||
await froca.getNotes(noteIds, true); // preload all at once
|
||||
setEditedNotes(editedNotes);
|
||||
});
|
||||
@@ -41,11 +41,11 @@ export default function EditedNotesTab({ note }: TabContext) {
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}), " ")}
|
||||
}))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="no-edited-notes-found">{t("edited_notes.no_edited_notes_found")}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import { ConvertToAttachmentResponse } from "@triliumnext/commons";
|
||||
import { FormDropdownDivider, FormListItem } from "../react/FormList";
|
||||
import { isElectron as getIsElectron, isMac as getIsMac } from "../../services/utils";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import { t } from "../../services/i18n"
|
||||
import { useContext } from "preact/hooks";
|
||||
import { useIsNoteReadOnly } from "../react/hooks";
|
||||
import ActionButton from "../react/ActionButton"
|
||||
import appContext, { CommandNames } from "../../components/app_context";
|
||||
import branches from "../../services/branches";
|
||||
import dialog from "../../services/dialog";
|
||||
import Dropdown from "../react/Dropdown";
|
||||
import FNote from "../../entities/fnote"
|
||||
import NoteContext from "../../components/note_context";
|
||||
import dialog from "../../services/dialog";
|
||||
import { t } from "../../services/i18n"
|
||||
import server from "../../services/server";
|
||||
import toast from "../../services/toast";
|
||||
import ws from "../../services/ws";
|
||||
import ActionButton from "../react/ActionButton"
|
||||
import Dropdown from "../react/Dropdown";
|
||||
import { FormDropdownDivider, FormListItem } from "../react/FormList";
|
||||
import { isElectron as getIsElectron, isMac as getIsMac } from "../../services/utils";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import { useContext } from "preact/hooks";
|
||||
import NoteContext from "../../components/note_context";
|
||||
import branches from "../../services/branches";
|
||||
|
||||
interface NoteActionsProps {
|
||||
note?: FNote;
|
||||
@@ -53,7 +52,6 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
|
||||
const isMac = getIsMac();
|
||||
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap"].includes(note.type);
|
||||
const isSearchOrBook = ["search", "book"].includes(note.type);
|
||||
const {isReadOnly, enableEditing} = useIsNoteReadOnly(note, noteContext);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
@@ -61,14 +59,8 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
|
||||
className="note-actions"
|
||||
hideToggleArrow
|
||||
noSelectButtonStyle
|
||||
iconAction>
|
||||
|
||||
{isReadOnly && <>
|
||||
<CommandItem icon="bx bx-pencil" text={t("read-only-info.edit-note")}
|
||||
command={() => enableEditing()} />
|
||||
<FormDropdownDivider />
|
||||
</>}
|
||||
|
||||
iconAction
|
||||
>
|
||||
{canBeConvertedToAttachment && <ConvertToAttachment note={note} /> }
|
||||
{note.type === "render" && <CommandItem command="renderActiveNote" icon="bx bx-extension" text={t("note_actions.re_render_note")} />}
|
||||
<CommandItem command="findInText" icon="bx bx-search" disabled={!isSearchable} text={t("note_actions.search_in_note")} />
|
||||
|
||||
@@ -264,6 +264,7 @@
|
||||
position: absolute;
|
||||
inset-inline-end: 5px;
|
||||
bottom: 5px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.style-resolver {
|
||||
|
||||
@@ -329,30 +329,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
});
|
||||
}
|
||||
|
||||
async addHtmlToEditor(html: string) {
|
||||
await this.initialized;
|
||||
|
||||
const editor = this.watchdog.editor;
|
||||
if (!editor) return;
|
||||
|
||||
editor.model.change((writer) => {
|
||||
const viewFragment = editor.data.processor.toView(html);
|
||||
const modelFragment = editor.data.toModel(viewFragment);
|
||||
const insertPosition = editor.model.document.selection.getLastPosition();
|
||||
|
||||
if (insertPosition) {
|
||||
const range = editor.model.insertContent(modelFragment, insertPosition);
|
||||
|
||||
if (range) {
|
||||
writer.setSelection(range.end);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
editor.editing.view.focus();
|
||||
}
|
||||
|
||||
addTextToActiveEditorEvent({ text }: EventData<"addTextToActiveEditor">) {
|
||||
if (!this.isActive()) {
|
||||
return;
|
||||
@@ -409,10 +385,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
this.triggerCommand("showAddLinkDialog", { textTypeWidget: this, text: selectedText });
|
||||
}
|
||||
|
||||
pasteMarkdownIntoTextCommand() {
|
||||
this.triggerCommand("showPasteMarkdownDialog", { textTypeWidget: this });
|
||||
}
|
||||
|
||||
getSelectedText() {
|
||||
const range = this.watchdog.editor?.model.document.selection.getFirstRange();
|
||||
let text = "";
|
||||
|
||||
@@ -284,8 +284,7 @@ function SmoothScrollEnabledOption() {
|
||||
}
|
||||
|
||||
function MaxContentWidth() {
|
||||
const [maxContentWidth, setMaxContentWidth] = useTriliumOption("maxContentWidth");
|
||||
const [centerContent, setCenterContent] = useTriliumOptionBool("centerContent");
|
||||
const [ maxContentWidth, setMaxContentWidth ] = useTriliumOption("maxContentWidth");
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("max_content_width.title")}>
|
||||
@@ -301,9 +300,9 @@ function MaxContentWidth() {
|
||||
</FormGroup>
|
||||
</Column>
|
||||
|
||||
<FormCheckbox label={t("max_content_width.centerContent")}
|
||||
currentValue={centerContent}
|
||||
onChange={setCenterContent} />
|
||||
<p>
|
||||
{t("max_content_width.apply_changes_description")} <Button text={t("max_content_width.reload_button")} size="micro" onClick={reloadFrontendApp} />
|
||||
</p>
|
||||
</OptionsSection>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ComponentChildren } from "preact";
|
||||
import { CSSProperties } from "preact/compat";
|
||||
|
||||
interface OptionsSectionProps {
|
||||
title?: ComponentChildren;
|
||||
title?: string;
|
||||
children: ComponentChildren;
|
||||
noCard?: boolean;
|
||||
style?: CSSProperties;
|
||||
|
||||
@@ -11,7 +11,6 @@ import dialog from "../../../services/dialog";
|
||||
import { formatDateTime } from "../../../utils/formatters";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import { useTriliumEvent } from "../../react/hooks";
|
||||
import HelpButton from "../../react/HelpButton";
|
||||
|
||||
type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>;
|
||||
type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>;
|
||||
@@ -49,13 +48,19 @@ export default function EtapiSettings() {
|
||||
message: t("etapi.token_created_message"),
|
||||
defaultValue: authToken
|
||||
});
|
||||
}, []);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("etapi.title")}>
|
||||
<FormText>
|
||||
{t("etapi.description")}
|
||||
<HelpButton helpPage="pgxEVkzLl1OP" />
|
||||
{t("etapi.description")}<br />
|
||||
<RawHtml
|
||||
html={t("etapi.see_more", {
|
||||
link_to_wiki: `<a class="tn-link" href="https://triliumnext.github.io/Docs/Wiki/etapi.html">${t("etapi.wiki")}</a>`,
|
||||
// TODO: We use window.open src/public/app/services/link.ts -> prevents regular click behavior on "a" element here because it's a relative path
|
||||
link_to_openapi_spec: `<a class="tn-link" onclick="window.open('etapi/etapi.openapi.yaml')" href="etapi/etapi.openapi.yaml">${t("etapi.openapi_spec")}</a>`,
|
||||
link_to_swagger_ui: `<a class="tn-link" href="#_help_f3xpgx6H01PW">${t("etapi.swagger_ui")}</a>`
|
||||
})} />
|
||||
</FormText>
|
||||
|
||||
<Button
|
||||
@@ -63,7 +68,6 @@ export default function EtapiSettings() {
|
||||
text={t("etapi.create_token")}
|
||||
onClick={createTokenCallback}
|
||||
/>
|
||||
|
||||
<hr />
|
||||
|
||||
<h5>{t("etapi.existing_tokens")}</h5>
|
||||
@@ -97,7 +101,7 @@ function TokenList({ tokens }: { tokens: EtapiToken[] }) {
|
||||
|
||||
return (
|
||||
tokens.length ? (
|
||||
<div style={{ overflow: "auto"}}>
|
||||
<div style={{ overflow: "auto", height: "500px"}}>
|
||||
<table className="table table-stripped">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -119,7 +123,7 @@ function TokenList({ tokens }: { tokens: EtapiToken[] }) {
|
||||
text={t("etapi.rename_token")}
|
||||
onClick={() => renameCallback(etapiTokenId, name)}
|
||||
/>
|
||||
|
||||
|
||||
<ActionButton
|
||||
icon="bx bx-trash"
|
||||
text={t("etapi.delete_token")}
|
||||
|
||||
@@ -72,8 +72,8 @@ function EditorFeatures() {
|
||||
return (
|
||||
<OptionsSection title={t("editorfeatures.title")}>
|
||||
<EditorFeature name="emoji-completion-enabled" optionName="textNoteEmojiCompletionEnabled" label={t("editorfeatures.emoji_completion_enabled")} description={t("editorfeatures.emoji_completion_description")} />
|
||||
<EditorFeature name="note-completion-enabled" optionName="textNoteCompletionEnabled" label={t("editorfeatures.note_completion_enabled")} description={t("editorfeatures.note_completion_description")} />
|
||||
<EditorFeature name="slash-commands-enabled" optionName="textNoteSlashCommandsEnabled" label={t("editorfeatures.slash_commands_enabled")} description={t("editorfeatures.slash_commands_description")} />
|
||||
<EditorFeature name="note-completion-enabled" optionName="textNoteCompletionEnabled" label={t("editorfeatures.note_completion_enabled")} description={t("editorfeatures.emoji_completion_description")} />
|
||||
<EditorFeature name="slash-commands-enabled" optionName="textNoteSlashCommandsEnabled" label={t("editorfeatures.slash_commands_enabled")} description={t("editorfeatures.emoji_completion_description")} />
|
||||
</OptionsSection>
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user