Compare commits

..

1 Commits

Author SHA1 Message Date
Adorian Doran
ff06376a30 website: tweak the download button 2025-10-06 16:37:41 +03:00
1228 changed files with 23801 additions and 60220 deletions

View File

@@ -10,9 +10,9 @@ runs:
steps:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: "pnpm"
- name: Install dependencies
shell: bash

View File

@@ -67,7 +67,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@@ -95,6 +95,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@@ -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,31 +49,75 @@ 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.13'
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
uses: actions/setup-node@v5
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
if: github.repository == ${{ vars.REPO_MAIN }}
with:
project_name: "trilium-docs"
comment_body: "📚 Documentation preview is ready"

View File

@@ -28,9 +28,9 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: "pnpm"
- run: pnpm install --frozen-lockfile

View File

@@ -44,9 +44,9 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
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 }}
@@ -144,9 +144,9 @@ jobs:
uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: 'pnpm'
- name: Install dependencies
@@ -155,10 +155,6 @@ jobs:
- name: Update build info
run: pnpm run chore:update-build-info
- name: Update nightly version
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
run: pnpm run chore:ci-update-nightly-version
- name: Run the TypeScript build
run: pnpm run server:build
@@ -213,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/*
@@ -227,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-*

View File

@@ -50,14 +50,14 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Update nightly version
run: pnpm run chore:ci-update-nightly-version
run: npm run chore:ci-update-nightly-version
- name: Run the build
uses: ./.github/actions/build-electron
with:
@@ -77,7 +77,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release
uses: softprops/action-gh-release@v2.4.2
uses: softprops/action-gh-release@v2.3.4
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false
@@ -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 }}
@@ -118,7 +118,7 @@ jobs:
arch: ${{ matrix.arch }}
- name: Publish release
uses: softprops/action-gh-release@v2.4.2
uses: softprops/action-gh-release@v2.3.4
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false

View File

@@ -4,7 +4,6 @@ on:
push:
branches:
- main
- hotfix
paths-ignore:
- "apps/website/**"
pull_request:
@@ -14,24 +13,8 @@ permissions:
contents: read
jobs:
e2e:
strategy:
fail-fast: false
matrix:
include:
- name: linux-x64
os: ubuntu-22.04
arch: x64
- name: linux-arm64
os: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.os }}
name: E2E tests on ${{ matrix.name }}
env:
TRILIUM_DOCKER: 1
TRILIUM_PORT: 8082
TRILIUM_DATA_DIR: "${{ github.workspace }}/apps/server/spec/db"
TRILIUM_INTEGRATION_TEST: memory
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
@@ -39,49 +22,20 @@ jobs:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
- uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps
- name: Build the server
uses: ./.github/actions/build-server
with:
os: linux
arch: ${{ matrix.arch }}
- name: Unpack and start the server
run: |
version=$(node --eval "console.log(require('./package.json').version)")
file=$(find ./upload -name '*.tar.xz' -print -quit)
name=$(basename "$file" .tar.xz)
mkdir -p ./server-dist
tar -xvf "$file" -C ./server-dist
server_dir="./server-dist/TriliumNotes-Server-$version-linux-${{ matrix.arch }}"
if [ ! -d "$server_dir" ]; then
echo Missing dir.
exit 1
fi
cd "$server_dir"
"./trilium.sh" &
sleep 10
- name: Server end-to-end tests
run: pnpm --filter server-e2e e2e
- run: pnpm --filter server-e2e e2e
- 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
- name: Kill the server
if: always()
run: pkill -f trilium || true

View File

@@ -48,9 +48,9 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
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,14 +120,14 @@ jobs:
docs/Release Notes
- name: Download all artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v5
with:
merge-multiple: true
pattern: release-*
path: upload
- name: Publish stable release
uses: softprops/action-gh-release@v2.4.2
uses: softprops/action-gh-release@v2.3.4
with:
draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

View File

@@ -11,9 +11,6 @@ on:
paths:
- "apps/website/**"
release:
types: [ released ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
@@ -28,9 +25,9 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v6
uses: actions/setup-node@v5
with:
node-version: 24
node-version: 22
cache: "pnpm"
- name: Install dependencies

2
.nvmrc
View File

@@ -1 +1 @@
24.11.1
22.20.0

View File

@@ -14,7 +14,6 @@ usageMatchRegex:
# the `{key}` will be placed by a proper keypath matching regex,
# you can ignore it and use your own matching rules as well
- "[^\\w\\d]t\\(['\"`]({key})['\"`]"
- <Trans\s*i18nKey="({key})"[^>]*>
# A RegEx to set a custom scope range. This scope will be used as a prefix when detecting keys
# and works like how the i18next framework identifies the namespace scope from the

View File

@@ -5,8 +5,7 @@
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": [
"apps/server/src/assets/translations",
"apps/client/src/translations",
"apps/website/public/translations"
"apps/client/src/translations"
],
"npm.exclude": [
"**/dist",

View File

@@ -1,14 +1,3 @@
<div align="center">
<sup>Special thanks to:</sup><br />
<a href="https://go.warp.dev/Trilium" target="_blank">
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-03.png"><br />
Warp, built for coding with multiple AI agents<br />
</a>
<sup>Available for macOS, Linux and Windows</sup>
</div>
<hr />
# Trilium Notes
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran) ![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)
@@ -24,10 +13,6 @@ See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for q
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest) stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) unstable development version, updated daily with the latest features and fixes.
## 📚 Documentation
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**
@@ -182,7 +167,7 @@ Please view the [documentation guide](https://github.com/TriliumNext/Trilium/blo
## 👏 Shoutouts
* [zadam](https://github.com/zadam) for the original concept and implementation of the application.
* [Sarah Hussein](https://github.com/Sarah-Hussein) for designing the application icon.
* [Larsa](https://github.com/LarsaSara) for designing the application icon.
* [nriver](https://github.com/nriver) for his work on internationalization.
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas.
* [antoniotejada](https://github.com/nriver) for the original syntax highlight widget.

View File

@@ -35,20 +35,22 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.56.1",
"@stylistic/eslint-plugin": "5.5.0",
"@types/express": "5.0.5",
"@types/node": "24.10.1",
"@types/yargs": "17.0.35",
"@playwright/test": "1.55.1",
"@stylistic/eslint-plugin": "5.4.0",
"@types/express": "5.0.3",
"@types/node": "22.18.8",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4",
"eslint": "9.39.1",
"eslint": "9.37.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.5",
"jsdoc": "4.0.4",
"lorem-ipsum": "2.0.8",
"rcedit": "5.0.1",
"rimraf": "6.1.0",
"tslib": "2.8.1"
"rcedit": "4.0.1",
"rimraf": "6.0.1",
"tslib": "2.8.1",
"typedoc": "0.28.13",
"typedoc-plugin-missing-exports": "4.1.0"
},
"optionalDependencies": {
"appdmg": "0.6.6"

View File

@@ -1,3 +1,4 @@
import type child_process from "child_process";
import { describe, beforeAll, afterAll } from "vitest";
let etapiAuthToken: string | undefined;
@@ -11,6 +12,8 @@ type SpecDefinitionsFunc = () => void;
function describeEtapi(description: string, specDefinitions: SpecDefinitionsFunc): void {
describe(description, () => {
let appProcess: ReturnType<typeof child_process.spawn>;
beforeAll(async () => {});
afterAll(() => {});

15
_regroup/typedoc.json Normal file
View 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"
}
]
}

View File

@@ -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.22.0",
"devDependencies": {
"@redocly/cli": "2.11.1",
"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"
}
}

View File

@@ -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, {});

View File

@@ -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);
});
});
}

View File

@@ -1,4 +0,0 @@
export default interface BuildContext {
gitRootDir: string;
baseDir: string;
}

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();

View File

@@ -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"
});
}
}

View File

@@ -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" });
}
}

View File

@@ -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"
}
]
}

View File

@@ -1,15 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"include": [],
"references": [
{
"path": "../server"
},
{
"path": "../client"
},
{
"path": "./tsconfig.app.json"
}
]
}

View File

@@ -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"
]
}

View File

@@ -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"
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.99.5",
"version": "0.99.1",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -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.37.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -25,42 +25,40 @@
"@fullcalendar/timegrid": "6.1.19",
"@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.2.0",
"@mind-elixir/node-menu": "5.0.1",
"@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8",
"@triliumnext/ckeditor5": "workspace:*",
"@triliumnext/codemirror": "workspace:*",
"@triliumnext/commons": "workspace:*",
"@triliumnext/highlightjs": "workspace:*",
"@triliumnext/share-theme": "workspace:*",
"@triliumnext/split.js": "workspace:*",
"autocomplete.js": "0.38.1",
"bootstrap": "5.3.8",
"boxicons": "2.1.4",
"color": "5.0.3",
"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",
"i18next": "25.6.2",
"globals": "16.4.0",
"i18next": "25.5.3",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6",
"katex": "0.16.25",
"katex": "0.16.23",
"knockout": "3.5.1",
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.4.2",
"mermaid": "11.12.1",
"mind-elixir": "5.3.5",
"marked": "16.3.0",
"mermaid": "11.12.0",
"mind-elixir": "5.1.1",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.2",
"react-i18next": "16.3.3",
"reveal.js": "5.2.1",
"react-i18next": "16.0.0",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
"vanilla-js-wheel-zoom": "9.0.4"
@@ -70,14 +68,13 @@
"@preact/preset-vite": "2.10.2",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33",
"@types/leaflet": "1.9.21",
"@types/leaflet": "1.9.20",
"@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": "19.0.2",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.4"
"vite-plugin-static-copy": "3.1.3"
}
}

View File

@@ -13,6 +13,7 @@ import MainTreeExecutors from "./main_tree_executors.js";
import toast from "../services/toast.js";
import ShortcutComponent from "./shortcut_component.js";
import { t, initLocale } from "../services/i18n.js";
import type NoteDetailWidget from "../widgets/note_detail.js";
import type { ResolveOptions } from "../widgets/dialogs/delete_notes.js";
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
import type { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js";
@@ -20,6 +21,8 @@ import type LoadResults from "../services/load_results.js";
import type { Attribute } from "../services/attribute_parser.js";
import type NoteTreeWidget from "../widgets/note_tree.js";
import type { default as NoteContext, GetTextEditorCallback } from "./note_context.js";
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.js";
import type { NativeImage, TouchBar } from "electron";
import TouchBarComponent from "./touch_bar.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
@@ -30,10 +33,6 @@ import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type RootContainer from "../widgets/containers/root_container.js";
import { SqlExecuteResults } from "@triliumnext/commons";
import { AddLinkOpts } from "../widgets/dialogs/add_link.jsx";
import { IncludeNoteOpts } from "../widgets/dialogs/include_note.jsx";
import { ReactWrappedWidget } from "../widgets/basic_widget.js";
import type { MarkdownImportOpts } from "../widgets/dialogs/markdown_import.jsx";
interface Layout {
getRootWidget: (appContext: AppContext) => RootContainer;
@@ -200,7 +199,7 @@ export type CommandMappings = {
resetLauncher: ContextMenuCommandData;
executeInActiveNoteDetailWidget: CommandData & {
callback: (value: ReactWrappedWidget) => void;
callback: (value: NoteDetailWidget | PromiseLike<NoteDetailWidget>) => void;
};
executeWithTextEditor: CommandData &
ExecuteCommandData<CKTextEditor> & {
@@ -212,19 +211,19 @@ export type CommandMappings = {
* Generally should not be invoked manually, as it is used by {@link NoteContext.getContentElement}.
*/
executeWithContentElement: CommandData & ExecuteCommandData<JQuery<HTMLElement>>;
executeWithTypeWidget: CommandData & ExecuteCommandData<ReactWrappedWidget | null>;
executeWithTypeWidget: CommandData & ExecuteCommandData<TypeWidget | null>;
addTextToActiveEditor: CommandData & {
text: string;
};
/** Works only in the electron context menu. */
replaceMisspelling: CommandData;
importMarkdownInline: CommandData;
showPasswordNotSet: CommandData;
showProtectedSessionPasswordDialog: CommandData;
showUploadAttachmentsDialog: CommandData & { noteId: string };
showIncludeNoteDialog: CommandData & IncludeNoteOpts;
showAddLinkDialog: CommandData & AddLinkOpts;
showPasteMarkdownDialog: CommandData & MarkdownImportOpts;
showIncludeNoteDialog: CommandData & { textTypeWidget: EditableTextTypeWidget };
showAddLinkDialog: CommandData & { textTypeWidget: EditableTextTypeWidget, text: string };
closeProtectedSessionPasswordDialog: CommandData;
copyImageReferenceToClipboard: CommandData;
copyImageToClipboard: CommandData;
@@ -271,7 +270,6 @@ export type CommandMappings = {
closeThisNoteSplit: CommandData;
moveThisNoteSplit: CommandData & { isMovingLeft: boolean };
jumpToNote: CommandData;
openTodayNote: CommandData;
commandPalette: CommandData;
// Keyboard shortcuts
@@ -329,7 +327,6 @@ export type CommandMappings = {
exportAsPdf: CommandData;
openNoteExternally: CommandData;
openNoteCustom: CommandData;
openNoteOnServer: CommandData;
renderActiveNote: CommandData;
unhoist: CommandData;
reloadFrontendApp: CommandData;
@@ -487,8 +484,13 @@ type EventMappings = {
relationMapResetZoomIn: { ntxId: string | null | undefined };
relationMapResetZoomOut: { ntxId: string | null | undefined };
activeNoteChanged: {};
showAddLinkDialog: AddLinkOpts;
showIncludeDialog: IncludeNoteOpts;
showAddLinkDialog: {
textTypeWidget: EditableTextTypeWidget;
text: string;
};
showIncludeDialog: {
textTypeWidget: EditableTextTypeWidget;
};
openBulkActionsDialog: {
selectedOrActiveNoteIds: string[];
};
@@ -496,10 +498,6 @@ type EventMappings = {
noteIds: string[];
};
refreshData: { ntxId: string | null | undefined };
contentSafeMarginChanged: {
top: number;
noteContext: NoteContext;
}
};
export type EventListener<T extends EventNames> = {
@@ -667,10 +665,6 @@ export class AppContext extends Component {
this.beforeUnloadListeners.push(obj);
}
}
removeBeforeUnloadListener(listener: (() => boolean)) {
this.beforeUnloadListeners = this.beforeUnloadListeners.filter(l => l !== listener);
}
}
const appContext = new AppContext(window.glob.isMainWindow);

View File

@@ -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) {

View File

@@ -9,10 +9,10 @@ import hoistedNoteService from "../services/hoisted_note.js";
import options from "../services/options.js";
import type { ViewScope } from "../services/link.js";
import type FNote from "../entities/fnote.js";
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
import type { CKTextEditor } from "@triliumnext/ckeditor5";
import type CodeMirror from "@triliumnext/codemirror";
import { closeActiveDialog } from "../services/dialog.js";
import { ReactWrappedWidget } from "../widgets/basic_widget.js";
export interface SetNoteOpts {
triggerSwitchEvent?: unknown;
@@ -326,11 +326,9 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
// Collections must always display a note list, even if no children.
if (note.type === "book") {
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
}
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
}
if (!note.hasChildren()) {
@@ -397,7 +395,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
async getTypeWidget() {
return this.timeout(
new Promise<ReactWrappedWidget | null>((resolve) =>
new Promise<TypeWidget | null>((resolve) =>
appContext.triggerCommand("executeWithTypeWidget", {
resolve,
ntxId: this.ntxId
@@ -440,22 +438,4 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
}
export function openInCurrentNoteContext(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement> | null, notePath: string, viewScope?: ViewScope) {
const ntxId = $(evt?.target as Element)
.closest("[data-ntx-id]")
.attr("data-ntx-id");
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
if (noteContext) {
noteContext.setNote(notePath, { viewScope }).then(() => {
if (noteContext !== appContext.tabManager.getActiveContext()) {
appContext.tabManager.activateNoteContext(noteContext.ntxId);
}
});
} else {
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
}
}
export default NoteContext;

View File

@@ -7,6 +7,7 @@ import protectedSessionService from "../services/protected_session.js";
import options from "../services/options.js";
import froca from "../services/froca.js";
import utils from "../services/utils.js";
import LlmChatPanel from "../widgets/llm_chat_panel.js";
import toastService from "../services/toast.js";
import noteCreateService from "../services/note_create.js";
@@ -66,13 +67,6 @@ export default class RootCommandExecutor extends Component {
}
}
openNoteOnServerCommand() {
const noteId = appContext.tabManager.getActiveContextNoteId();
if (noteId) {
openService.openNoteOnServer(noteId);
}
}
enterProtectedSessionCommand() {
protectedSessionService.enterProtectedSession();
}
@@ -177,8 +171,7 @@ export default class RootCommandExecutor extends Component {
}
toggleTrayCommand() {
if (!utils.isElectron() || options.is("disableTray")) return;
if (!utils.isElectron()) return;
const { BrowserWindow } = utils.dynamicRequire("@electron/remote");
const windows = BrowserWindow.getAllWindows() as Electron.BaseWindow[];
const isVisible = windows.every((w) => w.isVisible());

View File

@@ -265,7 +265,6 @@ export default class TabManager extends Component {
mainNtxId: string | null = null
): Promise<NoteContext> {
const noteContext = new NoteContext(ntxId, hoistedNoteId, mainNtxId);
noteContext.setEmpty();
const existingNoteContext = this.children.find((nc) => nc.ntxId === noteContext.ntxId);

View File

@@ -10,6 +10,7 @@ import { t } from "./services/i18n.js";
import options from "./services/options.js";
import type ElectronRemote from "@electron/remote";
import type Electron from "electron";
import "bootstrap/dist/css/bootstrap.min.css";
import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js";

View File

@@ -1,12 +1,12 @@
import server from "../services/server.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import ws from "../services/ws.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import cssClassManager from "../services/css_class_manager.js";
import type { Froca } from "../services/froca-interface.js";
import type FAttachment from "./fattachment.js";
import type { default as FAttribute, AttributeType } from "./fattribute.js";
import utils from "../services/utils.js";
import search from "../services/search.js";
const LABEL = "label";
const RELATION = "relation";
@@ -256,23 +256,6 @@ export default class FNote {
return this.children;
}
async getChildNoteIdsWithArchiveFiltering(includeArchived = false) {
const isHiddenNote = this.noteId.startsWith("_");
const isSearchNote = this.type === "search";
if (!includeArchived && !isHiddenNote && !isSearchNote) {
const unorderedIds = new Set(await search.searchForNoteIds(`note.parents.noteId="${this.noteId}" #!archived`));
const results: string[] = [];
for (const id of this.children) {
if (unorderedIds.has(id)) {
results.push(id);
}
}
return results;
} else {
return this.children;
}
}
async getSubtreeNoteIds(includeArchived = false) {
let noteIds: (string | string[])[] = [];
for (const child of await this.getChildNotes()) {
@@ -435,7 +418,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) => ({
@@ -446,23 +429,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) {
@@ -483,11 +450,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;
}
/**
@@ -620,7 +586,7 @@ export default class FNote {
let childBranches = this.getChildBranches();
if (!childBranches) {
console.error(`No children for '${this.noteId}'. This shouldn't happen.`);
ws.logError(`No children for '${this.noteId}'. This shouldn't happen.`);
return [];
}
@@ -806,16 +772,6 @@ export default class FNote {
return this.getAttributeValue(LABEL, name);
}
getLabelOrRelation(nameWithPrefix: string) {
if (nameWithPrefix.startsWith("#")) {
return this.getLabelValue(nameWithPrefix.substring(1));
} else if (nameWithPrefix.startsWith("~")) {
return this.getRelationValue(nameWithPrefix.substring(1));
} else {
return this.getLabelValue(nameWithPrefix);
}
}
/**
* @param name - relation name
* @returns relation value if relation exists, null otherwise
@@ -867,7 +823,8 @@ export default class FNote {
return [];
}
const promotedAttrs = this.getAttributeDefinitions()
const promotedAttrs = this.getAttributes()
.filter((attr) => attr.isDefinition())
.filter((attr) => {
const def = attr.getDefinition();
@@ -887,11 +844,6 @@ export default class FNote {
return promotedAttrs;
}
getAttributeDefinitions() {
return this.getAttributes()
.filter((attr) => attr.isDefinition());
}
hasAncestor(ancestorNoteId: string, followTemplates = false, visitedNoteIds: Set<string> | null = null) {
if (this.noteId === ancestorNoteId) {
return true;

View File

@@ -1,49 +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 ContentHeader from "../widgets/containers/content_header.js";
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 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/ReadOnlyNoteInfoBar.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 NoteDetail from "../widgets/NoteDetail.jsx";
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,19 +129,16 @@ export default class DesktopLayout {
.child(<CreatePaneButton />)
)
.child(<Ribbon />)
.child(<SharedInfo />)
.child(new WatchedFileUpdateStatusWidget())
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />)
.child(
new ScrollingContainer()
.filling()
.child(new ContentHeader()
.child(<ReadOnlyNoteInfoBar />)
.child(<SharedInfo />)
)
.child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />)
.child(<NoteDetail />)
.child(<NoteList media="screen" />)
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<SearchResult />)
.child(<SqlResults />)
.child(<ScrollPadding />)

View File

@@ -26,12 +26,11 @@ import PopupEditorDialog from "../widgets/dialogs/popup_editor.js";
import FlexContainer from "../widgets/containers/flex_container.js";
import NoteIconWidget from "../widgets/note_icon";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
import NoteDetailWidget from "../widgets/note_detail.js";
import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx";
import NoteTitleWidget from "../widgets/note_title.jsx";
import FormattingToolbar from "../widgets/ribbon/FormattingToolbar.js";
import { PopupEditorFormattingToolbar } from "../widgets/ribbon/FormattingToolbar.js";
import NoteList from "../widgets/collections/NoteList.jsx";
import NoteDetail from "../widgets/NoteDetail.jsx";
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
export function applyModals(rootContainer: RootContainer) {
rootContainer
@@ -64,9 +63,9 @@ export function applyModals(rootContainer: RootContainer) {
.cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />))
.child(<StandaloneRibbonAdapter component={FormattingToolbar} />)
.child(<PopupEditorFormattingToolbar />)
.child(new PromotedAttributesWidget())
.child(<NoteDetail />)
.child(<NoteList media="screen" displayOnlyCollections />))
.child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />))
.child(<CallToActionDialog />);
}

View File

@@ -1,34 +1,29 @@
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 NoteList from "../widgets/collections/NoteList.jsx";
import NoteTitleWidget from "../widgets/note_title.js";
import ContentHeader from "../widgets/containers/content_header.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/ReadOnlyNoteInfoBar.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 SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx";
import SearchResult from "../widgets/search_result.jsx";
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 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";
import NoteDetail from "../widgets/NoteDetail.jsx";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
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";
const MOBILE_CSS = `
<style>
@@ -45,8 +40,8 @@ kbd {
border: none;
cursor: pointer;
font-size: 1.25em;
padding-inline-start: 0.5em;
padding-inline-end: 0.5em;
padding-left: 0.5em;
padding-right: 0.5em;
color: var(--main-text-color);
}
.quick-search {
@@ -64,7 +59,7 @@ const FANCYTREE_CSS = `
margin-top: 0px;
overflow-y: auto;
contain: content;
padding-inline-start: 10px;
padding-left: 10px;
}
.fancytree-custom-icon {
@@ -73,7 +68,7 @@ const FANCYTREE_CSS = `
.fancytree-title {
font-size: 1.5em;
margin-inline-start: 0.6em !important;
margin-left: 0.6em !important;
}
.fancytree-node {
@@ -86,7 +81,7 @@ const FANCYTREE_CSS = `
span.fancytree-expander {
width: 24px !important;
margin-inline-end: 5px;
margin-right: 5px;
}
.fancytree-loading span.fancytree-expander {
@@ -106,7 +101,7 @@ span.fancytree-expander {
.tree-wrapper .scroll-to-active-note-button,
.tree-wrapper .tree-settings-button {
position: fixed;
margin-inline-end: 16px;
margin-right: 16px;
display: none;
}
@@ -131,8 +126,8 @@ export default class MobileLayout {
.class("d-md-flex d-lg-flex d-xl-flex col-12 col-sm-5 col-md-4 col-lg-3 col-xl-3")
.id("mobile-sidebar-wrapper")
.css("max-height", "100%")
.css("padding-inline-start", "0")
.css("padding-inline-end", "0")
.css("padding-left", "0")
.css("padding-right", "0")
.css("contain", "content")
.child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS)))
)
@@ -151,20 +146,15 @@ export default class MobileLayout {
.child(<NoteTitleWidget />)
.child(<MobileDetailMenu />)
)
.child(<SharedInfoWidget />)
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(new ContentHeader()
.child(<ReadOnlyNoteInfoBar />)
.child(<SharedInfoWidget />)
)
.child(<NoteDetail />)
.child(<NoteList media="screen" />)
.child(<StandaloneRibbonAdapter component={SearchDefinitionTab} />)
.child(<SearchResult />)
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)

View File

@@ -1,3 +1,5 @@
import "bootstrap/dist/css/bootstrap.min.css";
// @ts-ignore - module = undefined
// Required for correct loading of scripts in Electron
if (typeof module === 'object') {window.module = module; module = undefined;}

View File

@@ -150,8 +150,8 @@ class ContextMenu {
this.$widget
.css({
display: "block",
top,
left
top: top,
left: left
})
.addClass("show");
}
@@ -187,7 +187,7 @@ class ContextMenu {
}
// Create a new group to avoid column breaks before and after the seaparator / header.
// This is a workaround for Firefox not supporting break-before / break-after: avoid
// This is a workaround for Firefox not supporting break-before / break-after: avoid
// for columns.
if (shouldStartNewGroup) {
$group = $("<div class='dropdown-no-break'>");
@@ -313,7 +313,7 @@ class ContextMenu {
}
$group.append($item);
// After adding a menu item, if the previous item was a separator or header,
// reset the group so that the next item will be appended directly to the parent.
if (shouldResetGroup) {

View File

@@ -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 },

View File

@@ -1,6 +1,7 @@
import appContext from "./components/app_context.js";
import noteAutocompleteService from "./services/note_autocomplete.js";
import glob from "./services/glob.js";
import "bootstrap/dist/css/bootstrap.min.css";
import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js";

View File

@@ -1,157 +0,0 @@
@import "boxicons/css/boxicons.min.css";
:root {
--print-font-size: 11pt;
--ck-content-color-image-caption-background: transparent !important;
}
html,
body {
width: 100%;
height: 100%;
color: black;
}
@page {
margin: 2cm;
}
.note-list-widget.full-height,
.note-list-widget.full-height .note-list-widget-content {
height: unset !important;
}
.component {
contain: none !important;
}
body[data-note-type="text"] .ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.ck-content figcaption {
font-style: italic;
}
.ck-content a {
text-decoration: none;
}
.ck-content a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.ck-content .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.ck-content .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-inline-start: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.ck-content .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.ck-content .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/* #region Footnotes */
.footnote-reference a,
.footnote-back-link a {
text-decoration: none !important;
}
li.footnote-item {
position: relative;
width: fit-content;
}
.ck-content .footnote-back-link {
margin-right: 0.25em;
}
.ck-content .footnote-content {
display: inline-block;
width: unset;
}
/* #endregion */
/* #region Widows and orphans */
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}
/* #endregion */
/* #region Tables */
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/* #endregion */
/* #region Page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > *,
.page-break::after {
display: none !important;
}
/* #endregion */

View File

@@ -1,132 +0,0 @@
import FNote from "./entities/fnote";
import { render } from "preact";
import { CustomNoteList } from "./widgets/collections/NoteList";
import { useCallback, useLayoutEffect, useRef } from "preact/hooks";
import content_renderer from "./services/content_renderer";
interface RendererProps {
note: FNote;
onReady: () => void;
}
async function main() {
const notePath = window.location.hash.substring(1);
const noteId = notePath.split("/").at(-1);
if (!noteId) return;
await import("./print.css");
const froca = (await import("./services/froca")).default;
const note = await froca.getNote(noteId);
render(<App note={note} noteId={noteId} />, document.body);
}
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
const sentReadyEvent = useRef(false);
const onReady = useCallback(() => {
if (sentReadyEvent.current) return;
window.dispatchEvent(new Event("note-ready"));
window._noteReady = true;
sentReadyEvent.current = true;
}, []);
const props: RendererProps | undefined | null = note && { note, onReady };
if (!note || !props) return <Error404 noteId={noteId} />
useLayoutEffect(() => {
document.body.dataset.noteType = note.type;
}, [ note ]);
return (
<>
{note.type === "book"
? <CollectionRenderer {...props} />
: <SingleNoteRenderer {...props} />
}
</>
);
}
function SingleNoteRenderer({ note, onReady }: RendererProps) {
const containerRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
async function load() {
if (note.type === "text") {
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 });
});
})
);
// Check custom CSS.
await loadCustomCss(note);
}
load().then(() => requestAnimationFrame(onReady))
}, [ note ]);
return <>
<h1>{note.title}</h1>
<main ref={containerRef} />
</>;
}
function CollectionRenderer({ note, onReady }: RendererProps) {
return <CustomNoteList
isEnabled
note={note}
notePath={note.getBestNotePath().join("/")}
ntxId="print"
highlightedTokens={null}
media="print"
onReady={async () => {
await loadCustomCss(note);
onReady();
}}
/>;
}
function Error404({ noteId }: { noteId: string }) {
return (
<main>
<p>The note you are trying to print could not be found.</p>
<small>{noteId}</small>
</main>
)
}
async function loadCustomCss(note: FNote) {
const printCssNotes = await note.getRelationTargets("printCss");
let loadPromises: JQueryPromise<void>[] = [];
for (const printCssNote of printCssNotes) {
if (!printCssNote || (printCssNote.type !== "code" && printCssNote.mime !== "text/css")) continue;
const linkEl = document.createElement("link");
linkEl.href = `/api/notes/${printCssNote.noteId}/download`;
linkEl.rel = "stylesheet";
const promise = $.Deferred();
loadPromises.push(promise.promise());
linkEl.onload = () => promise.resolve();
document.head.appendChild(linkEl);
}
await Promise.allSettled(loadPromises);
}
main();

View File

@@ -1,15 +1,5 @@
import $ from "jquery";
async function loadBootstrap() {
if (document.body.dir === "rtl") {
await import("bootstrap/dist/css/bootstrap.rtl.min.css");
} else {
await import("bootstrap/dist/css/bootstrap.min.css");
}
}
(window as any).$ = $;
(window as any).jQuery = $;
await loadBootstrap();
$("body").show();

View File

@@ -90,8 +90,7 @@ const HIDDEN_ATTRIBUTES = [
"viewType",
"geolocation",
"docName",
"webViewSrc",
"archived"
"webViewSrc"
];
async function renderNormalAttributes(note: FNote) {

View File

@@ -22,15 +22,6 @@ export async function setLabel(noteId: string, name: string, value: string = "",
});
}
export async function setRelation(noteId: string, name: string, value: string = "", isInheritable = false) {
await server.put(`notes/${noteId}/set-attribute`, {
type: "relation",
name: name,
value: value,
isInheritable
});
}
async function removeAttributeById(noteId: string, attributeId: string) {
await server.remove(`notes/${noteId}/attributes/${attributeId}`);
}
@@ -60,23 +51,6 @@ function removeOwnedLabelByName(note: FNote, labelName: string) {
return false;
}
/**
* Removes a relation identified by its name from the given note, if it exists. Note that the relation must be owned, i.e.
* it will not remove inherited attributes.
*
* @param note the note from which to remove the relation.
* @param relationName the name of the relation to remove.
* @returns `true` if an attribute was identified and removed, `false` otherwise.
*/
function removeOwnedRelationByName(note: FNote, relationName: string) {
const relation = note.getOwnedRelation(relationName);
if (relation) {
removeAttributeById(note.noteId, relation.attributeId);
return true;
}
return false;
}
/**
* Sets the attribute of the given note to the provided value if its truthy, or removes the attribute if the value is falsy.
* For an attribute with an empty value, pass an empty string instead.
@@ -142,10 +116,8 @@ function isAffecting(attrRow: AttributeRow, affectedNote: FNote | null | undefin
export default {
addLabel,
setLabel,
setRelation,
setAttribute,
removeAttributeById,
removeOwnedLabelByName,
removeOwnedRelationByName,
isAffecting
};

View File

@@ -23,13 +23,11 @@ interface Options {
tooltip?: boolean;
trim?: boolean;
imageHasZoom?: boolean;
/** If enabled, it will prevent the default behavior in which an empty note would display a list of children. */
noChildrenList?: boolean;
}
const CODE_MIME_TYPES = new Set(["application/json"]);
export async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: Options = {}) {
async function getRenderedContent(this: {} | { ctx: string }, entity: FNote | FAttachment, options: Options = {}) {
options = Object.assign(
{
@@ -44,7 +42,7 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
const $renderedContent = $('<div class="rendered-content">');
if (type === "text" || type === "book") {
await renderText(entity, $renderedContent, options);
await renderText(entity, $renderedContent);
} else if (type === "code") {
await renderCode(entity, $renderedContent);
} else if (["image", "canvas", "mindMap"].includes(type)) {
@@ -116,7 +114,7 @@ export async function getRenderedContent(this: {} | { ctx: string }, entity: FNo
};
}
async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>, options: Options = {}) {
async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>) {
// entity must be FNote
const blob = await note.getBlob();
@@ -137,7 +135,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
}
await formatCodeBlocks($renderedContent);
} else if (note instanceof FNote && !options.noChildrenList) {
} else if (note instanceof FNote) {
await renderChildrenList($renderedContent, note);
}
}

View File

@@ -1,39 +1,21 @@
import {readCssVar} from "../utils/css-var";
import Color, { ColorInstance } from "color";
const registeredClasses = new Set<string>();
// Read the color lightness limits defined in the theme as CSS variables
function createClassForColor(color: string | null) {
if (!color?.trim()) {
return "";
}
const lightThemeColorMaxLightness = readCssVar(
document.documentElement,
"tree-item-light-theme-max-color-lightness"
).asNumber(70);
const normalizedColorName = color.replace(/[^a-z0-9]/gi, "");
const darkThemeColorMinLightness = readCssVar(
document.documentElement,
"tree-item-dark-theme-min-color-lightness"
).asNumber(50);
if (!normalizedColorName.trim()) {
return "";
}
function createClassForColor(colorString: string | null) {
if (!colorString?.trim()) return "";
const color = parseColor(colorString);
if (!color) return "";
const className = `color-${color.hex().substring(1)}`;
const className = `color-${normalizedColorName}`;
if (!registeredClasses.has(className)) {
const adjustedColor = adjustColorLightness(color, lightThemeColorMaxLightness!,
darkThemeColorMinLightness!);
$("head").append(`<style>
.${className}, span.fancytree-active.${className} {
--light-theme-custom-color: ${adjustedColor.lightThemeColor};
--dark-theme-custom-color: ${adjustedColor.darkThemeColor};
--custom-color-hue: ${getHue(color) ?? 'unset'};
}
</style>`);
// make the active fancytree selector more specific than the normal color setting
$("head").append(`<style>.${className}, span.fancytree-active.${className} { color: ${color} !important; }</style>`);
registeredClasses.add(className);
}
@@ -41,46 +23,6 @@ function createClassForColor(colorString: string | null) {
return className;
}
function parseColor(color: string) {
try {
return Color(color);
} catch (ex) {
console.error(ex);
}
}
/**
* Returns a pair of colors — one optimized for light themes and the other for dark themes, derived
* from the specified color to maintain sufficient contrast with each theme.
* The adjustment is performed by limiting the colors lightness in the CIELAB color space,
* according to the lightThemeMaxLightness and darkThemeMinLightness parameters.
*/
function adjustColorLightness(color: ColorInstance, lightThemeMaxLightness: number, darkThemeMinLightness: number) {
const labColor = color.lab();
const lightness = labColor.l();
// For the light theme, limit the maximum lightness
const lightThemeColor = labColor.l(Math.min(lightness, lightThemeMaxLightness)).hex();
// For the dark theme, limit the minimum lightness
const darkThemeColor = labColor.l(Math.max(lightness, darkThemeMinLightness)).hex();
return {lightThemeColor, darkThemeColor};
}
/** Returns the hue of the specified color, or undefined if the color is grayscale. */
function getHue(color: ColorInstance) {
const hslColor = color.hsl();
if (hslColor.saturationl() > 0) {
return hslColor.hue();
}
}
export function getReadableTextColor(bgColor: string) {
const colorInstance = Color(bgColor);
return colorInstance.isLight() ? "#000" : "#fff";
}
export default {
createClassForColor
};

View File

@@ -1,5 +1,4 @@
import type FNote from "../entities/fnote.js";
import { applyReferenceLinks } from "../widgets/type_widgets/text/read_only_helper.js";
import { getCurrentLanguage } from "./i18n.js";
import { formatCodeBlocks } from "./syntax_highlight.js";
@@ -11,18 +10,18 @@ export default function renderDoc(note: FNote) {
if (docName) {
// find doc based on language
const url = getUrl(docName, getCurrentLanguage());
$content.load(url, async (response, status) => {
$content.load(url, (response, status) => {
// fallback to english doc if no translation available
if (status === "error") {
const fallbackUrl = getUrl(docName, "en");
$content.load(fallbackUrl, async () => {
await processContent(fallbackUrl, $content)
$content.load(fallbackUrl, () => {
processContent(fallbackUrl, $content)
resolve($content);
});
return;
}
await processContent(url, $content);
processContent(url, $content);
resolve($content);
});
} else {
@@ -33,7 +32,7 @@ export default function renderDoc(note: FNote) {
});
}
async function processContent(url: string, $content: JQuery<HTMLElement>) {
function processContent(url: string, $content: JQuery<HTMLElement>) {
const dir = url.substring(0, url.lastIndexOf("/"));
// Images are relative to the docnote but that will not work when rendered in the application since the path breaks.
@@ -43,9 +42,6 @@ async function processContent(url: string, $content: JQuery<HTMLElement>) {
});
formatCodeBlocks($content);
// Apply reference links.
await applyReferenceLinks($content[0]);
}
function getUrl(docNameValue: string, language: string) {

View File

@@ -40,23 +40,20 @@ class FrocaImpl implements Froca {
constructor() {
this.initializedPromise = this.loadInitialTree();
this.#clear();
}
async loadInitialTree() {
const resp = await server.get<SubtreeResponse>("tree");
// clear the cache only directly before adding new content which is important for e.g., switching to protected session
this.#clear();
this.addResp(resp);
}
#clear() {
this.notes = {};
this.branches = {};
this.attributes = {};
this.attachments = {};
this.blobPromises = {};
this.addResp(resp);
}
async loadSubTree(subTreeNoteId: string) {

View File

@@ -11,7 +11,7 @@ import RightPanelWidget from "../widgets/right_panel_widget.js";
import ws from "./ws.js";
import appContext from "../components/app_context.js";
import NoteContextAwareWidget from "../widgets/note_context_aware_widget.js";
import BasicWidget, { ReactWrappedWidget } from "../widgets/basic_widget.js";
import BasicWidget from "../widgets/basic_widget.js";
import SpacedUpdate from "./spaced_update.js";
import shortcutService from "./shortcuts.js";
import dialogService from "./dialog.js";
@@ -19,6 +19,7 @@ import type FNote from "../entities/fnote.js";
import { t } from "./i18n.js";
import dayjs from "dayjs";
import type NoteContext from "../components/note_context.js";
import type NoteDetailWidget from "../widgets/note_detail.js";
import type Component from "../components/component.js";
import { formatLogMessage } from "@triliumnext/commons";
@@ -316,7 +317,7 @@ export interface Api {
* Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the
* implementation of actual widget type.
*/
getActiveNoteDetailWidget(): Promise<ReactWrappedWidget>;
getActiveNoteDetailWidget(): Promise<NoteDetailWidget>;
/**
* @returns returns a note path of active note or null if there isn't active note
*/

View 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();

View File

@@ -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();

View File

@@ -6,7 +6,7 @@ import { describe, expect, it } from "vitest";
describe("i18n", () => {
it("translations are valid JSON", () => {
for (const locale of LOCALES) {
if (locale.contentOnly || locale.id === "en_rtl") {
if (locale.contentOnly) {
continue;
}

View File

@@ -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,
@@ -27,8 +27,7 @@ export const byBookType: Record<ViewTypeOptions, string | null> = {
calendar: "xWbu3jpNWapp",
table: "2FvYrpmOXm29",
geoMap: "81SGnPGMk7Xc",
board: "CtBQqbwXDx1w",
presentation: null
board: "CtBQqbwXDx1w"
};
export function getHelpUrlForNote(note: FNote | null | undefined) {

View File

@@ -1,6 +1,6 @@
import server from "./server.js";
import appContext from "../components/app_context.js";
import shortcutService, { ShortcutBinding } from "./shortcuts.js";
import appContext, { type CommandNames } from "../components/app_context.js";
import shortcutService from "./shortcuts.js";
import type Component from "../components/component.js";
import type { ActionKeyboardShortcut } from "@triliumnext/commons";
@@ -29,21 +29,13 @@ async function getActionsForScope(scope: string) {
}
async function setupActionsForElement(scope: string, $el: JQuery<HTMLElement>, component: Component) {
if (!$el[0]) return [];
const actions = await getActionsForScope(scope);
const bindings: ShortcutBinding[] = [];
for (const action of actions) {
for (const shortcut of action.effectiveShortcuts ?? []) {
const binding = shortcutService.bindElShortcut($el, shortcut, () => component.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
if (binding) {
bindings.push(binding);
}
shortcutService.bindElShortcut($el, shortcut, () => component.triggerCommand(action.actionName, { ntxId: appContext.tabManager.activeNtxId }));
}
}
return bindings;
}
getActionsForScope("window").then((actions) => {

View File

@@ -3,8 +3,16 @@ import linkContextMenuService from "../menus/link_context_menu.js";
import appContext, { type NoteCommandData } from "../components/app_context.js";
import froca from "./froca.js";
import utils from "./utils.js";
import { ALLOWED_PROTOCOLS } from "@triliumnext/commons";
import { openInCurrentNoteContext } from "../components/note_context.js";
// Be consistent with `allowedSchemes` in `src\services\html_sanitizer.ts`
// TODO: Deduplicate with server once we can.
export const ALLOWED_PROTOCOLS = [
'http', 'https', 'ftp', 'ftps', 'mailto', 'data', 'evernote', 'file', 'facetime', 'gemini', 'git',
'gopher', 'imap', 'irc', 'irc6', 'jabber', 'jar', 'lastfm', 'ldap', 'ldaps', 'magnet', 'message',
'mumble', 'nfs', 'onenote', 'pop', 'rmi', 's3', 'sftp', 'skype', 'sms', 'spotify', 'steam', 'svn', 'udp',
'view-source', 'vlc', 'vnc', 'ws', 'wss', 'xmpp', 'jdbc', 'slack', 'tel', 'smb', 'zotero', 'geo',
'mid'
];
function getNotePathFromUrl(url: string) {
const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url);
@@ -150,16 +158,11 @@ async function createLink(notePath: string | undefined, options: CreateLinkOptio
$container.append($noteLink);
if (showNotePath) {
let pathSegments: string[];
if (notePath == "root") {
pathSegments = ["⌂"];
} else {
const resolvedPathSegments = (await treeService.resolveNotePathToSegments(notePath)) || [];
resolvedPathSegments.pop(); // Remove last element
const resolvedPathSegments = (await treeService.resolveNotePathToSegments(notePath)) || [];
resolvedPathSegments.pop(); // Remove last element
const resolvedPath = resolvedPathSegments.join("/");
pathSegments = await treeService.getNotePathTitleComponents(resolvedPath);
}
const resolvedPath = resolvedPathSegments.join("/");
const pathSegments = await treeService.getNotePathTitleComponents(resolvedPath);
if (pathSegments) {
if (pathSegments.length) {
@@ -285,7 +288,7 @@ function goToLink(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent) {
* @param $link the jQuery element of the link that was clicked, used to determine if the link is an anchor link (e.g., `#fn1` or `#fnref1`) and to handle it accordingly.
* @returns `true` if the link was handled (i.e., the element was found and scrolled to), or a falsy value otherwise.
*/
export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement> | null, hrefLink: string | undefined, $link?: JQuery<HTMLElement> | null) {
function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement> | null, hrefLink: string | undefined, $link?: JQuery<HTMLElement> | null) {
if (hrefLink?.startsWith("data:")) {
return true;
}
@@ -307,8 +310,7 @@ export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDo
// Right click is handled separately.
const isMiddleClick = evt && "which" in evt && evt.which === 2;
const targetIsBlank = ($link?.attr("target") === "_blank");
const isDoubleClick = isLeftClick && evt?.type === "dblclick";
const openInNewTab = (isLeftClick && ctrlKey) || isDoubleClick || isMiddleClick || targetIsBlank;
const openInNewTab = (isLeftClick && ctrlKey) || isMiddleClick || targetIsBlank;
const activate = (isLeftClick && ctrlKey && shiftKey) || (isMiddleClick && shiftKey);
const openInNewWindow = isLeftClick && evt?.shiftKey && !ctrlKey;
@@ -323,24 +325,36 @@ export function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDo
viewScope
});
} else if (isLeftClick) {
openInCurrentNoteContext(evt, notePath, viewScope);
const ntxId = $(evt?.target as any)
.closest("[data-ntx-id]")
.attr("data-ntx-id");
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
if (noteContext) {
noteContext.setNote(notePath, { viewScope }).then(() => {
if (noteContext !== appContext.tabManager.getActiveContext()) {
appContext.tabManager.activateNoteContext(noteContext.ntxId);
}
});
} else {
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
}
}
} else if (hrefLink) {
const withinEditLink = $link?.hasClass("ck-link-actions__preview");
const outsideOfCKEditor = !$link || $link.closest("[contenteditable]").length === 0;
if (openInNewTab || openInNewWindow || (isLeftClick && (withinEditLink || outsideOfCKEditor))) {
if (openInNewTab || (withinEditLink && (isLeftClick || isMiddleClick)) || (outsideOfCKEditor && (isLeftClick || isMiddleClick))) {
if (hrefLink.toLowerCase().startsWith("http") || hrefLink.startsWith("api/")) {
window.open(hrefLink, "_blank");
} else if ((hrefLink.toLowerCase().startsWith("file:") || hrefLink.toLowerCase().startsWith("geo:")) && utils.isElectron()) {
const electron = utils.dynamicRequire("electron");
electron.shell.openPath(hrefLink);
} else {
// Enable protocols supported by CKEditor 5 to be clickable.
if (ALLOWED_PROTOCOLS.some((protocol) => hrefLink.toLowerCase().startsWith(protocol + ":"))) {
if ( utils.isElectron()) {
const electron = utils.dynamicRequire("electron");
electron.shell.openExternal(hrefLink);
} else {
window.open(hrefLink, "_blank");
}
window.open(hrefLink, "_blank");
}
}
}
@@ -476,9 +490,18 @@ $(document).on("auxclick", "a", goToLink); // to handle the middle button
// TODO: Check why the event is not supported.
//@ts-ignore
$(document).on("contextmenu", "a", linkContextMenu);
// TODO: Check why the event is not supported.
//@ts-ignore
$(document).on("dblclick", "a", goToLink);
$(document).on("dblclick", "a", (e) => {
e.preventDefault();
e.stopPropagation();
const $link = $(e.target).closest("a");
const address = $link.attr("href");
if (address && address.startsWith("http")) {
window.open(address, "_blank");
}
});
$(document).on("mousedown", "a", (e) => {
if (e.which === 2) {

View File

@@ -1,21 +1,11 @@
import type { AttachmentRow, EtapiTokenRow, NoteType, OptionNames } from "@triliumnext/commons";
import type { AttachmentRow, EtapiTokenRow, OptionNames } from "@triliumnext/commons";
import type { AttributeType } from "../entities/fattribute.js";
import type { EntityChange } from "../server_types.js";
// TODO: Deduplicate with server.
interface NoteRow {
blobId: string;
dateCreated: string;
dateModified: string;
isDeleted?: boolean;
isProtected?: boolean;
mime: string;
noteId: string;
title: string;
type: NoteType;
utcDateCreated: string;
utcDateModified: string;
}
// TODO: Deduplicate with BranchRow from `rows.ts`/

View File

@@ -168,8 +168,7 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
}
for (const templateNote of childNotes) {
if (templateNote.hasLabel("collection") !== filterCollections ||
!templateNote.hasLabel("template")) {
if (templateNote.hasLabel("collection") !== filterCollections) {
continue;
}

View File

@@ -1,5 +1,4 @@
import utils from "./utils.js";
import options from "./options.js";
import server from "./server.js";
type ExecFunction = (command: string, cb: (err: string, stdout: string, stderror: string) => void) => void;
@@ -127,7 +126,7 @@ function downloadRevision(noteId: string, revisionId: string) {
/**
* @param url - should be without initial slash!!!
*/
export function getUrlForDownload(url: string) {
function getUrlForDownload(url: string) {
if (utils.isElectron()) {
// electron needs absolute URL, so we extract current host, port, protocol
return `${getHost()}/${url}`;
@@ -172,21 +171,6 @@ function getHost() {
return `${url.protocol}//${url.hostname}:${url.port}`;
}
async function openNoteOnServer(noteId: string) {
// Get the sync server host from options
const syncServerHost = options.get("syncServerHost");
if (!syncServerHost) {
console.error("No sync server host configured");
return;
}
const url = new URL(`#root/${noteId}`, syncServerHost).toString();
// Use window.open to ensure link opens in external browser in Electron
window.open(url, '_blank', 'noopener,noreferrer');
}
async function openDirectory(directory: string) {
try {
if (utils.isElectron()) {
@@ -214,6 +198,5 @@ export default {
openAttachmentExternally,
openNoteCustom,
openAttachmentCustom,
openNoteOnServer,
openDirectory
};

View File

@@ -1,5 +1,5 @@
import options from "./options.js";
import Split from "@triliumnext/split.js";
import Split from "split.js"
export const DEFAULT_GUTTER_SIZE = 5;
@@ -46,7 +46,6 @@ function setupLeftPaneResizer(leftPaneVisible: boolean) {
sizes: [leftPaneWidth, restPaneWidth],
gutterSize: DEFAULT_GUTTER_SIZE,
minSize: [150, 300],
rtl: glob.isRtl,
onDragEnd: (sizes) => {
leftPaneWidth = Math.round(sizes[0]);
options.save("leftPaneWidth", Math.round(sizes[0]));
@@ -80,7 +79,6 @@ function setupRightPaneResizer() {
sizes: [100 - rightPaneWidth, rightPaneWidth],
gutterSize: DEFAULT_GUTTER_SIZE,
minSize: [300, 180],
rtl: glob.isRtl,
onDragEnd: (sizes) => {
rightPaneWidth = Math.round(sizes[1]);
options.save("rightPaneWidth", Math.round(sizes[1]));
@@ -101,7 +99,7 @@ function setupNoteSplitResizer(ntxIds: string[]) {
let targetNtxIds: string[] | undefined;
for (const ntxId of ntxIds) {
targetNtxIds = findKeyByNtxId(ntxId);
if (targetNtxIds) break;
if (targetNtxIds) break;
}
if (targetNtxIds) {
@@ -156,7 +154,6 @@ function createSplitInstance(targetNtxIds: string[]) {
const splitPanels = [...splitNoteContainer.querySelectorAll<HTMLElement>(':scope > .note-split')]
.filter(el => targetNtxIds.includes(el.getAttribute('data-ntx-id') ?? ""));
const splitInstance = Split(splitPanels, {
rtl: glob.isRtl,
gutterSize: DEFAULT_GUTTER_SIZE,
minSize: 150,
});

View File

@@ -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();
}

View File

@@ -3,7 +3,7 @@ import utils from "./utils.js";
type ElementType = HTMLElement | Document;
type Handler = (e: KeyboardEvent) => void;
export interface ShortcutBinding {
interface ShortcutBinding {
element: HTMLElement | Document;
shortcut: string;
handler: Handler;
@@ -46,7 +46,6 @@ for (let i = 1; i <= 19; i++) {
const KEYCODES_WITH_NO_MODIFIER = new Set([
"Delete",
"Enter",
"NumpadEnter",
...functionKeyCodes
]);
@@ -127,20 +126,10 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
activeBindings.set(key, []);
}
activeBindings.get(key)!.push(binding);
return binding;
}
}
}
export function removeIndividualBinding(binding: ShortcutBinding) {
const key = binding.namespace ?? "global";
const activeBindingsInNamespace = activeBindings.get(key);
if (activeBindingsInNamespace) {
activeBindings.set(key, activeBindingsInNamespace.filter(aBinding => aBinding.handler === binding.handler));
}
binding.element.removeEventListener("keydown", binding.listener);
}
function removeNamespaceBindings(namespace: string) {
const bindings = activeBindings.get(namespace);
if (bindings) {

View File

@@ -24,9 +24,7 @@ export async function formatCodeBlocks($container: JQuery<HTMLElement>) {
continue;
}
if (glob.device !== "print") {
applyCopyToClipboardButton($(codeBlock));
}
applyCopyToClipboardButton($(codeBlock));
if (syntaxHighlightingEnabled) {
applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType);
@@ -63,11 +61,7 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
highlightedText = highlightAuto(text);
} else if (normalizedMimeType) {
await ensureMimeTypesForHighlighting(normalizedMimeType);
try {
highlightedText = highlight(text, { language: normalizedMimeType });
} catch (e) {
console.warn("Unable to apply syntax highlight.", e);
}
highlightedText = highlight(text, { language: normalizedMimeType });
}
if (highlightedText) {
@@ -82,7 +76,7 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
// Load theme.
const currentThemeName = String(options.get("codeBlockTheme"));
await loadHighlightingTheme(currentThemeName);
loadHighlightingTheme(currentThemeName);
// Load mime types.
let mimeTypes: MimeType[];
@@ -104,16 +98,17 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
highlightingLoaded = true;
}
export async function loadHighlightingTheme(themeName: string) {
export function loadHighlightingTheme(themeName: string) {
const themePrefix = "default:";
let theme: Theme | null = null;
if (glob.device === "print") {
theme = Themes.vs;
} else if (themeName.includes(themePrefix)) {
if (themeName.includes(themePrefix)) {
theme = Themes[themeName.substring(themePrefix.length)];
}
if (!theme) {
theme = Themes.default;
}
await loadTheme(theme ?? Themes.default);
loadTheme(theme);
}
/**

View File

@@ -77,11 +77,11 @@ function closePersistent(id: string) {
$(`#toast-${id}`).remove();
}
function showMessage(message: string, delay = 2000, icon = "check") {
function showMessage(message: string, delay = 2000) {
console.debug(utils.now(), "message:", message);
toast({
icon,
icon: "check",
message: message,
autohide: true,
delay

View File

@@ -4,6 +4,9 @@ import froca from "./froca.js";
import hoistedNoteService from "./hoisted_note.js";
import appContext from "../components/app_context.js";
/**
* @returns {string|null}
*/
async function resolveNotePath(notePath: string, hoistedNoteId = "root") {
const runPath = await resolveNotePathToSegments(notePath, hoistedNoteId);
@@ -26,12 +29,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 +68,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 +80,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 +111,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}'`);

View File

@@ -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() {
@@ -173,7 +169,7 @@ const entityMap: Record<string, string> = {
"=": "&#x3D;"
};
export function escapeHtml(str: string) {
function escapeHtml(str: string) {
return str.replace(/[&<>"'`=\/]/g, (s) => entityMap[s]);
}
@@ -841,7 +837,7 @@ export function arrayEqual<T>(a: T[], b: T[]) {
return true;
}
export type Indexed<T extends object> = T & { index: number };
type Indexed<T extends object> = T & { index: number };
/**
* Given an object array, alters every object in the array to have an index field assigned to it.
@@ -873,18 +869,6 @@ export function getErrorMessage(e: unknown) {
}
}
/**
* Handles left or right placement of e.g. tooltips in case of right-to-left languages. If the current language is a RTL one, then left and right are swapped. Other directions are unaffected.
* @param placement a string optionally containing a "left" or "right" value.
* @returns a left/right value swapped if needed, or the same as input otherwise.
*/
export function handleRightToLeftPlacement<T extends string>(placement: T) {
if (!glob.isRtl) return placement;
if (placement === "left") return "right";
if (placement === "right") return "left";
return placement;
}
export default {
reloadFrontendApp,
restartDesktopApp,

View File

@@ -304,8 +304,6 @@ async function sendPing() {
}
setTimeout(() => {
if (glob.device === "print") return;
ws = connectWebSocket();
lastPingTs = Date.now();

View File

@@ -1,3 +1,4 @@
import "bootstrap/dist/css/bootstrap.min.css";
import "./stylesheets/auth.css";
// @TriliumNextTODO: is this even needed anymore?

View File

@@ -1,6 +1,7 @@
import "jquery";
import utils from "./services/utils.js";
import ko from "knockout";
import "bootstrap/dist/css/bootstrap.min.css";
// TriliumNextTODO: properly make use of below types
// type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";

84
apps/client/src/share.ts Normal file
View 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
});

View File

@@ -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;

View File

@@ -60,7 +60,7 @@
appearance: none;
text-align: center;
border: 0;
border-inline-start: unset;
border-left: unset;
background-color: var(--menu-background-color);
font-weight: bold;
outline: 0;
@@ -102,7 +102,7 @@
content: '';
position: absolute;
top: 0;
inset-inline-end: 0;
right: 0;
bottom: 0;
width: 1px;
background-color: var(--main-border-color);

View File

@@ -299,7 +299,7 @@
content: '';
position: absolute;
top: 0;
inset-inline-start: -100%;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, var(--hover-item-background-color, rgba(0, 0, 0, 0.03)), transparent);
@@ -406,10 +406,10 @@
@keyframes shimmer {
0% {
inset-inline-start: -100%;
left: -100%;
}
100% {
inset-inline-start: 100%;
left: 100%;
}
}

View File

@@ -0,0 +1,322 @@
:root {
--main-background-color: white;
--root-background: var(--main-background-color);
--launcher-pane-background-color: var(--main-background-color);
--main-text-color: black;
--input-text-color: var(--main-text-color);
--print-font-size: 11pt;
}
@page {
margin: 2cm;
}
.ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.note-detail-readonly-text {
padding: 0 !important;
}
.no-print,
.no-print *,
.tab-row-container,
.tab-row-widget,
.title-bar-buttons,
#launcher-pane,
#left-pane,
#center-pane > *:not(.split-note-container-widget),
#right-pane,
.title-row .note-icon-widget,
.title-row .icon-action,
.ribbon-container,
.promoted-attributes-widget,
.scroll-padding-widget,
.note-list-widget,
.spacer {
display: none !important;
}
body.mobile #mobile-sidebar-wrapper,
body.mobile .classic-toolbar-widget,
body.mobile .action-button {
display: none !important;
}
body.mobile #detail-container {
max-height: unset;
}
body.mobile .note-title-widget {
padding: 0 !important;
}
body,
#root-widget,
#rest-pane > div.component:first-child,
.note-detail-printable,
.note-detail-editable-text-editor {
height: unset !important;
overflow: auto;
}
.ck.ck-editor__editable_inline {
overflow: hidden !important;
}
.note-title-widget input,
.note-detail-editable-text,
.note-detail-editable-text-editor {
padding: 0 !important;
}
html,
body {
width: unset !important;
height: unset !important;
overflow: visible;
position: unset;
/* https://github.com/zadam/trilium/issues/3202 */
color: black;
}
#root-widget,
#horizontal-main-container,
#rest-pane,
#vertical-main-container,
#center-pane,
.split-note-container-widget,
.note-split:not(.hidden-ext),
body.mobile #mobile-rest-container {
display: block !important;
overflow: auto;
border-radius: 0 !important;
}
#center-pane,
#rest-pane,
.note-split,
body.mobile #detail-container {
width: unset !important;
max-width: unset !important;
}
.component {
contain: none !important;
}
/* Respect page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > * {
display: none !important;
}
.relation-map-wrapper {
height: 100vh !important;
}
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/*
* Text note specific fixes
*/
.ck-widget {
outline: none !important;
}
.ck-placeholder,
.ck-widget__type-around,
.ck-widget__selection-handle {
display: none !important;
}
.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table td.ck-editor__nested-editable:focus,
.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table th.ck-editor__nested-editable:focus {
background: unset !important;
outline: unset !important;
}
.include-note .include-note-content {
max-height: unset !important;
overflow: unset !important;
}
/* TODO: This will break once we translate the language */
.ck-content pre[data-language="Auto-detected"]:after {
display: none !important;
}
/*
* Code note specific fixes.
*/
.note-detail-code pre {
border: unset !important;
border-radius: unset !important;
}
/*
* Links
*/
.note-detail-printable a {
text-decoration: none;
}
.note-detail-printable a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.note-detail-printable a::after {
/* Hide the external link trailing arrow */
display: none !important;
}
/*
* TODO list check boxes
*/
.note-detail-printable .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.note-detail-printable .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-left: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.note-detail-printable .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.note-detail-printable .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/*
* Blockquotes
*/
.note-detail-printable blockquote {
box-shadow: unset;
}
/*
* Figures
*/
.note-detail-printable figcaption {
--accented-background-color: transparent;
font-style: italic;
}
/*
* Footnotes
*/
.note-detail-printable .footnote-reference a,
.footnote-back-link a {
text-decoration: none;
}
/* Make the "^" link cover the whole area of the footnote item */
.footnote-section {
clear: both;
}
.note-detail-printable li.footnote-item {
position: relative;
width: fit-content;
}
.note-detail-printable .footnote-back-link,
.note-detail-printable .footnote-back-link *,
.note-detail-printable .footnote-back-link a {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.note-detail-printable .footnote-back-link a {
color: transparent;
}
.note-detail-printable .footnote-content {
display: inline-block;
width: unset;
}
/*
* Widows and orphans
*/
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}

View File

@@ -5,6 +5,7 @@
.note-detail-relation-map {
height: 100%;
overflow: hidden !important;
padding: 10px;
position: relative;
}
@@ -61,7 +62,7 @@
.note-detail-relation-map .endpoint {
position: absolute;
bottom: 37%;
inset-inline-end: 5px;
right: 5px;
width: 1em;
height: 1em;
background-color: #333;

View File

@@ -174,12 +174,12 @@ textarea,
/* Add a gap between consecutive radios / check boxes */
label.tn-radio + label.tn-radio,
label.tn-checkbox + label.tn-checkbox {
margin-inline-start: 12px;
margin-left: 12px;
}
label.tn-radio input[type="radio"],
label.tn-checkbox input[type="checkbox"] {
margin-inline-end: .5em;
margin-right: .5em;
}
#left-pane input,
@@ -226,7 +226,7 @@ samp {
.badge {
--bs-badge-color: var(--muted-text-color);
margin-inline-start: 8px;
margin-left: 8px;
background: var(--accented-background-color);
}
@@ -338,8 +338,8 @@ button kbd {
}
.ui-menu kbd {
margin-inline-start: 30px;
float: inline-end;
margin-left: 30px;
float: right;
}
.suppressed {
@@ -360,8 +360,7 @@ button kbd {
}
.dropdown-menu,
.tabulator-popup-container,
:root .excalidraw .popover {
.tabulator-popup-container {
color: var(--menu-text-color) !important;
font-size: inherit;
background: var(--menu-background-color) !important;
@@ -372,9 +371,7 @@ button kbd {
}
body.desktop .dropdown-menu,
body.desktop .tabulator-popup-container,
:root .excalidraw .dropdown-menu .dropdown-menu-container,
:root .excalidraw .popover {
body.desktop .tabulator-popup-container {
border: 1px solid var(--dropdown-border-color);
column-rule: 1px solid var(--dropdown-border-color);
box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
@@ -395,7 +392,7 @@ body.desktop .tabulator-popup-container,
}
.dropend .dropdown-toggle::after {
margin-inline-start: 0.5em;
margin-left: 0.5em;
color: var(--muted-text-color);
}
@@ -406,8 +403,8 @@ body.desktop .tabulator-popup-container,
.dropdown-menu .disabled .disabled-tooltip {
pointer-events: all;
margin-inline-start: 8px;
font-size: 0.75rem;
margin-left: 8px;
font-size: 0.5em;
color: var(--disabled-tooltip-icon-color);
cursor: help;
opacity: 0.75;
@@ -419,8 +416,7 @@ body.desktop .tabulator-popup-container,
.dropdown-menu a:hover:not(.disabled),
.dropdown-item:hover:not(.disabled, .dropdown-container-item),
.tabulator-menu-item:hover,
:root .excalidraw .context-menu .context-menu-item:hover {
.tabulator-menu-item:hover {
color: var(--hover-item-text-color) !important;
background-color: var(--hover-item-background-color) !important;
border-color: var(--hover-item-border-color) !important;
@@ -447,7 +443,7 @@ body #context-menu-container .dropdown-item > span {
.dropdown-item span.keyboard-shortcut,
.dropdown-item *:not(.keyboard-shortcut) > kbd {
flex-grow: 1;
text-align: end;
text-align: right;
padding-inline-start: 12px;
}
@@ -461,8 +457,7 @@ body #context-menu-container .dropdown-item > span {
}
.dropdown-item,
.dropdown-header,
:root .excalidraw .context-menu .context-menu-item:hover {
.dropdown-header {
color: var(--menu-text-color) !important;
border: 1px solid transparent !important;
}
@@ -509,7 +504,7 @@ body #context-menu-container .dropdown-item > span {
body .cm-editor .cm-gutters {
background-color: inherit !important;
border-inline-end: none;
border-right: none;
}
body .cm-editor .cm-placeholder {
@@ -591,10 +586,6 @@ button.btn-sm {
z-index: 1000;
}
body[dir=rtl] .ck.ck-block-toolbar-button {
transform: translateX(-7px);
}
pre:not(.hljs) {
color: var(--main-text-color) !important;
white-space: pre-wrap;
@@ -613,11 +604,11 @@ pre:not(.hljs) {
pre > button.copy-button {
position: absolute;
top: var(--copy-button-margin-size);
inset-inline-end: var(--copy-button-margin-size);
right: var(--copy-button-margin-size);
}
:root pre:has(> button.copy-button) {
padding-inline-end: calc(var(--copy-button-width) + (var(--copy-button-margin-size) * 2));
padding-right: calc(var(--copy-button-width) + (var(--copy-button-margin-size) * 2));
}
pre > button.copy-button:hover {
@@ -643,31 +634,31 @@ pre > button.copy-button:active {
.full-text-search-button {
cursor: pointer;
font-size: 1.3em;
padding-inline-start: 5px;
padding-inline-end: 5px;
padding-left: 5px;
padding-right: 5px;
}
.input-clearer-button {
cursor: pointer;
font-size: 1.3em;
background: inherit !important;
padding-inline-start: 5px;
padding-inline-end: 5px;
padding-left: 5px;
padding-right: 5px;
}
.open-external-link-button {
cursor: pointer;
font-size: 1.3em;
padding-inline-start: 5px;
padding-inline-end: 5px;
padding-left: 5px;
padding-right: 5px;
padding-top: 8px;
}
.go-to-selected-note-button {
cursor: pointer;
font-size: 1.3em;
padding-inline-start: 4px;
padding-inline-end: 3px;
padding-left: 4px;
padding-right: 3px;
}
.go-to-selected-note-button.disabled,
@@ -680,7 +671,7 @@ pre > button.copy-button:active {
.note-autocomplete-input {
/* this is for seamless integration of "input clearer" button */
border-inline-end: 0;
border-right: 0;
}
table.promoted-attributes-in-tooltip {
@@ -713,10 +704,10 @@ table.promoted-attributes-in-tooltip th {
border-top-color: var(--main-border-color) !important;
}
.bs-tooltip-left .tooltip-arrow::before {
border-inline-start-color: var(--main-border-color) !important;
border-left-color: var(--main-border-color) !important;
}
.bs-tooltip-right .tooltip-arrow::before {
border-inline-end-color: var(--main-border-color) !important;
border-right-color: var(--main-border-color) !important;
}
.bs-tooltip-bottom .tooltip-arrow::after {
@@ -726,17 +717,17 @@ table.promoted-attributes-in-tooltip th {
border-top-color: var(--tooltip-background-color) !important;
}
.bs-tooltip-left .tooltip-arrow::after {
border-inline-start-color: var(--tooltip-background-color) !important;
border-left-color: var(--tooltip-background-color) !important;
}
.bs-tooltip-right .tooltip-arrow::after {
border-inline-end-color: var(--tooltip-background-color) !important;
border-right-color: var(--tooltip-background-color) !important;
}
.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::before,
.bs-tooltip-left .tooltip-arrow::before {
inset-inline-start: -1px;
left: -1px;
border-width: 0.4rem 0 0.4rem 0.4rem;
border-inline-start-color: var(--main-border-color) !important;
border-left-color: var(--main-border-color) !important;
}
.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::before,
@@ -748,9 +739,9 @@ table.promoted-attributes-in-tooltip th {
.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::before,
.bs-tooltip-right .tooltip-arrow::before {
inset-inline-end: -1px;
right: -1px;
border-width: 0.4rem 0.4rem 0.4rem 0;
border-inline-end-color: var(--main-border-color) !important;
border-right-color: var(--main-border-color) !important;
}
.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::before,
@@ -762,9 +753,9 @@ table.promoted-attributes-in-tooltip th {
.bs-tooltip-auto[data-popper-placement^="left"] .tooltip-arrow::after,
.bs-tooltip-left .tooltip-arrow::after {
inset-inline-start: -1px;
left: -1px;
border-width: 0.4rem 0 0.4rem 0.4rem;
border-inline-start-color: var(--tooltip-background-color) !important;
border-left-color: var(--tooltip-background-color) !important;
}
.bs-tooltip-auto[data-popper-placement^="bottom"] .tooltip-arrow::after,
@@ -776,9 +767,9 @@ table.promoted-attributes-in-tooltip th {
.bs-tooltip-auto[data-popper-placement^="right"] .tooltip-arrow::after,
.bs-tooltip-right .tooltip-arrow::after {
inset-inline-end: -1px;
right: -1px;
border-width: 0.4rem 0.4rem 0.4rem 0;
border-inline-end-color: var(--tooltip-background-color) !important;
border-right-color: var(--tooltip-background-color) !important;
}
.bs-tooltip-auto[data-popper-placement^="top"] .tooltip-arrow::after,
@@ -797,7 +788,7 @@ table.promoted-attributes-in-tooltip th {
background-color: var(--tooltip-background-color) !important;
border: 1px solid var(--main-border-color);
border-radius: 5px;
text-align: start;
text-align: left;
color: var(--main-text-color) !important;
max-width: 500px;
box-shadow: 10px 10px 93px -25px #aaaaaa;
@@ -830,7 +821,7 @@ table.promoted-attributes-in-tooltip th {
.note-tooltip-content .open-popup-button {
position: absolute;
inset-inline-end: 15px;
right: 15px;
bottom: 8px;
font-size: 1.2em;
color: inherit;
@@ -850,7 +841,7 @@ table.promoted-attributes-in-tooltip th {
}
.tooltip-inner figure.image-style-side {
float: inline-end;
float: right;
}
.tooltip.show {
@@ -899,7 +890,7 @@ table.promoted-attributes-in-tooltip th {
.aa-dropdown-menu .aa-suggestion .text {
display: inline-block;
width: calc(100% - 20px);
padding-inline-start: 4px;
padding-left: 4px;
}
.aa-dropdown-menu .aa-suggestion .search-result-title {
@@ -925,7 +916,7 @@ table.promoted-attributes-in-tooltip th {
}
.help-button {
float: inline-end;
float: right;
background: none;
font-weight: 900;
color: orange;
@@ -1013,7 +1004,7 @@ svg.ck-icon .note-icon {
--ck-content-line-height: var(--bs-body-line-height);
}
:root .ck-content .table table:not(.layout-table) th {
.ck-content .table table th {
background-color: var(--accented-background-color);
}
@@ -1042,7 +1033,7 @@ svg.ck-icon .note-icon {
counter-increment: footnote-counter;
display: flex;
list-style: none;
margin-inline-start: 0.5em;
margin-left: 0.5em;
}
.ck-content .footnote-item > * {
@@ -1050,13 +1041,13 @@ svg.ck-icon .note-icon {
}
.ck-content .footnote-back-link {
margin-inline-end: 0.1em;
margin-right: 0.1em;
position: relative;
top: -0.2em;
}
.ck-content .footnotes .footnote-back-link > sup {
margin-inline-end: 0;
margin-right: 0;
}
.ck-content .footnote-item:before {
@@ -1064,8 +1055,8 @@ svg.ck-icon .note-icon {
display: inline-block;
min-width: fit-content;
position: relative;
inset-inline-end: 0.2em;
text-align: end;
right: 0.2em;
text-align: right;
}
.ck-content .footnote-content {
@@ -1081,11 +1072,11 @@ svg.ck-icon .note-icon {
}
#options-dialog input[type="number"] {
text-align: end;
text-align: right;
}
.help-cards ul {
padding-inline-start: 20px;
padding-left: 20px;
}
.help-cards kbd {
@@ -1104,6 +1095,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.card {
color: inherit !important;
background-color: inherit !important;
border-color: var(--main-border-color) !important;
}
@@ -1161,8 +1153,8 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
}
.toast.no-title .toast-body {
padding-inline-start: 0;
padding-inline-end: 0;
padding-left: 0;
padding-right: 0;
}
.toast.no-title .toast-header {
@@ -1282,8 +1274,8 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
#context-menu-cover.show {
position: fixed;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.1);
@@ -1296,8 +1288,8 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
body.mobile #context-menu-container.mobile-bottom-menu {
position: fixed !important;
inset-inline-start: 0 !important;
inset-inline-end: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
top: unset !important;
max-height: 70vh;
@@ -1347,7 +1339,7 @@ body.desktop li.dropdown-submenu:hover > ul.dropdown-menu {
.dropdown-submenu > .dropdown-menu {
top: 0;
inset-inline-start: calc(100% - 2px); /* -2px, otherwise there's a small gap between menu and submenu where the hover can disappear */
left: calc(100% - 2px); /* -2px, otherwise there's a small gap between menu and submenu where the hover can disappear */
margin-top: -10px;
min-width: 15rem;
/* to make submenu scrollable https://github.com/zadam/trilium/issues/3136 */
@@ -1356,7 +1348,7 @@ body.desktop li.dropdown-submenu:hover > ul.dropdown-menu {
}
body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
inset-inline-start: calc(-100% + 10px);
left: calc(-100% + 10px);
}
.right-dropdown-widget {
@@ -1422,7 +1414,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
.ck.ck-slash-command-button__text-part,
.ck.ck-template-form__text-part {
margin-inline-start: 0.5em;
margin-left: 0.5em;
line-height: 1.2em !important;
}
@@ -1453,8 +1445,8 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
}
.area-expander-text {
padding-inline-start: 20px;
padding-inline-end: 20px;
padding-left: 20px;
padding-right: 20px;
white-space: nowrap;
}
@@ -1500,7 +1492,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
cursor: pointer;
border: none;
color: var(--launcher-pane-text-color);
background-color: transparent;
background: transparent;
flex-shrink: 0;
}
@@ -1541,16 +1533,16 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
position: fixed !important;
bottom: calc(var(--mobile-bottom-offset) + var(--launcher-pane-size)) !important;
top: unset !important;
inset-inline-start: 0 !important;
inset-inline-end: 0 !important;
left: 0 !important;
right: 0 !important;
transform: unset !important;
}
#mobile-sidebar-container {
position: fixed;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
transition: background-color 250ms ease-in-out;
@@ -1565,7 +1557,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
#mobile-sidebar-wrapper {
position: absolute;
top: 0;
inset-inline-start: 0;
left: 0;
bottom: 0;
width: 85vw;
padding-top: env(safe-area-inset-top);
@@ -1597,8 +1589,8 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
body.mobile .modal-dialog {
position: fixed;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
left: 0;
right: 0;
margin: 0 !important;
max-height: 85vh;
display: flex;
@@ -1756,12 +1748,12 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
display: flex;
flex-shrink: 0;
flex-direction: column;
margin-inline-start: 10px;
margin-inline-end: 5px;
background: transparent;
margin-left: 10px;
margin-right: 5px;
}
#right-pane .card-header {
background: inherit;
padding: 6px 0 3px 0;
width: 99%; /* to give minimal right margin */
background-color: var(--button-background-color);
@@ -1797,7 +1789,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
}
#right-pane .card-body ul {
padding-inline-start: 25px;
padding-left: 25px;
margin-bottom: 5px;
}
@@ -1808,15 +1800,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;
margin-left: auto;
margin-right: auto;
}
.note-split.full-content-width {
--max-content-width: unset;
max-width: 999999px;
}
button.close:hover {
@@ -1831,7 +1820,7 @@ button.close:hover {
.reference-link .bx {
position: relative;
top: 1px;
margin-inline-end: 3px;
margin-right: 3px;
}
.options-section:first-of-type h4 {
@@ -1869,7 +1858,7 @@ textarea {
.attachment-help-button {
display: inline-block;
margin-inline-start: 10px;
margin-left: 10px;
vertical-align: middle;
font-size: 1em;
}
@@ -1977,7 +1966,7 @@ textarea {
}
body.electron.platform-darwin:not(.native-titlebar) .tab-row-container {
padding-inline-start: 1em;
padding-left: 1em;
}
#tab-row-left-spacer {
@@ -1985,12 +1974,8 @@ body.electron.platform-darwin:not(.native-titlebar) .tab-row-container {
-webkit-app-region: drag;
}
body.electron.platform-darwin:not(.native-titlebar) #tab-row-left-spacer {
width: 80px;
}
.tab-row-widget {
padding-inline-end: calc(100vw - env(titlebar-area-width, 100vw));
padding-right: calc(100vw - env(titlebar-area-width, 100vw));
}
.tab-row-container .toggle-button {
@@ -2036,16 +2021,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 .promoted-attributes-widget,
body.zen .floating-buttons-children > *:not(.bx-edit-alt),
body.zen .action-button,
body.zen .note-split:not(.type-book) .note-list-widget {
body.zen .action-button {
display: none !important;
}
@@ -2056,7 +2038,7 @@ body.zen .split-note-container-widget > .gutter {
body.zen #launcher-pane {
position: absolute !important;
top: 0 !important;
inset-inline-end: 0 !important;
right: 0 !important;
width: 64px !important;
height: 64px !important;
background: transparent !important;
@@ -2067,8 +2049,8 @@ body.zen .title-row {
display: block !important;
height: unset !important;
-webkit-app-region: drag;
padding-inline-start: env(titlebar-area-x);
padding-inline-end: calc(100vw - env(titlebar-area-width, 100vw) + 2.5em);
padding-left: env(titlebar-area-x);
padding-right: calc(100vw - env(titlebar-area-width, 100vw) + 2.5em);
}
body.zen .floating-buttons {
@@ -2076,7 +2058,7 @@ body.zen .floating-buttons {
}
body.zen .floating-buttons-children {
inset-inline-end: 0;
right: 0;
}
body.zen .floating-buttons-children .button-widget {
@@ -2089,121 +2071,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 .ribbon-container .classic-toolbar-widget:not(:has(> .ck-toolbar)) {
/* Hide the toolbar wrapper if the toolbar is missing */
display: none;
}
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,
@@ -2344,7 +2217,7 @@ footer.webview-footer button {
.chat-input {
width: 100%;
resize: none;
padding-inline-end: 40px;
padding-right: 40px;
}
.chat-buttons {
@@ -2400,13 +2273,14 @@ footer.webview-footer button {
.admonition {
--accent-color: var(--card-border-color);
background: color-mix(in srgb, var(--accent-color) 15%, transparent);
border: 1px solid var(--accent-color);
box-shadow: var(--card-box-shadow);
background: var(--card-background-color);
border-radius: 0.5em;
padding: 1em;
margin: 1.25em 0;
position: relative;
padding-inline-start: 2.5em;
padding-left: 2.5em;
overflow: hidden;
}
@@ -2419,7 +2293,7 @@ footer.webview-footer button {
font-family: boxicons !important;
position: absolute;
top: 1em;
inset-inline-start: 1em;
left: 1em;
}
.admonition.note { --accent-color: var(--admonition-note-accent-color); }
@@ -2445,18 +2319,18 @@ footer.webview-footer button {
display: flex;
align-items: center;
font-size: 0.9em;
margin-inline-end: 15px;
margin-right: 15px;
cursor: pointer;
}
.chat-option input[type="checkbox"] {
margin-inline-end: 5px;
margin-right: 5px;
}
/* Style for thinking process in chat responses */
.thinking-process {
background-color: rgba(0, 0, 0, 0.05);
border-inline-start: 3px solid var(--main-text-color);
border-left: 3px solid var(--main-text-color);
padding: 10px;
margin: 10px 0;
border-radius: 4px;
@@ -2464,23 +2338,23 @@ footer.webview-footer button {
.thinking-step {
margin-bottom: 8px;
padding-inline-start: 10px;
padding-left: 10px;
}
.thinking-step.observation {
border-inline-start: 2px solid #69c7ff;
border-left: 2px solid #69c7ff;
}
.thinking-step.hypothesis {
border-inline-start: 2px solid #9839f7;
border-left: 2px solid #9839f7;
}
.thinking-step.evidence {
border-inline-start: 2px solid #40c025;
border-left: 2px solid #40c025;
}
.thinking-step.conclusion {
border-inline-start: 2px solid #e2aa03;
border-left: 2px solid #e2aa03;
font-weight: bold;
}
@@ -2495,17 +2369,17 @@ footer.webview-footer button {
.content-floating-buttons.top-left {
top: 10px;
inset-inline-start: 10px;
left: 10px;
}
.content-floating-buttons.bottom-left {
bottom: 10px;
inset-inline-start: 10px;
left: 10px;
}
.content-floating-buttons.bottom-right {
bottom: 10px;
inset-inline-end: 10px;
right: 10px;
}
.content-floating-buttons button.bx {
@@ -2520,7 +2394,7 @@ footer.webview-footer button {
transform: rotate(180deg);
}
/* CK Editor */
/* CK Edito */
/* Insert text snippet: limit the width of the listed items to avoid overly long names */
:root body.desktop div.ck-template-form li.ck-list__item .ck-template-form__text-part > span {
@@ -2536,32 +2410,4 @@ footer.webview-footer button {
.revision-diff-removed {
background: rgba(255, 100, 100, 0.5);
text-decoration: line-through;
}
iframe.print-iframe {
position: absolute;
top: 0;
left: -600px;
right: -600px;
bottom: 0;
width: 0;
height: 0;
}
.excalidraw.theme--dark canvas {
--theme-filter: invert(100%) hue-rotate(180deg);
}
/* Scrolling container */
.scrolling-container:has(> :is(.note-detail.full-height, .note-list-widget.full-height)) {
display: flex;
flex-direction: column;
}
.scrolling-container > .note-detail.full-height,
.scrolling-container > .note-list-widget.full-height {
position: relative;
flex-grow: 1;
width: 100%;
}

View File

@@ -67,13 +67,13 @@
}
.tabulator div.tabulator-header .tabulator-frozen.tabulator-frozen-left {
margin-inline-start: var(--cell-editing-border-width);
margin-left: var(--cell-editing-border-width);
}
.tabulator div.tabulator-header .tabulator-col,
.tabulator div.tabulator-header .tabulator-frozen.tabulator-frozen-left {
background: var(--col-header-background-color);
border-inline-end: var(--col-header-separator-border);
border-right: var(--col-header-separator-border);
}
/* Table body */
@@ -90,8 +90,8 @@
}
.tabulator-row .tabulator-cell input {
padding-inline-start: var(--cell-horiz-padding-size) !important;
padding-inline-end: var(--cell-horiz-padding-size) !important;
padding-left: var(--cell-horiz-padding-size) !important;
padding-right: var(--cell-horiz-padding-size) !important;
}
.tabulator-row {
@@ -117,12 +117,12 @@
/* Cell */
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left {
margin-inline-end: var(--cell-editing-border-width);
margin-right: var(--cell-editing-border-width);
}
.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left,
.tabulator-row .tabulator-cell {
border-inline-end-color: transparent;
border-right-color: transparent;
}
.tabulator-row .tabulator-cell:not(.tabulator-editable) {
@@ -156,14 +156,14 @@
/* Align items without children/expander to the ones with. */
.tabulator-cell[tabulator-field="title"] > span:first-child, /* 1st level */
.tabulator-cell[tabulator-field="title"] > div:first-child + span { /* sub-level */
padding-inline-start: 21px;
padding-left: 21px;
}
/* Checkbox cells */
.tabulator .tabulator-cell:has(svg),
.tabulator .tabulator-cell:has(input[type="checkbox"]) {
padding-inline-start: 8px;
padding-left: 8px;
display: inline-flex;
flex-direction: column;
justify-content: center;

View File

@@ -82,17 +82,6 @@ body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--dark-theme-custom-color);
}
:root .reference-link,
:root .reference-link:hover,
.ck-content a.reference-link > span,
.board-note {
color: var(--dark-theme-custom-color, inherit);
}
.excalidraw.theme--dark {
--theme-filter: invert(80%) hue-rotate(180deg) !important;
}
@@ -108,4 +97,3 @@ body .todo-list input[type="checkbox"]:not(:checked):before {
.ck-content pre {
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6) !important;
}

View File

@@ -81,14 +81,3 @@ html {
--mermaid-theme: default;
--native-titlebar-background: #ffffff00;
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--light-theme-custom-color);
}
:root .reference-link,
:root .reference-link:hover,
.ck-content a.reference-link > span,
.board-note {
color: var(--light-theme-custom-color, inherit);
}

View File

@@ -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;
@@ -160,15 +160,9 @@
--launcher-pane-horiz-background-color-bgfx: #ffffff17; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000080; /* When background effects enabled */
--global-menu-update-available-badge-background-color: #7dbe61;
--global-menu-update-available-badge-color: black;
--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 +189,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 +205,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;
@@ -230,9 +222,10 @@
--code-block-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
--card-background-color: #ffffff12;
--card-background-hover-color: #ffffff20;
--card-border-color: transparent;
--card-box-shadow: none;
--card-background-hover-color: #3c3c3c;
--card-background-press-color: #464646;
--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);
@@ -272,22 +265,6 @@
* Dark color scheme tweaks
*/
#left-pane .fancytree-node.tinted {
--custom-color: var(--dark-theme-custom-color);
/* The background color of the active item in the note tree.
* 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), 20%, 33%, 0.4);
}
:root .reference-link,
:root .reference-link:hover,
.ck-content a.reference-link > span,
.board-note {
color: var(--dark-theme-custom-color, inherit);
}
body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
@@ -299,9 +276,3 @@ 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%);
}

View File

@@ -127,7 +127,7 @@
--left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
--left-pane-item-action-button-background: rgba(0, 0, 0, 0.11);
--left-pane-item-action-button-color: var(--left-pane-text-color);
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, 0.15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, 0.25);
@@ -153,15 +153,9 @@
--launcher-pane-horiz-background-color-bgfx: #ffffffb3; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000026; /* When background effects enabled */
--global-menu-update-available-badge-background-color: #4fa450;
--global-menu-update-available-badge-color: white;
--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 +177,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,9 +204,7 @@
--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: #ffffff9e; /* Only for the vertical layout */
--right-pane-item-hover-background: #00000013;
--right-pane-item-hover-background: #ececec;
--right-pane-item-hover-color: inherit;
--scrollbar-thumb-color: #0000005c;
@@ -228,11 +220,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-hover-color: #0000001c;
--card-border-color: transparent;
--card-background-color: var(--accented-background-color);
--card-background-hover-color: #f9f9f9;
--card-background-press-color: #efefef;
--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);
@@ -265,19 +258,5 @@
--ck-editor-toolbar-button-on-color: black;
--ck-editor-toolbar-button-on-shadow: none;
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
}
#left-pane .fancytree-node.tinted {
--custom-color: var(--light-theme-custom-color);
/* The background color of the active item in the note tree.
* 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%);
}

View File

@@ -4,7 +4,6 @@
@import url(./pages.css);
@import url(./ribbon.css);
@import url(./notes/text.css);
@import url(./notes/canvas.css);
@import url(./notes/collections/table.css);
@font-face {
@@ -82,21 +81,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
* component of the color represented in the CIELAB color space, will be
* constrained to a certain percentage defined below.
*
* Note: the tree background may vary when background effects are enabled, so it is recommended
* to maintain a higher contrast margin than on the usual note tree solid background. */
/* The maximum perceptual lightness for the custom color in the light theme (%): */
--tree-item-light-theme-max-color-lightness: 60;
/* The minimum perceptual lightness for the custom color in the dark theme (%): */
--tree-item-dark-theme-min-color-lightness: 65;
}
body.backdrop-effects-disabled {
@@ -112,10 +96,9 @@ body.backdrop-effects-disabled {
* supported when this class is used.
*/
.dropdown-menu:not(.static),
:root .excalidraw .popover {
.dropdown-menu:not(.static) {
border-radius: var(--dropdown-border-radius);
padding: var(--padding, var(--menu-padding-size)) !important;
padding: var(--menu-padding-size) !important;
font-size: 0.9rem !important;
}
@@ -131,16 +114,14 @@ 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 .ck.ck-dropdown__panel::before {
content: "";
backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius);
position: absolute;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
}
@@ -167,17 +148,9 @@ body.desktop .dropdown-submenu .dropdown-menu {
}
.dropdown-item,
body.mobile .dropdown-submenu .dropdown-toggle,
.excalidraw .context-menu .context-menu-item {
--menu-item-start-padding: 8px;
--menu-item-end-padding: 22px;
--menu-item-vertical-padding: 2px;
padding-top: var(--menu-item-vertical-padding) !important;
padding-bottom: var(--menu-item-vertical-padding) !important;
padding-inline-start: var(--menu-item-start-padding) !important;
padding-inline-end: var(--menu-item-end-padding) !important;
body.mobile .dropdown-submenu .dropdown-toggle {
padding: 2px 2px 2px 8px !important;
padding-inline-end: 22px !important;
/* Note: the right padding should also accommodate the submenu arrow. */
border-radius: 6px;
cursor: default !important;
@@ -229,8 +202,7 @@ html body .dropdown-item[disabled] {
}
/* Menu item keyboard shortcut */
.dropdown-item kbd,
.excalidraw .context-menu-item__shortcut {
.dropdown-item kbd {
font-family: unset !important;
font-size: unset !important;
color: var(--menu-item-keyboard-shortcut-color) !important;
@@ -239,23 +211,21 @@ html body .dropdown-item[disabled] {
.dropdown-item span.keyboard-shortcut {
color: var(--menu-item-keyboard-shortcut-color) !important;
margin-inline-start: 16px;
margin-left: 16px;
}
.dropdown-divider,
.excalidraw .context-menu hr {
.dropdown-divider {
position: relative;
border-color: transparent !important;
overflow: visible;
}
.dropdown-divider::after,
.excalidraw .context-menu hr::before {
.dropdown-divider::after {
position: absolute;
content: "";
top: -1px;
inset-inline-start: calc(0px - var(--menu-padding-size));
inset-inline-end: calc(0px - var(--menu-padding-size));
left: calc(0px - var(--menu-padding-size));
right: calc(0px - var(--menu-padding-size));
border-top: 1px solid var(--menu-item-delimiter-color);
}
@@ -267,7 +237,7 @@ html body .dropdown-item[disabled] {
align-items: center;
justify-content: center;
top: 0;
inset-inline-end: 0;
right: 0;
margin: unset !important;
border: unset !important;
padding: 0 4px;
@@ -276,16 +246,10 @@ html body .dropdown-item[disabled] {
color: var(--menu-item-arrow-color) !important;
}
body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdown-toggle::after {
content: "\ea4d" !important;
}
/* Menu item group heading */
/* The heading body */
.dropdown-menu h6,
.excalidraw .dropdown-menu-container .dropdown-menu-group-title,
.excalidraw .dropdown-menu-container div[data-testid="canvas-background-label"] {
.dropdown-menu h6 {
position: relative;
background: transparent;
padding: 1em 8px 14px 8px;
@@ -296,14 +260,12 @@ body[dir=rtl] .dropdown-menu:not([data-popper-placement="bottom-start"]) .dropdo
}
/* The delimiter line */
.dropdown-menu h6::before,
.excalidraw .dropdown-menu-container .dropdown-menu-group-title::before,
.excalidraw .dropdown-menu-container div[data-testid="canvas-background-label"]::before {
.dropdown-menu h6::before {
content: "";
position: absolute;
bottom: 8px;
inset-inline-start: calc(0px - var(--menu-padding-size));
inset-inline-end: calc(0px - var(--menu-padding-size));
left: calc(0px - var(--menu-padding-size));
right: calc(0px - var(--menu-padding-size));
border-top: 1px solid var(--menu-item-delimiter-color);
}
@@ -395,13 +357,13 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
}
#toast-container .toast:not(.no-title) .bx {
margin-inline-end: 0.5em;
margin-right: 0.5em;
font-size: 1.1em;
opacity: 0.85;
}
#toast-container .toast.no-title .bx {
margin-inline-end: 0;
margin-right: 0;
font-size: 1.3em;
}
@@ -487,21 +449,13 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
--note-list-vertical-padding: 15px;
background-color: var(--card-background-color);
border: 1px solid var(--card-border-color) !important;
box-shadow: 2px 3px 4px var(--card-shadow-color);
border-radius: 12px;
user-select: none;
padding: 0;
margin: 5px 10px 5px 0;
}
:root .note-list .note-book-card:hover {
background-color: var(--card-background-hover-color);
transition: background-color 200ms ease-out;
}
:root .note-list.grid-view .note-book-card:active {
transform: scale(.98);
}
.note-list.list-view .note-book-card {
box-shadow: 0 0 3px var(--card-shadow-color);
}
@@ -510,6 +464,10 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
vertical-align: middle;
}
.note-list-wrapper .note-book-card:active {
background-color: var(--card-background-press-color);
}
.note-list-wrapper .note-book-card a {
color: inherit !important;
}
@@ -581,14 +539,9 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
padding: 0;
}
.note-list-wrapper .note-book-card .note-book-content.type-code {
height: 100%;
}
.note-list-wrapper .note-book-card .note-book-content.type-code pre {
height: 100%;
padding: 1em;
margin-bottom: 0;
}
.note-list-wrapper .note-book-card .bx {
@@ -596,6 +549,7 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
}
.note-list.grid-view .note-book-card:hover {
background: var(--card-background-color) !important;
filter: contrast(105%);
}

View File

@@ -29,7 +29,7 @@
display: flex;
justify-content: center;
align-items: center;
margin-inline-start: 8px;
margin-left: 8px;
border: 0;
border-radius: 50%;
padding: 0;
@@ -56,7 +56,7 @@
}
.modal .modal-header .help-button {
margin-inline-end: 0;
margin-right: 0;
font-size: calc(var(--modal-control-button-size) * .75);
font-family: unset;
font-weight: bold;
@@ -141,7 +141,7 @@ div.tn-tool-dialog {
/* Search box wrapper */
.jump-to-note-dialog .input-group {
margin-inline-end: 16px;
margin-right: 16px;
}
.jump-to-note-dialog .input-group:hover {
@@ -197,8 +197,8 @@ div.tn-tool-dialog {
border: unset;
padding-top: var(--timeline-item-top-padding);
padding-bottom: var(--timeline-item-bottom-padding);
padding-inline-start: calc(var(--timeline-left-gap) + var(--timeline-right-gap));
padding-inline-end: var(--timeline-left-gap);
padding-left: calc(var(--timeline-left-gap) + var(--timeline-right-gap));
padding-right: var(--timeline-left-gap);
color: var(--active-item-text-color);
}
@@ -259,7 +259,7 @@ div.tn-tool-dialog {
position: absolute;
content: "";
top: var(--connector-top, 0);
inset-inline-start: calc(var(--timeline-left-gap) + ((var(--timeline-bullet-size) - var(--timeline-connector-size)) / 2));
left: calc(var(--timeline-left-gap) + ((var(--timeline-bullet-size) - var(--timeline-connector-size)) / 2));
bottom: var(--connector-bottom, 0);
width: var(--timeline-connector-size);
border-radius: var(--connector-radius, 0) var(--connector-radius, 0) 0 0;
@@ -291,7 +291,7 @@ div.tn-tool-dialog {
position: absolute;
content: "";
top: calc(var(--timeline-item-top-padding) + var(--timeline-bullet-vertical-pos));
inset-inline-start: var(--timeline-left-gap);
left: var(--timeline-left-gap);
width: var(--timeline-bullet-size);
height: var(--timeline-bullet-size);
border-radius: 50%;
@@ -374,7 +374,7 @@ div.tn-tool-dialog {
}
.help-dialog .help-cards kbd:first-child {
margin-inline-start: 0;
margin-left: 0;
}
/* Inline code - used for Markdown samples */
@@ -392,8 +392,7 @@ div.tn-tool-dialog {
}
.delete-notes-list .note-path {
padding-inline-start: 8px;
color: var(--muted-text-color)
padding-left: 8px;
}
/*
@@ -402,7 +401,7 @@ div.tn-tool-dialog {
/* Labels */
.attr-edit-table th {
padding-inline-end: 12px;
padding-right: 12px;
font-weight: normal;
white-space: nowrap;
}
@@ -420,5 +419,5 @@ div.tn-tool-dialog {
}
.note-type-chooser-dialog div.note-type-dropdown .dropdown-item span.bx {
margin-inline-end: .25em;
margin-right: .25em;
}

View File

@@ -62,7 +62,7 @@ button.btn.btn-secondary span.bx,
button.btn.btn-sm span.bx,
button.btn.btn-success span.bx {
color: var(--cmd-button-icon-color);
padding-inline-end: 0.35em;
padding-right: 0.35em;
font-size: 1.2em;
}
@@ -71,7 +71,7 @@ button.btn.btn-primary kbd,
button.btn.btn-secondary kbd,
button.btn.btn-sm kbd,
button.btn.btn-success kbd {
margin-inline-start: 0.5em;
margin-left: 0.5em;
background: var(--cmd-button-keyboard-shortcut-background);
color: var(--cmd-button-keyboard-shortcut-color);
font-size: 0.6em;
@@ -102,7 +102,7 @@ button.btn.btn-success kbd {
}
.btn-group .tn-tool-button + .tn-tool-button {
margin-inline-start: 4px !important;
margin-left: 4px !important;
}
/* The "x" icon button */
@@ -237,7 +237,7 @@ input::selection,
outline-offset: 6px;
background: var(--input-background-color);
border-radius: 6px;
padding-inline-end: 8px;
padding-right: 8px;
color: var(--quick-search-color);
flex-wrap: nowrap;
}
@@ -357,20 +357,13 @@ select.form-control,
outline: 3px solid transparent;
outline-offset: 6px;
padding-inline-end: calc(15px + 1.5rem);
background: var(--input-background-color) var(--dropdown-arrow);;
padding-right: calc(15px + 1.5rem);
background: var(--input-background-color) var(--dropdown-arrow);
color: var(--input-text-color);
border: unset;
border-radius: 0.375rem;
}
body[dir=rtl] select,
body[dir=rtl] select.form-select,
body[dir=rtl] select.form-control,
body[dir=rtl] .select-button.dropdown-toggle.btn {
background-position: left 0.75rem center;
}
select:hover,
select.form-select:hover,
select.form-control:hover,
@@ -451,7 +444,7 @@ optgroup {
content: "\eae1";
width: 2em;
height: 100%;
inset-inline-end: 0;
right: 0;
top: 0;
font-size: 1.2em;
font-family: boxicons;
@@ -469,7 +462,7 @@ optgroup {
--box-label-gap: 0.5em;
position: relative;
padding-inline-start: calc(var(--box-size) + var(--box-label-gap)) !important;
padding-left: calc(var(--box-size) + var(--box-label-gap)) !important;
user-select: none;
}
@@ -478,7 +471,7 @@ optgroup {
label.tn-checkbox > input[type="checkbox"] {
position: absolute;
top: 0;
inset-inline-start: 0;
left: 0;
width: var(--box-size);
height: 100%;
margin: unset;
@@ -492,7 +485,7 @@ optgroup {
content: "";
position: absolute;
top: 50%;
inset-inline-start: 0;
left: 0;
translate: 0 -50%;
width: var(--box-size);
height: var(--box-size);

View File

@@ -19,11 +19,11 @@
}
.chat-message.user-message {
margin-inline-start: auto;
margin-left: auto;
}
.chat-message.assistant-message {
margin-inline-end: auto;
margin-right: auto;
}
.message-avatar {
@@ -33,7 +33,7 @@
display: flex;
align-items: center;
justify-content: center;
margin-inline-end: 8px;
margin-right: 8px;
}
.user-message .message-avatar {

View File

@@ -1,261 +0,0 @@
:root .excalidraw {
--ui-font: var(--main-font-family);
/* Button hover background color */
--button-hover-bg: var(--hover-item-background-color);
--color-surface-high: var(--hover-item-background-color);
--button-active-border: transparent;
--color-brand-active: transparent;
--color-surface-mid: transparent;
--color-surface-low: transparent;
/* Slider colors */
--color-slider-track: var(--menu-item-delimiter-color);
--color-slider-thumb: var(--muted-text-color);
/* Selected button icon fill color */
--color-on-primary-container: var(--ck-editor-toolbar-button-on-color);
--color-primary: var(--ck-editor-toolbar-button-on-color);
/* Selected button icon background color */
--color-surface-primary-container: var(--ck-editor-toolbar-button-on-background);
--color-primary-light: var(--ck-editor-toolbar-button-on-background);
--island-bg-color: var(--floating-button-background-color);
}
/* Dark theme tweaks */
:root body .excalidraw.theme--dark {
--color-surface-high: transparent;
--color-brand-hover: transparent;
}
:root .excalidraw.theme--dark.excalidraw .App-mobile-menu,
:root .excalidraw.theme--dark.excalidraw .App-menu__left {
--button-hover-bg: var(--hover-item-background-color);
}
:root .excalidraw.theme--dark.excalidraw .dropdown-menu-button:hover {
--background: var(--hover-item-background-color);
}
/* Backdrop blur pseudo-element */
.Island:not(.App-menu__left)::before,
.excalidraw .picker::before,
:root .App-menu__left > .panelColumn > fieldset::before,
:root .App-menu__left > .panelColumn > label::before,
:root .App-menu__left > .panelColumn > div:has(> *)::before {
display: block;
position: absolute;
content: "";
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
backdrop-filter: blur(10px) saturate(6);
z-index: -1;
}
/* Note's root */
:root .type-canvas {
--floating-buttons-vert-offset: 20px;
}
/* Context menus */
/* Context menu - outer wrapper */
:root .excalidraw .popover {
--padding: 0;
max-width: unset;
overflow: hidden;
font-family: var(--main-font-family);
}
/* Context menu - inner wrapper */
:root .excalidraw .popover > .context-menu {
margin: 0;
padding: 8px !important;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
border: none;
padding: 0;
box-shadow: none;
background: transparent;
}
/* Context menu item */
:root .excalidraw .context-menu .context-menu-item {
--menu-item-start-padding: 22px;
border: 1px solid transparent;
}
/* Context menu item icon */
:root .excalidraw .dropdown-menu-item__icon {
color: var(--menu-item-icon-color);
}
/* Context menu item label */
:root .excalidraw .context-menu-item__label,
:root .excalidraw .context-menu-item.dangerous .context-menu-item__label {
color: var(--menu-text-color);
}
:root .excalidraw .context-menu-item:hover .context-menu-item__label {
color: var(--hover-item-text-color);
}
/* Context menu item keyboard shortcut */
:root .excalidraw .context-menu-item__shortcut {
padding: 0;
opacity: 1;
}
/* Context menu separator */
.excalidraw .context-menu .context-menu-item-separator {
margin: 8px 0;
opacity: 1;
}
/* Main menu */
/* Hide separators - no longer needed as the menu group headers feature a delimiter line */
.excalidraw .Island.dropdown-menu-container>div:not(:has(>*)) {
display: none;
}
/* Menu group header */
.excalidraw .dropdown-menu-container .dropdown-menu-group-title,
.excalidraw .Island.dropdown-menu-container div[data-testid="canvas-background-label"] {
margin: 0 !important;
}
/* Header */
.excalidraw .App-menu.App-menu_top {
align-items: center;
}
.excalidraw .App-menu.App-menu_top .App-menu_top__left {
/* Fixes a layout glitch with the header when the options panel is visbile */
--gap: 0 !important;
}
/* The parent element of the "Library" button */
.excalidraw .App-menu.App-menu_top > div:nth-child(3) {
flex-direction: row-reverse;
}
/* Panels */
.excalidraw .zoom-actions,
.undo-redo-buttons {
box-shadow: 1px 1px 1px var(--floating-button-shadow-color);
backdrop-filter: blur(10px) saturate(6);
}
:root .excalidraw .main-menu-trigger,
:root .excalidraw .sidebar-trigger,
:root .excalidraw .help-icon {
box-shadow: none;
}
/* Selected color outline */
:root .excalidraw .color-picker__button.active .color-picker__button-outline {
box-shadow: 0 0 0 2px var(--input-focus-outline-color);
}
:root .excalidraw .buttonList label.active {
border-color: transparent;
}
/* Options panel */
.excalidraw .Island.App-menu__left {
box-shadow: none;
background: transparent;
backdrop-filter: none;
width: 13.2em;
}
body[dir=ltr] .excalidraw .Island.App-menu__left {
right: 0;
}
body[dir=rtl] .excalidraw .Island.App-menu__left {
left: 0;
}
:root .App-menu__left > .panelColumn {
row-gap: 5px;
}
/* Options panel card */
:root .App-menu__left > .panelColumn > fieldset,
:root .App-menu__left > .panelColumn > label,
:root .App-menu__left > .panelColumn > div:has(> *) {
position: relative;
margin: 0;
border-radius: 4px;
box-shadow: 1px 1px 1px var(--floating-button-shadow-color);
background: var(--floating-button-background-color);
padding: 8px 12px;
/* backdrop: blur() creates a new stacking context that prevents some popovers like the
* arrowheads picker from being positioned correctly. To workaround this, the backdrop blur
* effect is applyed using a pseudo-element instead. */
}
/* Options panel card title */
:root .App-menu__left fieldset > legend,
:root .App-menu__left div > h3,
:root .App-menu__left > .panelColumn > label {
text-transform: uppercase;
font-size: .65rem;
letter-spacing: 1pt;
color: var(--muted-text-color);
}
/* Options panel button bar */
:root .excalidraw .App-menu__left .buttonList {
padding: 0;
}
/* Picker */
body[dir=ltr] .excalidraw .App-menu__left .buttonList .picker {
translate: -80% 0;
}
/* Properties panel */
body[dir=ltr] .excalidraw .exc-stats {
left: 0;
}
body[dir=rtl] .excalidraw .exc-stats {
right: 0;
}
/* Sidebar */
.split-note-container-widget > .component.type-canvas:has(.excalidraw-container > .Island.default-sidebar) > .floating-buttons {
/* Hide the floating buttons when the sidebar is open */
display: none;
}
/* Pickers */
.excalidraw .picker {
position: relative;
}

View File

@@ -117,9 +117,9 @@
content: "";
position: absolute;
top: var(--negative-padding);
inset-inline-end: var(--negative-padding);
right: var(--negative-padding);
bottom: var(--negative-padding);
inset-inline-start: var(--negative-padding);
left: var(--negative-padding);
border-radius: var(--dropdown-border-radius);
backdrop-filter: var(--dropdown-backdrop-filter);
z-index: -1;
@@ -210,7 +210,7 @@
/* Separator */
:root .ck .ck-list__separator {
margin: .5em 0;
margin-inline-start: calc(0px - var(--ck-editor-popup-padding));
margin-left: calc(0px - var(--ck-editor-popup-padding));
width: calc(100% + (var(--ck-editor-popup-padding) * 2));
background: var(--menu-item-delimiter-color);
}
@@ -233,8 +233,8 @@
position: absolute;
top: 0;
bottom: var(--negative-padding);
inset-inline-start: var(--negative-padding);
inset-inline-end: var(--negative-padding);
left: var(--negative-padding);
right: var(--negative-padding);
border-top: 1px solid var(--ck-editor-popup-border-color);
background: var(--menu-section-background-color);
}
@@ -255,7 +255,12 @@
:root .ck.ck-toolbar .ck.ck-toolbar__separator {
background: transparent;
border-inline-start: 1px solid var(--ck-color-toolbar-border);
border-left: 1px solid var(--ck-color-toolbar-border);
}
/* The last separator of the toolbar */
:root .classic-toolbar-widget .ck.ck-toolbar__separator:last-of-type {
flex-grow: 1;
}
/* Heading dropdown */
@@ -349,8 +354,7 @@
align-items: center;
width: 100%;
margin: 4px;
background: color-mix(in srgb, var(--accent) 15%, var(--main-background-color));
padding-inline-end: 2em;
padding-right: 2em;
border: 1px solid var(--accent);
border-radius: 6px;
}
@@ -488,7 +492,7 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck
/* Move the label above the text box regardless of the text box state */
transform: translate(0, calc(-.2em - var(--ck-input-label-height))) !important;
padding-inline-start: 0 !important;
padding-left: 0 !important;
background: transparent;
font-size: .85em;
font-weight: 600;
@@ -552,7 +556,7 @@ pre button.copy-button.icon-action {
}
:root pre:has(> button.copy-button) {
padding-inline-end: calc(var(--icon-button-size) + (var(--copy-button-margin-size) * 2));
padding-right: calc(var(--icon-button-size) + (var(--copy-button-margin-size) * 2));
}
html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
@@ -611,12 +615,12 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
.ck-content blockquote:before {
content: "“";
inset-inline-start: 0.2em;
left: 0.2em;
}
.ck-content blockquote:after {
content: "”";
inset-inline-end: 0.35em;
right: 0.35em;
}
.ck-content h2,
@@ -661,30 +665,4 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
.ck-content .table > figcaption {
background: var(--accented-background-color);
color: var(--main-text-color);
}
/* Reference link */
.ck-content a.reference-link,
.ck-content a.reference-link:hover {
/* Apply underline only to the span inside the link so it can follow the
* target note's user defined color */
text-decoration: none;
}
.ck-content a.reference-link > span {
text-decoration: underline;
}
/*
* Read-only text content
*/
.note-detail-readonly-text:focus-visible {
outline: 2px solid var(--input-focus-outline-color);
border-radius: 4px;
}
.note-list-widget {
outline: 0 !important;
}

View File

@@ -52,7 +52,7 @@
background-color: #f5f5f5;
}
.google-login-btn img {
margin-inline-end: 10px;
margin-right: 10px;
width: 18px;
height: 18px;
}
@@ -63,7 +63,7 @@
/* Button bar */
.search-definition-widget .search-setting-table tbody:last-child div {
justify-content: flex-end;
justify-content: flex-end !important;
gap: 8px;
}
@@ -101,7 +101,7 @@
.sql-table-schemas-widget .sql-table-schemas button:hover,
.sql-table-schemas-widget .sql-table-schemas button:active,
.sql-table-schemas-widget .sql-table-schemas button:focus-visible {
--background: var(--card-background-hover-color);
--background: var(--card-background-press-color);
--color: var(--main-text-color);
}
@@ -123,12 +123,8 @@
*/
/* The container */
.note-split.empty-note {
--max-content-width: 70%;
}
.note-split.empty-note div.note-detail {
div.note-detail-empty {
max-width: 70%;
margin: 50px auto;
}
@@ -152,7 +148,7 @@
--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 */
@@ -177,19 +173,16 @@
}
.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);
}
@@ -200,20 +193,13 @@ 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;
margin-inline-start: calc(-1 * var(--options-card-padding));
margin-left: calc(-1 * var(--options-card-padding));
}
.options-section:not(.tn-no-card) h5 {
@@ -230,8 +216,8 @@ body.desktop .options-section:not(.tn-no-card) {
.options-section hr {
--bs-border-width: 2px;
margin-inline-start: calc(var(--options-card-padding) * -1);
margin-inline-end: calc(var(--options-card-padding) * -1);
margin-left: calc(var(--options-card-padding) * -1);
margin-right: calc(var(--options-card-padding) * -1);
opacity: 1;
color: var(--root-background);
}

View File

@@ -34,7 +34,6 @@
div.promoted-attributes-container {
margin-top: 8px;
margin-bottom: 8px;
margin-inline-start: 12px;
}
/*
@@ -42,7 +41,7 @@ div.promoted-attributes-container {
*/
/* The property label */
.note-info-item > span:first-child,
.note-info-widget-table th,
.file-properties-widget .file-table th,
.image-properties > div:first-child > span > strong {
opacity: 0.65;
@@ -50,6 +49,7 @@ div.promoted-attributes-container {
vertical-align: top;
}
.note-info-widget-table td,
.file-properties-widget .file-table td {
vertical-align: top;
}
@@ -95,7 +95,7 @@ div.promoted-attributes-container {
/* Note type dropdown */
ul.note-type-dropdown .check {
margin-inline-end: 6px;
margin-right: 6px;
}
ul.note-type-dropdown li.dropdown-item {
@@ -105,7 +105,7 @@ ul.note-type-dropdown li.dropdown-item {
/* Editability dropdown */
ul.editability-dropdown li.dropdown-item > div {
margin-inline-start: 4px;
margin-left: 4px;
}
.editability-dropdown .dropdown-item .description {
@@ -142,12 +142,12 @@ ul.editability-dropdown li.dropdown-item > div {
}
.attribute-list .save-attributes-button {
inset-inline-end: 30px;
right: 30px;
}
/* Note path in attribute detail dialog */
.attr-detail .note-path {
margin-inline-start: 8px;
margin-left: 8px;
}
/*

View File

@@ -8,7 +8,7 @@
}
:root {
--dropdown-backdrop-filter: blur(20px) saturate(6);
--dropdown-backdrop-filter: blur(10px) saturate(6);
--dropdown-border-radius: 10px;
}
@@ -16,13 +16,9 @@
background-color: var(--root-background);
}
body.mobile #root-widget {
background-color: var(--main-background-color);
}
body {
--native-titlebar-darwin-x-offset: 10;
--native-titlebar-darwin-y-offset: 12 !important;
--native-titlebar-darwin-y-offset: 17 !important;
}
body.layout-horizontal {
@@ -39,53 +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);
--gutter-color: var(--left-pane-background-color);
}
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 */
@@ -96,24 +69,12 @@ body.background-effects.theme-supports-background-effects.platform-win32 #center
/* Add a border to the vertical launch bar if collapsed. */
body.layout-vertical #horizontal-main-container.left-pane-hidden #launcher-pane.vertical {
border-inline-end: 2px solid var(--left-pane-collapsed-border-color);
border-right: 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;
}
/*
@@ -139,7 +100,7 @@ body.layout-horizontal > .horizontal {
align-items: center;
}
body[dir=ltr] #launcher-container {
#launcher-container {
scrollbar-gutter: stable both-edges;
}
@@ -318,13 +279,16 @@ body[dir=ltr] #launcher-container {
animation: sync-status-pulse 1s ease-in-out alternate-reverse infinite;
}
#launcher-pane button.global-menu-button {
--update-badge-x-offset: 3%;
--update-badge-y-offset: -12%;
#launcher-pane .global-menu-button {
--hover-item-background-color: transparent;
}
#launcher-pane.horizontal .global-menu-button .global-menu-button-update-available {
right: -23px;
bottom: -22px;
transform: scale(0.85);
}
.tooltip .tooltip-arrow {
display: none;
}
@@ -436,9 +400,9 @@ body[dir=ltr] #launcher-container {
content: "";
position: absolute;
top: var(--vertical-margin);
inset-inline-end: var(--horiz-margin);
right: var(--horiz-margin);
bottom: var(--vertical-margin);
inset-inline-start: var(--horiz-margin);
left: var(--horiz-margin);
border-radius: 6px;
background: var(--calendar-day-highlight-background);
z-index: -1;
@@ -486,7 +450,7 @@ div.bookmark-folder-widget .note-link:hover {
}
div.bookmark-folder-widget .note-link a {
padding-inline-start: 8px;
padding-left: 8px;
color: var(--menu-text-color);
cursor: default;
}
@@ -507,8 +471,8 @@ div.bookmark-folder-widget .note-link .bx {
div.quick-search {
--padding-top: 8px;
--padding-inline-start: 8px;
--padding-inline-end: 8px;
--padding-left: 8px;
--padding-right: 8px;
--padding-bottom: 8px;
position: relative;
@@ -516,7 +480,7 @@ div.quick-search {
align-items: center;
height: unset;
contain: unset;
padding: var(--padding-top) var(--padding-inline-end) var(--padding-bottom) var(--padding-inline-start);
padding: var(--padding-top) var(--padding-right) var(--padding-bottom) var(--padding-left);
}
div.quick-search,
@@ -532,9 +496,9 @@ div.quick-search::before {
position: absolute;
content: "";
top: var(--padding-top);
inset-inline-start: var(--padding-inline-start);
left: var(--padding-left);
bottom: var(--padding-bottom);
inset-inline-end: var(--padding-inline-end);
right: var(--padding-right);
z-index: 0;
border: 2px solid transparent;
border-radius: 6px;
@@ -556,7 +520,7 @@ div.quick-search:focus-within:before {
}
div.quick-search input {
padding-inline-start: 15px !important;
padding-left: 15px !important;
box-shadow: unset !important;
background: transparent !important;
}
@@ -575,7 +539,7 @@ div.quick-search .search-button {
justify-content: center;
width: 25px;
height: 25px;
margin-inline-end: 8px;
margin-right: 8px;
border-radius: 50%;
padding: 0;
color: var(--quick-search-color) !important;
@@ -667,18 +631,18 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
}
#left-pane .ui-fancytree ul {
padding-inline-start: 10px;
padding-left: 10px;
}
/* The root element of the tree */
#left-pane .fancytree-container > li:first-child > span {
padding-inline-start: 12px;
padding-left: 12px;
}
#left-pane span.fancytree-node.fancytree-active {
position: relative;
background: transparent !important;
color: var(--custom-color, var(--left-pane-item-selected-color));
color: var(--left-pane-item-selected-color) !important;
}
@keyframes left-pane-item-select {
@@ -694,10 +658,10 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
position: absolute;
content: "";
top: var(--left-pane-item-selected-shadow-size);
inset-inline-start: var(--left-pane-item-selected-shadow-size);
left: var(--left-pane-item-selected-shadow-size);
bottom: var(--left-pane-item-selected-shadow-size);
inset-inline-end: var(--left-pane-item-selected-shadow-size);
background: var(--custom-bg-color, var(--left-pane-item-selected-background)) !important;
right: var(--left-pane-item-selected-shadow-size);
background: var(--left-pane-item-selected-background) !important;
box-shadow: var(--left-pane-item-selected-shadow);
border-radius: 6px;
animation: left-pane-item-select 200ms ease-out;
@@ -712,7 +676,7 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
#left-pane span.fancytree-node.protected > span.fancytree-custom-icon:after {
position: absolute;
bottom: 0;
inset-inline-end: 0;
right: 0;
font-size: 14px;
content: "\eb4a";
font-family: "boxicons";
@@ -721,10 +685,6 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
border-radius: 50%;
}
body[dir=rtl] #left-pane span.fancytree-node.protected > span.fancytree-custom-icon:after {
transform: translateX(-25%);
}
body.mobile .fancytree-expander::before,
body.mobile .fancytree-title,
body.mobile .fancytree-node > span {
@@ -739,7 +699,7 @@ body.mobile .fancytree-node > span {
body.mobile:not(.force-fixed-tree) #mobile-sidebar-wrapper {
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
border-inline-end: 1px solid var(--subtle-border-color);
border-right: 1px solid var(--subtle-border-color);
}
}
@@ -757,6 +717,9 @@ body.mobile .fancytree-node > span {
margin-top: 0; /* Use this to align the icon with the tree view item's caption */
}
#left-pane span .fancytree-title {
margin-top: -5px;
}
#left-pane span.fancytree-active .fancytree-title {
font-weight: normal;
@@ -771,7 +734,7 @@ body.mobile .fancytree-node > span {
}
#left-pane .tree-item-button {
margin-inline-end: 6px;
margin-right: 6px;
border: unset;
border-radius: 50%;
background: var(--left-pane-item-action-button-background);
@@ -805,12 +768,12 @@ body.mobile .fancytree-node > span {
/* Toolbar container (collapsed state) */
#left-pane .tree-actions {
max-width: var(--tree-actions-toolbar-collapsed-width);
inset-inline-end: var(--tree-actions-toolbar-horizontal-margin);
right: var(--tree-actions-toolbar-horizontal-margin);
bottom: var(--tree-actions-toolbar-vertical-margin);
overflow: hidden;
border: 1px solid transparent;
padding: var(--tree-actions-toolbar-padding-size);
padding-inline-end: var(--tree-actions-toolbar-collapsed-width);
padding-right: var(--tree-actions-toolbar-collapsed-width);
background: transparent;
transition:
max-width 400ms ease-out,
@@ -854,7 +817,7 @@ body.mobile .fancytree-node > span {
justify-content: center;
align-items: center;
top: 50%;
inset-inline-end: calc((var(--tree-actions-toolbar-collapsed-width) - var(--tree-actions-toolbar-expand-button-size)) / 2);
right: calc((var(--tree-actions-toolbar-collapsed-width) - var(--tree-actions-toolbar-expand-button-size)) / 2);
width: var(--tree-actions-toolbar-expand-button-size);
height: var(--tree-actions-toolbar-expand-button-size);
box-shadow: 2px 2px 6px var(--left-pane-background-color);
@@ -943,8 +906,8 @@ body.electron.background-effects.layout-horizontal .tab-row-container .toggle-bu
content: "";
position: absolute;
bottom: 0;
inset-inline-start: -10px;
inset-inline-end: -10px;
left: -10px;
right: -10px;
top: 32px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
@@ -955,13 +918,13 @@ body.electron.background-effects.layout-horizontal .tab-row-container .tab-scrol
position: relative;
}
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-inset-inline-start:after,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-inset-inline-end:after {
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left:after,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right:after {
content: "";
position: absolute;
bottom: 0;
inset-inline-start: 0px;
inset-inline-end: 0px;
left: 0px;
right: 0px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
@@ -970,9 +933,9 @@ body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[
content: "";
position: absolute;
bottom: 0;
inset-inline-start: -32768px;
left: -32768px;
top: var(--tab-height);
inset-inline-end: calc(100% - 1px);
right: calc(100% - 1px);
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
@@ -981,9 +944,9 @@ body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[
content: "";
position: absolute;
bottom: 0;
inset-inline-start: 100%;
left: 100%;
top: var(--tab-height);
inset-inline-end: 0;
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
@@ -993,9 +956,9 @@ body.electron.background-effects.layout-horizontal .tab-row-container .note-new-
content: "";
position: absolute;
bottom: 0;
inset-inline-start: -4px;
left: -4px;
top: calc(var(--tab-height), -1);
inset-inline-end: 0;
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
@@ -1082,18 +1045,18 @@ body.layout-horizontal .tab-row-widget .note-tab .note-tab-wrapper {
content: "";
position: absolute;
top: 0;
inset-inline-start: 0;
inset-inline-end: 0;
left: 0;
right: 0;
height: 3px;
background-color: var(--workspace-tab-background-color);
}
body:not([dir=rtl]) .tab-row-widget .note-tab:nth-child(1) {
.tab-row-widget .note-tab:nth-child(1) {
transform: translate3d(var(--tab-first-item-horiz-offset), 0, 0);
}
:root .tab-row-widget .note-tab .note-tab-icon {
padding-inline-end: 5px; /* The gap between the icon and the title */
padding-right: 5px; /* The gap between the icon and the title */
}
.tab-row-widget .note-tab[active] .note-tab-icon {
@@ -1138,7 +1101,7 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
.tab-row-widget .note-new-tab {
position: relative;
margin-inline-start: 3px;
margin-left: 3px;
color: transparent; /* Prevent the original "+" from being displayed */
}
@@ -1151,7 +1114,7 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
position: absolute;
content: "";
top: calc((var(--tab-height) - var(--new-tab-button-size)) / 2);
inset-inline-start: calc((var(--tab-height) - var(--new-tab-button-size)) / 2);
left: calc((var(--tab-height) - var(--new-tab-button-size)) / 2);
width: var(--new-tab-button-size);
height: var(--new-tab-button-size);
background: var(--new-tab-button-background);
@@ -1176,7 +1139,7 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
display: flex;
position: absolute;
content: "\ebc0";
inset-inline-start: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
@@ -1210,18 +1173,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;
}
/*
@@ -1234,9 +1202,9 @@ body:not(.background-effects) #center-pane .note-split {
@keyframes note-entrance {
from {
filter: opacity(0);
opacity: 0;
} to {
filter: opacity(1);
opacity: 1;
}
}
@@ -1253,23 +1221,23 @@ body.mobile .note-title {
}
.title-row > *:first-child {
margin-inline-end: 0;
margin-right: 0;
}
.title-row > *:nth-child(2) {
margin-inline-start: 0;
margin-left: 0;
}
.title-row {
/* Aligns the "Create new split" button with the note menu button (the three dots button) */
padding-inline-end: 3px;
padding-right: 3px;
}
.note-title-widget input {
--input-background-color: transparent;
border-radius: 8px;
padding-inline-start: 12px;
padding-left: 12px;
}
/* The "Change note icon" button */
@@ -1344,7 +1312,7 @@ body.mobile .note-title {
/* The promoted attributes section */
div.promoted-attributes-container {
display: flex;
margin-inline-end: 10%;
margin-right: 10%;
padding: 6px 0;
gap: 8px;
align-items: stretch;
@@ -1358,15 +1326,16 @@ div.promoted-attributes-container input {
/* A promoted attribute card */
div.promoted-attribute-cell {
--pa-card-padding-inline-start: 16px;
--pa-card-padding-inline-end: 2px;
--pa-card-padding-left: 16px;
--pa-card-padding-right: 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;
padding: 2px var(--pa-card-padding-inline-end) 2px var(--pa-card-padding-inline-start);
padding: 2px var(--pa-card-padding-right) 2px var(--pa-card-padding-left);
background: var(--promoted-attribute-card-background-color);
overflow-y: visible;
}
@@ -1381,7 +1350,7 @@ div.promoted-attribute-cell {
/* A promoted attribute card (boolean attribute) */
div.promoted-attribute-cell:has(input[type="checkbox"]):not(:has(.multiplicity > span)) {
/* Checbox attribute, without multiplicity */
padding-inline-end: var(--pa-card-padding-inline-start);
padding-right: var(--pa-card-padding-left);
}
div.promoted-attribute-cell > * {
@@ -1431,15 +1400,15 @@ div.promoted-attribute-cell .tn-checkbox {
/* Relocate the checkbox before the label */
div.promoted-attribute-cell.promoted-attribute-label-boolean > div:first-of-type {
order: -1;
margin-inline-end: 1.5em;
margin-right: 1.5em;
}
/* The element containing the "new attribute" and "remove this attribute button" */
div.promoted-attribute-cell .multiplicity:has(span) {
--icon-button-size: 24px;
margin-inline-start: 8px;
margin-inline-end: calc(var(--pa-card-padding-inline-start) - var(--pa-card-padding-inline-end));
margin-left: 8px;
margin-right: calc(var(--pa-card-padding-left) - var(--pa-card-padding-right));
font-size: 0; /* Prevent whitespaces creating a gap between buttons */
display: flex;
}
@@ -1467,10 +1436,6 @@ div#center-pane .floating-buttons-children {
opacity 250ms ease-out;
}
body[dir=rtl] div#center-pane .floating-buttons-children {
transform-origin: left;
}
/* Floating buttons container (collapsed) */
div#center-pane .floating-buttons-children.temporarily-hidden {
display: flex !important;
@@ -1582,7 +1547,7 @@ div.floating-buttons-children .close-floating-buttons {
}
div.floating-buttons-children .close-floating-buttons {
margin-inline-start: 0 !important;
margin-left: 0 !important;
background: var(--floating-button-hide-button-background);
color: var(--floating-button-hide-button-color);
}
@@ -1672,12 +1637,12 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
}
.find-replace-widget .form-check {
padding-inline-start: 0;
padding-left: 0;
white-space: nowrap;
}
.find-replace-widget .form-check .form-check-input {
margin-inline-start: 0;
margin-left: 0;
}
/* Narrow version */
@@ -1697,13 +1662,13 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
.find-widget-box,
.replace-widget-box {
padding-inline-end: 3em !important;
padding-right: 3em !important;
}
.find-widget-close-button {
position: absolute;
top: .85em;
inset-inline-end: .5em;
right: .5em;
}
.find-widget-box > * {
@@ -1735,7 +1700,7 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
}
.replace-widget-box > * {
margin-inline-end: unset !important;
margin-right: unset !important;
}
div.replace-widget-box button.btn.btn-sm {
@@ -1749,7 +1714,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 {
@@ -1778,7 +1743,7 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
#right-pane .toc li,
#right-pane .highlights-list li {
padding-top: 2px;
padding-inline-end: 8px;
padding-right: 8px;
padding-bottom: 2px;
border-radius: 4px;
text-align: unset;
@@ -1817,6 +1782,10 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
--border-radius-lg: 6px;
}
.excalidraw .Island {
backdrop-filter: var(--dropdown-backdrop-filter);
}
.excalidraw .Island.App-toolbar {
--island-bg-color: var(--floating-button-background-color);
--shadow-island: 1px 1px 1px var(--floating-button-shadow-color);
@@ -1837,8 +1806,8 @@ div.find-replace-widget div.find-widget-found-wrapper > span {
}
.excalidraw .dropdown-menu .dropdown-menu-container > div:not([class]):not(:last-child) {
margin-inline-start: calc(var(--padding) * var(--space-factor) * -1) !important;
margin-inline-end: calc(var(--padding) * var(--space-factor) * -1) !important;
margin-left: calc(var(--padding) * var(--space-factor) * -1) !important;
margin-right: calc(var(--padding) * var(--space-factor) * -1) !important;
}
.excalidraw .dropdown-menu:before {

View File

@@ -1,5 +1,5 @@
ul.fancytree-container {
padding-inline-start: 0;
padding-left: 0;
}
ul.fancytree-container li {
@@ -15,8 +15,10 @@ span.fancytree-node.fancytree-hide {
flex-shrink: 1;
flex-grow: 1;
overflow: hidden;
margin-inline-start: 7px;
margin-left: 7px;
outline: none;
position: relative;
top: 2px;
}
.fancytree-expander {
@@ -40,7 +42,6 @@ span.fancytree-node.fancytree-hide {
text-overflow: ellipsis;
user-select: none !important;
-webkit-user-select: none !important;
color: var(--custom-color, inherit);
}
.fancytree-node:not(.fancytree-loading) .fancytree-expander {
@@ -58,11 +59,7 @@ span.fancytree-node.fancytree-hide {
line-height: 1;
position: relative;
top: 2px;
margin-inline-end: 5px;
}
body[dir=rtl] .fancytree-node:not(.fancytree-loading):not(.fancytree-expanded) .fancytree-expander:before {
content: "\ea4d"; /* bx bx-chevron-left */
margin-right: 5px;
}
.fancytree-loading span.fancytree-expander {
@@ -83,7 +80,7 @@ body[dir=rtl] .fancytree-node:not(.fancytree-loading):not(.fancytree-expanded) .
width: 12px;
height: 12px;
margin-top: 2px;
margin-inline-start: 1px;
margin-left: 1px;
border-width: 1px;
border-style: solid;
}
@@ -172,15 +169,15 @@ span.fancytree-node.fancytree-active-clone:not(.fancytree-active) .fancytree-tit
/* first nesting level has lower left padding to avoid extra left padding. Other levels are not affected */
.ui-fancytree > li > ul {
padding-inline-start: 5px;
padding-left: 5px;
}
.ui-fancytree ul {
padding-inline-start: 20px;
padding-left: 20px;
}
span.fancytree-active {
color: var(--active-item-text-color);
color: var(--active-item-text-color) !important;
background-color: var(--active-item-background-color) !important;
border-color: transparent; /* invisible border */
border-radius: 5px;
@@ -232,14 +229,14 @@ span.fancytree-node.archived {
display: none;
font-size: 120%;
cursor: pointer;
margin-inline-start: 8px;
margin-left: 8px;
padding: 1px;
border: 1px solid transparent;
border-radius: 5px;
}
.unhoist-button.bx.tree-item-button {
margin-inline-start: 0; /* unhoist button is on the left and doesn't need more margin */
margin-left: 0; /* unhoist button is on the left and doesn't need more margin */
display: block; /* keep always visible */
}

View File

@@ -3,8 +3,6 @@ import FNote from "../entities/fnote.js";
import froca from "../services/froca.js";
import FAttribute from "../entities/fattribute.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import FBranch from "../entities/fbranch.js";
import FBlob from "../entities/fblob.js";
type AttributeDefinitions = { [key in `#${string}`]: string; };
type RelationDefinitions = { [key in `~${string}`]: string; };
@@ -12,8 +10,6 @@ type RelationDefinitions = { [key in `~${string}`]: string; };
interface NoteDefinition extends AttributeDefinitions, RelationDefinitions {
id?: string | undefined;
title: string;
children?: NoteDefinition[];
content?: string;
}
/**
@@ -51,38 +47,6 @@ export function buildNote(noteDef: NoteDefinition) {
blobId: ""
});
froca.notes[note.noteId] = note;
let childNotePosition = 0;
// Manage content.
const content = noteDef.content ?? "";
note.getContent = async () => content;
const blob = new FBlob({
blobId: utils.randomString(10),
content,
contentLength: content.length,
dateModified: new Date().toISOString(),
utcDateModified: new Date().toISOString()
});
note.getBlob = async () => blob;
// Manage children.
if (noteDef.children) {
for (const childDef of noteDef.children) {
const childNote = buildNote(childDef);
const branchId = `${note.noteId}_${childNote.noteId}`;
const branch = new FBranch(froca, {
branchId,
noteId: childNote.noteId,
parentNoteId: note.noteId,
notePosition: childNotePosition,
fromSearchNote: false
});
froca.branches[branchId] = branch;
note.addChild(childNote.noteId, branchId, false);
childNotePosition += 10;
}
}
let position = 0;
for (const [ key, value ] of Object.entries(noteDef)) {

File diff suppressed because it is too large Load Diff

View File

@@ -39,10 +39,7 @@
"help_on_tree_prefix": "有关树前缀的帮助",
"prefix": "前缀: ",
"save": "保存",
"branch_prefix_saved": "分支前缀已保存。",
"edit_branch_prefix_multiple": "编辑 {{count}} 个分支的前缀",
"branch_prefix_saved_multiple": "已为 {{count}} 个分支保存分支前缀。",
"affected_branches": "受影响的分支 {{count}}:"
"branch_prefix_saved": "分支前缀已保存。"
},
"bulk_actions": {
"bulk_actions": "批量操作",
@@ -54,7 +51,7 @@
"bulk_actions_executed": "批量操作已成功执行。",
"none_yet": "暂无操作 ... 通过点击上方的可用操作添加一个操作。",
"labels": "标签",
"relations": "关系",
"relations": "关联关系",
"notes": "笔记",
"other": "其它"
},
@@ -107,8 +104,7 @@
"export_status": "导出状态",
"export_in_progress": "导出进行中:{{progressCount}}",
"export_finished_successfully": "导出成功完成。",
"format_pdf": "PDF - 用于打印或共享目的。",
"share-format": "HTML 网页发布——采用与共享笔记相同的主题,但可发布为静态网站。"
"format_pdf": "PDF - 用于打印或共享目的。"
},
"help": {
"noteNavigation": "笔记导航",
@@ -188,8 +184,7 @@
},
"import-status": "导入状态",
"in-progress": "导入进行中:{{progress}}",
"successful": "导入成功完成。",
"importZipRecommendation": "导入 ZIP 文件时,笔记层级将反映压缩文件内的子目录结构。"
"successful": "导入成功完成。"
},
"include_note": {
"dialog_title": "包含笔记",
@@ -264,6 +259,7 @@
"delete_all_revisions": "删除此笔记的所有修订版本",
"delete_all_button": "删除所有修订版本",
"help_title": "关于笔记修订版本的帮助",
"revision_last_edited": "此修订版本上次编辑于 {{date}}",
"confirm_delete_all": "您是否要删除此笔记的所有修订版本?",
"no_revisions": "此笔记暂无修订版本...",
"restore_button": "恢复",
@@ -650,9 +646,7 @@
"about": "关于 TriliumNext 笔记",
"logout": "登出",
"show-cheatsheet": "显示快捷帮助",
"toggle-zen-mode": "禅模式",
"new-version-available": "新更新可用",
"download-update": "取得版本 {{latestVersion}}"
"toggle-zen-mode": "禅模式"
},
"zen_mode": {
"button_exit": "退出禅模式"
@@ -690,8 +684,7 @@
"convert_into_attachment_failed": "笔记 '{{title}}' 转换失败。",
"convert_into_attachment_successful": "笔记 '{{title}}' 已成功转换为附件。",
"convert_into_attachment_prompt": "确定要将笔记 '{{title}}' 转换为父笔记的附件吗?",
"print_pdf": "导出为 PDF...",
"open_note_on_server": "在服务器上打开笔记"
"print_pdf": "导出为 PDF..."
},
"onclick_button": {
"no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序"
@@ -743,8 +736,7 @@
"insert_child_note": "插入子笔记",
"delete_this_note": "删除此笔记",
"error_cannot_get_branch_id": "无法获取 notePath '{{notePath}}' 的 branchId",
"error_unrecognized_command": "无法识别的命令 {{command}}",
"note_revisions": "笔记历史版本"
"error_unrecognized_command": "无法识别的命令 {{command}}"
},
"note_icon": {
"change_note_icon": "更改笔记图标",
@@ -757,7 +749,7 @@
"editable": "可编辑",
"basic_properties": "基本属性",
"language": "语言",
"configure_code_notes": "配置代码笔记…"
"configure_code_notes": "配置代码注释..."
},
"book_properties": {
"view_type": "视图类型",
@@ -773,8 +765,7 @@
"table": "表格",
"geo-map": "地理地图",
"board": "看板",
"include_archived_notes": "展示归档笔记",
"presentation": "演示"
"include_archived_notes": "展示归档笔记"
},
"edited_notes": {
"no_edited_notes_found": "今天还没有编辑过的笔记...",
@@ -996,7 +987,7 @@
},
"protected_session": {
"enter_password_instruction": "显示受保护的笔记需要输入您的密码:",
"start_session_button": "开始受保护的会话",
"start_session_button": "开始受保护的会话 <kbd>Enter</kbd>",
"started": "受保护的会话已启动。",
"wrong_password": "密码错误。",
"protecting-finished-successfully": "保护操作已成功完成。",
@@ -1111,8 +1102,10 @@
"title": "内容宽度",
"default_description": "Trilium默认会限制内容的最大宽度以提高在宽屏中全屏时的可读性。",
"max_width_label": "内容最大宽度(像素)",
"max_width_unit": "像素",
"centerContent": "保持内容居中"
"apply_changes_description": "要应用内容宽度更改,请点击",
"reload_button": "重载前端",
"reload_description": "来自外观选项的更改",
"max_width_unit": "像素"
},
"native_title_bar": {
"title": "原生标题栏(需要重新启动应用)",
@@ -1265,13 +1258,7 @@
"min-days-in-first-week": "第一周的最小天数",
"first-week-info": "第一周包含一年的第一个周四,基于 <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a> 标准。",
"first-week-warning": "更改第一周选项可能会导致与现有周笔记重复,已创建的周笔记将不会相应更新。",
"formatting-locale": "日期和数字格式",
"tuesday": "周二",
"wednesday": "周三",
"thursday": "周四",
"friday": "周五",
"saturday": "周六",
"formatting-locale-auto": "依应用的语言设置"
"formatting-locale": "日期和数字格式"
},
"backup": {
"automatic_backup": "自动备份",
@@ -1291,6 +1278,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": "目前还没有令牌。点击上面的按钮创建一个。",
@@ -1557,9 +1548,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": "请输入笔记标题..."
@@ -1919,7 +1908,7 @@
},
"custom_date_time_format": {
"title": "自定义日期/时间格式",
"description": "自定义通过 <shortcut /> 或工具栏插入的日期和时间格式有关日期/时间格式字符串中各个字符的含义,请参阅<doc>Day.js docs</doc>。",
"description": "通过<shortcut />或工具栏的方式可自定义日期和时间格式有关日期/时间格式字符串中各个字符的含义,请参阅<doc>Day.js docs</doc>。",
"format_string": "日期/时间格式字符串:",
"formatted_time": "格式化后日期/时间:"
},
@@ -2076,19 +2065,5 @@
},
"collections": {
"rendering_error": "出现错误无法显示内容。"
},
"presentation_view": {
"edit-slide": "编辑此幻灯片",
"start-presentation": "开始演示",
"slide-overview": "切换幻灯片概览"
},
"calendar_view": {
"delete_note": "删除笔记..."
},
"read-only-info": {
"read-only-note": "当前正在查看一个只读笔记。",
"auto-read-only-note": "这条笔记以只读模式显示便于快速加载。",
"auto-read-only-learn-more": "了解更多",
"edit-note": "编辑笔记"
}
}

View File

@@ -4,7 +4,7 @@
"homepage": "Domovská stránka:",
"app_version": "Verze aplikace:",
"db_version": "Verze DB:",
"sync_version": "Verze synchronizace:",
"sync_version": "Verze sync:",
"build_date": "Datum sestavení:",
"build_revision": "Revize sestavení:",
"data_directory": "Datový adresář:"
@@ -36,29 +36,6 @@
"add_link": "Přidat odkaz",
"help_on_links": "Nápověda k odkazům",
"note": "Poznámka",
"search_note": "hledat poznámku podle názvu",
"link_title": "Název odkazu",
"button_add_link": "Přidat odkaz"
},
"branch_prefix": {
"prefix": "Prefix: ",
"save": "Uložit"
},
"bulk_actions": {
"bulk_actions": "Hromadné akce",
"affected_notes": "Ovlivněné poznámky",
"notes": "Poznámky"
},
"confirm": {
"cancel": "Zrušit",
"ok": "OK"
},
"delete_notes": {
"cancel": "Zrušit",
"ok": "OK",
"close": "Zavřít"
},
"export": {
"close": "Zavřít"
"search_note": "hledat poznámku podle názvu"
}
}

View File

@@ -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.",
@@ -647,9 +646,7 @@
"about": "Über Trilium Notes",
"logout": "Abmelden",
"show-cheatsheet": "Cheatsheet anzeigen",
"toggle-zen-mode": "Zen Modus",
"new-version-available": "Neues Update verfügbar",
"download-update": "Version {{latestVersion}} herunterladen"
"toggle-zen-mode": "Zen Modus"
},
"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>",
@@ -736,8 +733,7 @@
"insert_child_note": "Untergeordnete Notiz einfügen",
"delete_this_note": "Diese Notiz löschen",
"error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden",
"error_unrecognized_command": "Unbekannter Befehl {{command}}",
"note_revisions": "Notiz Revisionen"
"error_unrecognized_command": "Unbekannter Befehl {{command}}"
},
"note_icon": {
"change_note_icon": "Notiz-Icon ändern",
@@ -766,8 +762,7 @@
"table": "Tabelle",
"geo-map": "Weltkarte",
"board": "Tafel",
"include_archived_notes": "Zeige archivierte Notizen",
"presentation": "Präsentation"
"include_archived_notes": "Zeige archivierte Notizen"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -989,9 +984,9 @@
},
"protected_session": {
"enter_password_instruction": "Um die geschützte Notiz anzuzeigen, musst du dein Passwort eingeben:",
"start_session_button": "Starte eine geschützte Sitzung",
"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 +1099,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": {
@@ -1257,13 +1255,7 @@
"min-days-in-first-week": "Mindestanzahl an Tagen in erster Woche",
"first-week-info": "Die erste Woche, die den ersten Donnerstag des Jahres enthält, basiert auf dem Standard <a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>.",
"first-week-warning": "Das Ändern der Optionen für die erste Woche kann zu Duplikaten mit bestehenden Wochen-Notizen führen. Bestehende Wochen-Notizen werden nicht entsprechend aktualisiert.",
"formatting-locale": "Datums- und Zahlenformat",
"tuesday": "Dienstag",
"wednesday": "Mittwoch",
"thursday": "Donnerstag",
"friday": "Freitag",
"saturday": "Samstag",
"formatting-locale-auto": "Basierend auf die Anwendungssprache"
"formatting-locale": "Datums- und Zahlenformat"
},
"backup": {
"automatic_backup": "Automatische Sicherung",
@@ -1283,6 +1275,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 +1512,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 +1645,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"
@@ -2073,10 +2067,5 @@
},
"collections": {
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
},
"presentation_view": {
"edit-slide": "Folie bearbeiten",
"start-presentation": "Präsentation starten",
"slide-overview": "Übersicht der Folien ein-/ausblenden"
}
}

Some files were not shown because too many files have changed in this diff Show More