Compare commits

..

3 Commits

Author SHA1 Message Date
perf3ct
ce298e477b feat(docs): try to fix meta.json 2025-08-21 16:32:10 +00:00
perf3ct
81c0e508ac yeet 2025-08-21 16:03:53 +00:00
perf3ct
065740eabc feat(docs): completely redo documentation 2025-08-21 15:55:44 +00:00
1039 changed files with 88139 additions and 49595 deletions

View File

@@ -1,6 +1,6 @@
root = true root = true
[*.{js,ts,tsx}] [*.{js,ts}]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 4 indent_size = 4

1
.env Normal file
View File

@@ -0,0 +1 @@
NODE_OPTIONS=--max_old_space_size=4096

View File

@@ -74,7 +74,7 @@ runs:
- name: Update build info - name: Update build info
shell: ${{ inputs.shell }} shell: ${{ inputs.shell }}
run: pnpm run chore:update-build-info run: npm run chore:update-build-info
# Critical debugging configuration # Critical debugging configuration
- name: Run electron-forge build with enhanced logging - name: Run electron-forge build with enhanced logging
@@ -86,8 +86,7 @@ runs:
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }} APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }} WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }} TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
TARGET_ARCH: ${{ inputs.arch }} run: pnpm nx --project=desktop electron-forge:make -- --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
# Add DMG signing step # Add DMG signing step
- name: Sign DMG - name: Sign DMG

View File

@@ -10,7 +10,7 @@ runs:
steps: steps:
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: "pnpm" cache: "pnpm"
@@ -23,7 +23,7 @@ runs:
shell: bash shell: bash
run: | run: |
pnpm run chore:update-build-info pnpm run chore:update-build-info
pnpm run --filter server package pnpm nx --project=server package
- name: Prepare artifacts - name: Prepare artifacts
shell: bash shell: bash
run: | run: |

View File

@@ -1,103 +0,0 @@
name: "Deploy to Cloudflare Pages"
description: "Deploys to Cloudflare Pages on either a temporary branch with preview comment, or on the production version if on the main branch."
inputs:
project_name:
description: "CloudFlare Pages project name"
comment_body:
description: "The message to display when deployment is ready"
default: "Deployment is ready."
required: false
production_url:
description: "The URL to mention as the production URL."
required: true
deploy_dir:
description: "The directory from which to deploy."
required: true
cloudflare_api_token:
description: "The Cloudflare API token to use for deployment."
required: true
cloudflare_account_id:
description: "The Cloudflare account ID to use for deployment."
required: true
github_token:
description: "The GitHub token to use for posting PR comments."
required: true
runs:
using: composite
steps:
# Install wrangler globally to avoid workspace issues
- name: Install Wrangler
shell: bash
run: npm install -g wrangler
# Deploy using Wrangler (use pre-installed wrangler)
- name: Deploy to Cloudflare Pages
id: deploy
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ inputs.cloudflare_api_token }}
accountId: ${{ inputs.cloudflare_account_id }}
command: pages deploy ${{ inputs.deploy_dir }} --project-name=${{ inputs.project_name}} --branch=${{ github.ref_name }}
wranglerVersion: '' # Use pre-installed version
# Deploy preview for PRs
- name: Deploy Preview to Cloudflare Pages
id: preview-deployment
if: github.event_name == 'pull_request'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ inputs.cloudflare_api_token }}
accountId: ${{ inputs.cloudflare_account_id }}
command: pages deploy ${{ inputs.deploy_dir }} --project-name=${{ inputs.project_name}} --branch=pr-${{ github.event.pull_request.number }}
wranglerVersion: '' # Use pre-installed version
# Post deployment URL as PR comment
- name: Comment PR with Preview URL
if: github.event_name == 'pull_request'
uses: actions/github-script@v8
env:
COMMENT_BODY: ${{ inputs.comment_body }}
PRODUCTION_URL: ${{ inputs.production_url }}
PROJECT_NAME: ${{ inputs.project_name }}
with:
github-token: ${{ inputs.github_token }}
script: |
const prNumber = context.issue.number;
// Construct preview URL based on Cloudflare Pages pattern
const projectName = process.env.PROJECT_NAME;
const previewUrl = `https://pr-${prNumber}.${projectName}.pages.dev`;
// Check if we already commented
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const customMessage = process.env.COMMENT_BODY;
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes(customMessage)
);
const mainUrl = process.env.PRODUCTION_URL;
const commentBody = `${customMessage}!\n\n🔗 Preview URL: ${previewUrl}\n📖 Production URL: ${mainUrl}\n\n✅ All checks passed\n\n_This preview will be updated automatically with new commits._`;
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
} else {
// Create new comment
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: commentBody
});
}

40
.github/instructions/nx.instructions.md vendored Normal file
View File

@@ -0,0 +1,40 @@
---
applyTo: '**'
---
// This file is automatically generated by Nx Console
You are in an nx workspace using Nx 21.3.9 and pnpm as the package manager.
You have access to the Nx MCP server and the tools it provides. Use them. Follow these guidelines in order to best help the user:
# General Guidelines
- When answering questions, use the nx_workspace tool first to gain an understanding of the workspace architecture
- For questions around nx configuration, best practices or if you're unsure, use the nx_docs tool to get relevant, up-to-date docs!! Always use this instead of assuming things about nx configuration
- If the user needs help with an Nx configuration or project graph error, use the 'nx_workspace' tool to get any errors
- To help answer questions about the workspace structure or simply help with demonstrating how tasks depend on each other, use the 'nx_visualize_graph' tool
# Generation Guidelines
If the user wants to generate something, use the following flow:
- learn about the nx workspace and any specifics the user needs by using the 'nx_workspace' tool and the 'nx_project_details' tool if applicable
- get the available generators using the 'nx_generators' tool
- decide which generator to use. If no generators seem relevant, check the 'nx_available_plugins' tool to see if the user could install a plugin to help them
- get generator details using the 'nx_generator_schema' tool
- you may use the 'nx_docs' tool to learn more about a specific generator or technology if you're unsure
- decide which options to provide in order to best complete the user's request. Don't make any assumptions and keep the options minimalistic
- open the generator UI using the 'nx_open_generate_ui' tool
- wait for the user to finish the generator
- read the generator log file using the 'nx_read_generator_log' tool
- use the information provided in the log file to answer the user's question or continue with what they were doing
# Running Tasks Guidelines
If the user wants help with tasks or commands (which include keywords like "test", "build", "lint", or other similar actions), use the following flow:
- Use the 'nx_current_running_tasks_details' tool to get the list of tasks (this can include tasks that were completed, stopped or failed).
- If there are any tasks, ask the user if they would like help with a specific task then use the 'nx_current_running_task_output' tool to get the terminal output for that task/command
- Use the terminal output from 'nx_current_running_task_output' to see what's wrong and help the user fix their problem. Use the appropriate tools if necessary
- If the user would like to rerun the task or command, always use `nx run <taskId>` to rerun in the terminal. This will ensure that the task will run in the nx context and will be run the same way it originally executed
- If the task was marked as "continuous" do not offer to rerun the task. This task is already running and the user can see the output in the terminal. You can use 'nx_current_running_task_output' to get the output of the task to verify the output.

View File

@@ -1,128 +0,0 @@
# 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
push:
branches:
- main
- master # Also support master branch
# Only run when docs files change
paths:
- 'docs/**'
- '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:
# Run on pull requests for preview deployments
pull_request:
branches:
- main
- master
paths:
- 'docs/**'
- '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 MkDocs
runs-on: ubuntu-latest
timeout-minutes: 10
# Required permissions for deployment
permissions:
contents: read
deployments: write
pull-requests: write # For PR preview comments
id-token: write # For OIDC authentication (if needed)
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@v5
with:
node-version: '22'
cache: 'pnpm'
# Install Node.js dependencies for the TypeScript script
- name: Install Dependencies
run: |
pnpm install --frozen-lockfile
- 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/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
with:
project_name: "trilium-docs"
comment_body: "📚 Documentation preview is ready"
production_url: "https://docs.triliumnotes.org"
deploy_dir: "site"
cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,24 +19,45 @@ permissions:
pull-requests: write # for PR comments pull-requests: write # for PR comments
jobs: jobs:
check-affected:
name: Check affected jobs (NX)
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # needed for https://github.com/marketplace/actions/nx-set-shas
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Check affected
run: pnpm nx affected --verbose -t typecheck build rebuild-deps test-build
test_dev: test_dev:
name: Test development name: Test development
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs:
- check-affected
steps: steps:
- name: Checkout the repository - name: Checkout the repository
uses: actions/checkout@v5 uses: actions/checkout@v5
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: "pnpm" cache: "pnpm"
- run: pnpm install --frozen-lockfile - run: pnpm install --frozen-lockfile
- name: Typecheck
run: pnpm typecheck
- name: Run the unit tests - name: Run the unit tests
run: pnpm run test:all run: pnpm run test:all
@@ -45,6 +66,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- test_dev - test_dev
- check-affected
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
@@ -53,7 +75,7 @@ jobs:
- name: Update build info - name: Update build info
run: pnpm run chore:update-build-info run: pnpm run chore:update-build-info
- name: Trigger client build - name: Trigger client build
run: pnpm client:build run: pnpm nx run client:build
- name: Send client bundle stats to RelativeCI - name: Send client bundle stats to RelativeCI
if: false if: false
uses: relative-ci/agent-action@v3 uses: relative-ci/agent-action@v3
@@ -61,7 +83,7 @@ jobs:
webpackStatsFile: ./apps/client/dist/webpack-stats.json webpackStatsFile: ./apps/client/dist/webpack-stats.json
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }} key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
- name: Trigger server build - name: Trigger server build
run: pnpm run server:build run: pnpm nx run server:build
- uses: docker/setup-buildx-action@v3 - uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6 - uses: docker/build-push-action@v6
with: with:
@@ -73,6 +95,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- build_docker - build_docker
- check-affected
strategy: strategy:
matrix: matrix:
include: include:
@@ -89,7 +112,7 @@ jobs:
- name: Update build info - name: Update build info
run: pnpm run chore:update-build-info run: pnpm run chore:update-build-info
- name: Trigger build - name: Trigger build
run: pnpm server:build run: pnpm nx run server:build
- name: Set IMAGE_NAME to lowercase - name: Set IMAGE_NAME to lowercase
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV

View File

@@ -44,7 +44,7 @@ jobs:
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: "pnpm" cache: "pnpm"
@@ -82,7 +82,7 @@ jobs:
require-healthy: true require-healthy: true
- name: Run Playwright tests - name: Run Playwright tests
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm --filter=server-e2e e2e run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm exec nx run server-e2e:e2e
- name: Upload Playwright trace - name: Upload Playwright trace
if: failure() if: failure()
@@ -144,7 +144,7 @@ jobs:
uses: actions/checkout@v5 uses: actions/checkout@v5
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
@@ -152,12 +152,12 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Update build info
run: pnpm run chore:update-build-info
- name: Run the TypeScript build - name: Run the TypeScript build
run: pnpm run server:build run: pnpm run server:build
- name: Update build info
run: pnpm run chore:update-build-info
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v5
@@ -211,7 +211,7 @@ jobs:
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: digests-${{ env.PLATFORM_PAIR }}-${{ matrix.dockerfile }} name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/* path: /tmp/digests/*
if-no-files-found: error if-no-files-found: error
retention-days: 1 retention-days: 1

View File

@@ -19,6 +19,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
env: env:
GITHUB_UPLOAD_URL: https://uploads.github.com/repos/TriliumNext/Notes/releases/179589950/assets{?name,label}
GITHUB_RELEASE_ID: 179589950 GITHUB_RELEASE_ID: 179589950
permissions: permissions:
@@ -50,12 +51,13 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Update nightly version - name: Update nightly version
run: npm run chore:ci-update-nightly-version run: npm run chore:ci-update-nightly-version
- name: Run the build - name: Run the build
@@ -77,7 +79,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }} GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release - name: Publish release
uses: softprops/action-gh-release@v2.3.4 uses: softprops/action-gh-release@v2.3.2
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
with: with:
make_latest: false make_latest: false
@@ -118,7 +120,7 @@ jobs:
arch: ${{ matrix.arch }} arch: ${{ matrix.arch }}
- name: Publish release - name: Publish release
uses: softprops/action-gh-release@v2.3.4 uses: softprops/action-gh-release@v2.3.2
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
with: with:
make_latest: false make_latest: false

View File

@@ -4,8 +4,6 @@ on:
push: push:
branches: branches:
- main - main
paths-ignore:
- "apps/website/**"
pull_request: pull_request:
permissions: permissions:
@@ -21,8 +19,14 @@ jobs:
filter: tree:0 filter: tree:0
fetch-depth: 0 fetch-depth: 0
# This enables task distribution via Nx Cloud
# Run this command as early as possible, before dependencies are installed
# Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
# Connect your workspace by running "nx connect" and uncomment this line to enable task distribution
# - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci"
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5 - uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
@@ -30,12 +34,10 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps - run: pnpm exec playwright install --with-deps
- uses: nrwl/nx-set-shas@v4
- run: pnpm --filter server-e2e e2e # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: npx nx-cloud record -- echo Hello World
- name: Upload test report # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
if: failure() # When you enable task distribution, run the e2e-ci task instead of e2e
uses: actions/upload-artifact@v4 - run: pnpm exec nx affected -t e2e --exclude desktop-e2e
with:
name: e2e report
path: apps/server-e2e/test-output

View File

@@ -30,30 +30,18 @@ jobs:
image: win-signing image: win-signing
shell: cmd shell: cmd
forge_platform: win32 forge_platform: win32
# Exclude ARM64 Linux from default matrix to use native runner
exclude:
- arch: arm64
os:
name: linux
# Add ARM64 Linux with native ubuntu-24.04-arm runner for better-sqlite3 compatibility
include:
- arch: arm64
os:
name: linux
image: ubuntu-24.04-arm
shell: bash
forge_platform: linux
runs-on: ${{ matrix.os.image }} runs-on: ${{ matrix.os.image }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Set up node & dependencies - name: Set up node & dependencies
uses: actions/setup-node@v5 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: 'pnpm' cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- uses: nrwl/nx-set-shas@v4
- name: Run the build - name: Run the build
uses: ./.github/actions/build-electron uses: ./.github/actions/build-electron
with: with:
@@ -127,7 +115,7 @@ jobs:
path: upload path: upload
- name: Publish stable release - name: Publish stable release
uses: softprops/action-gh-release@v2.3.4 uses: softprops/action-gh-release@v2.3.2
with: with:
draft: false draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

View File

@@ -1,48 +0,0 @@
name: Deploy website
on:
push:
branches:
- main
paths:
- "apps/website/**"
pull_request:
paths:
- "apps/website/**"
jobs:
build-and-deploy:
runs-on: ubuntu-latest
name: Build & deploy website
permissions:
contents: read
deployments: write
pull-requests: write # For PR preview comments
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
with:
node-version: 22
cache: "pnpm"
- name: Install dependencies
run: pnpm install --filter website --frozen-lockfile
- name: Build the website
run: pnpm website:build
- name: Deploy
uses: ./.github/actions/deploy-to-cloudflare-pages
with:
project_name: "trilium-homepage"
comment_body: "📚 Website preview is ready"
production_url: "https://triliumnotes.org"
deploy_dir: "apps/website/dist"
cloudflare_api_token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
cloudflare_account_id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
github_token: ${{ secrets.GITHUB_TOKEN }}

11
.gitignore vendored
View File

@@ -1,5 +1,4 @@
# See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files. # See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
/.cache
# compiled output # compiled output
dist dist
@@ -33,11 +32,14 @@ testem.log
.DS_Store .DS_Store
Thumbs.db Thumbs.db
.nx/cache
.nx/workspace-data
vite.config.*.timestamp* vite.config.*.timestamp*
vitest.config.*.timestamp* vitest.config.*.timestamp*
test-output test-output
apps/*/data* apps/*/data
apps/*/out apps/*/out
upload upload
@@ -45,7 +47,4 @@ upload
*.tsbuildinfo *.tsbuildinfo
/result /result
.svelte-kit .svelte-kit
# docs
site/

2
.nvmrc
View File

@@ -1 +1 @@
22.20.0 22.18.0

View File

@@ -5,6 +5,7 @@
"lokalise.i18n-ally", "lokalise.i18n-ally",
"ms-azuretools.vscode-docker", "ms-azuretools.vscode-docker",
"ms-playwright.playwright", "ms-playwright.playwright",
"nrwl.angular-console",
"redhat.vscode-yaml", "redhat.vscode-yaml",
"tobermory.es6-string-html", "tobermory.es6-string-html",
"vitest.explorer", "vitest.explorer",

8
.vscode/mcp.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"servers": {
"nx-mcp": {
"type": "http",
"url": "http://localhost:9461/mcp"
}
}
}

View File

@@ -35,5 +35,6 @@
"docs/**/*.png": true, "docs/**/*.png": true,
"apps/server/src/assets/doc_notes/**": true, "apps/server/src/assets/doc_notes/**": true,
"apps/edit-docs/demo/**": true "apps/edit-docs/demo/**": true
} },
"nxConsole.generateAiAgentRules": true
} }

View File

@@ -20,10 +20,5 @@
"scope": "typescript", "scope": "typescript",
"prefix": "jqf", "prefix": "jqf",
"body": ["private $${1:name}!: JQuery<HTMLElement>;"] "body": ["private $${1:name}!: JQuery<HTMLElement>;"]
},
"region": {
"scope": "css",
"prefix": "region",
"body": ["/* #region ${1:name} */\n$0\n/* #endregion */"]
} }
} }

View File

@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Overview ## Overview
Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using pnpm, with multiple applications and shared packages. Trilium Notes is a hierarchical note-taking application with advanced features like synchronization, scripting, and rich text editing. It's built as a TypeScript monorepo using NX, with multiple applications and shared packages.
## Development Commands ## Development Commands
@@ -14,9 +14,12 @@ Trilium Notes is a hierarchical note-taking application with advanced features l
### Running Applications ### Running Applications
- `pnpm run server:start` - Start development server (http://localhost:8080) - `pnpm run server:start` - Start development server (http://localhost:8080)
- `pnpm nx run server:serve` - Alternative server start command
- `pnpm nx run desktop:serve` - Run desktop Electron app
- `pnpm run server:start-prod` - Run server in production mode - `pnpm run server:start-prod` - Run server in production mode
### Building ### Building
- `pnpm nx build <project>` - Build specific project (server, client, desktop, etc.)
- `pnpm run client:build` - Build client application - `pnpm run client:build` - Build client application
- `pnpm run server:build` - Build server application - `pnpm run server:build` - Build server application
- `pnpm run electron:build` - Build desktop application - `pnpm run electron:build` - Build desktop application
@@ -25,8 +28,13 @@ Trilium Notes is a hierarchical note-taking application with advanced features l
- `pnpm test:all` - Run all tests (parallel + sequential) - `pnpm test:all` - Run all tests (parallel + sequential)
- `pnpm test:parallel` - Run tests that can run in parallel - `pnpm test:parallel` - Run tests that can run in parallel
- `pnpm test:sequential` - Run tests that must run sequentially (server, ckeditor5-mermaid, ckeditor5-math) - `pnpm test:sequential` - Run tests that must run sequentially (server, ckeditor5-mermaid, ckeditor5-math)
- `pnpm nx test <project>` - Run tests for specific project
- `pnpm coverage` - Generate coverage reports - `pnpm coverage` - Generate coverage reports
### Linting & Type Checking
- `pnpm nx run <project>:lint` - Lint specific project
- `pnpm nx run <project>:typecheck` - Type check specific project
## Architecture Overview ## Architecture Overview
### Monorepo Structure ### Monorepo Structure
@@ -86,6 +94,7 @@ Frontend uses a widget system (`apps/client/src/widgets/`):
- `apps/server/src/assets/db/schema.sql` - Core database structure - `apps/server/src/assets/db/schema.sql` - Core database structure
4. **Configuration**: 4. **Configuration**:
- `nx.json` - NX workspace configuration
- `package.json` - Project dependencies and scripts - `package.json` - Project dependencies and scripts
## Note Types and Features ## Note Types and Features
@@ -145,7 +154,7 @@ Trilium provides powerful user scripting capabilities:
- Update schema in `apps/server/src/assets/db/schema.sql` - Update schema in `apps/server/src/assets/db/schema.sql`
## Build System Notes ## Build System Notes
- Uses pnpm for monorepo management - Uses NX for monorepo management with build caching
- Vite for fast development builds - Vite for fast development builds
- ESBuild for production optimization - ESBuild for production optimization
- pnpm workspaces for dependency management - pnpm workspaces for dependency management

View File

@@ -5,7 +5,7 @@
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total) ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [![Translation status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/) [![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [![Translation status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted.weblate.org/engage/trilium/)
[English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) | [Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README-ru.md) | [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) | [Spanish](./docs/README-es.md) [English](./README.md) | [Chinese (Simplified)](./docs/README-ZH_CN.md) | [Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases. Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
@@ -13,23 +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> <a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## 📚 Documentation
**Visit our comprehensive documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)**
Our documentation is available in multiple formats:
- **Online Documentation**: Browse the full documentation at [docs.triliumnotes.org](https://docs.triliumnotes.org/)
- **In-App Help**: Press `F1` within Trilium to access the same documentation directly in the application
- **GitHub**: Navigate through the [User Guide](./docs/User%20Guide/User%20Guide/) in this repository
### Quick Links
- [Getting Started Guide](https://docs.triliumnotes.org/)
- [Installation Instructions](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
- [Docker Setup](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
- [Upgrading TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
- [Basic Concepts and Features](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
- [Patterns of Personal Knowledge Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
## 🎁 Features ## 🎁 Features
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes)) * Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
@@ -71,7 +54,20 @@ The original Trilium developer ([Zadam](https://github.com/zadam)) has graciousl
There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Trilium instance. Simply [install TriliumNext/Trilium](#-installation) as usual and it will use your existing database. There are no special migration steps to migrate from a zadam/Trilium instance to a TriliumNext/Trilium instance. Simply [install TriliumNext/Trilium](#-installation) as usual and it will use your existing database.
Versions up to and including [v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) are compatible with the latest zadam/trilium version of [v0.63.7](https://github.com/zadam/trilium/releases/tag/v0.63.7). Any later versions of TriliumNext/Trilium have their sync versions incremented which prevents direct migration. Versions up to and including [v0.90.4](https://github.com/TriliumNext/Trilium/releases/tag/v0.90.4) are compatible with the latest TriliumNext/Trilium version of [v0.63.7](https://github.com/TriliumNext/Trilium/releases/tag/v0.63.7). Any later versions of TriliumNext/Trilium have their sync versions incremented which prevents direct migration.
## 📖 Documentation
We're currently in the progress of moving the documentation to in-app (hit the `F1` key within Trilium). As a result, there may be some missing parts until we've completed the migration. If you'd prefer to navigate through the documentation within GitHub, you can navigate the [User Guide](./docs/User%20Guide/User%20Guide/) documentation.
Below are some quick links for your convenience to navigate the documentation:
- [Server installation](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
- [Docker installation](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
- [Upgrading TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
- [Concepts and Features - Note](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
- [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
Until we finish reorganizing the documentation, you may also want to [browse the old documentation](https://triliumnext.github.io/Docs).
## 💬 Discuss with us ## 💬 Discuss with us
@@ -146,7 +142,7 @@ Download the repository, install dependencies using `pnpm` and then run the envi
git clone https://github.com/TriliumNext/Trilium.git git clone https://github.com/TriliumNext/Trilium.git
cd Trilium cd Trilium
pnpm install pnpm install
pnpm edit-docs:edit-docs pnpm nx run edit-docs:edit-docs
``` ```
### Building the Executable ### Building the Executable
@@ -155,7 +151,7 @@ Download the repository, install dependencies using `pnpm` and then build the de
git clone https://github.com/TriliumNext/Trilium.git git clone https://github.com/TriliumNext/Trilium.git
cd Trilium cd Trilium
pnpm install pnpm install
pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32 pnpm nx --project=desktop electron-forge:make -- --arch=x64 --platform=win32
``` ```
For more details, see the [development docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide). For more details, see the [development docs](https://github.com/TriliumNext/Trilium/tree/main/docs/Developer%20Guide/Developer%20Guide).
@@ -166,34 +162,16 @@ Please view the [documentation guide](https://github.com/TriliumNext/Trilium/blo
## 👏 Shoutouts ## 👏 Shoutouts
* [zadam](https://github.com/zadam) for the original concept and implementation of the application. * [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
* [Larsa](https://github.com/LarsaSara) for designing the application icon. * [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. Trilium Notes would not be the same without it.
* [nriver](https://github.com/nriver) for his work on internationalization. * [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas. * [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map)
* [antoniotejada](https://github.com/nriver) for the original syntax highlight widget.
* [Dosu](https://dosu.dev/) for providing us with the automated responses to GitHub issues and discussions.
* [Tabler Icons](https://tabler.io/icons) for the system tray icons.
Trilium would not be possible without the technologies behind it:
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - the visual editor behind text notes. We are grateful for being offered a set of the premium features.
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages.
* [Excalidraw](https://github.com/excalidraw/excalidraw) - the infinite whiteboard used in Canvas notes.
* [Mind Elixir](https://github.com/SSShooter/mind-elixir-core) - providing the mind map functionality.
* [Leaflet](https://github.com/Leaflet/Leaflet) - for rendering geographical maps.
* [Tabulator](https://github.com/olifolkerd/tabulator) - for the interactive table used in collections.
* [FancyTree](https://github.com/mar10/fancytree) - feature-rich tree library without real competition.
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map)
## 🤝 Support ## 🤝 Support
Trilium is built and maintained with [hundreds of hours of work](https://github.com/TriliumNext/Trilium/graphs/commit-activity). Your support keeps it open-source, improves features, and covers costs such as hosting. Support for the TriliumNext organization will be possible in the near future. For now, you can:
- Support continued development on TriliumNext by supporting our developers: [eliandoran](https://github.com/sponsors/eliandoran) (See the [repository insights]([developers]([url](https://github.com/TriliumNext/trilium/graphs/contributors))) for a full list)
Consider supporting the main developer ([eliandoran](https://github.com/eliandoran)) of the application via: - Show a token of gratitude to the original Trilium developer ([zadam](https://github.com/sponsors/zadam)) via [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
- [GitHub Sponsors](https://github.com/sponsors/eliandoran)
- [PayPal](https://paypal.me/eliandoran)
- [Buy Me a Coffee](https://buymeacoffee.com/eliandoran)
## 🔑 License ## 🔑 License

View File

@@ -8,9 +8,9 @@ fi
VERSION=$1 VERSION=$1
SERIES=${VERSION:0:4}-latest SERIES=${VERSION:0:4}-latest
docker push zadam/trilium:$VERSION docker push TriliumNext/Trilium:$VERSION
docker push zadam/trilium:$SERIES docker push TriliumNext/Trilium:$SERIES
if [[ $1 != *"beta"* ]]; then if [[ $1 != *"beta"* ]]; then
docker push zadam/trilium:latest docker push TriliumNext/Trilium:latest
fi fi

View File

@@ -35,13 +35,13 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js" "chore:generate-openapi": "tsx bin/generate-openapi.js"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "1.55.1", "@playwright/test": "1.54.2",
"@stylistic/eslint-plugin": "5.4.0", "@stylistic/eslint-plugin": "5.2.3",
"@types/express": "5.0.3", "@types/express": "5.0.3",
"@types/node": "22.18.8", "@types/node": "22.17.2",
"@types/yargs": "17.0.33", "@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4", "@vitest/coverage-v8": "3.2.4",
"eslint": "9.37.0", "eslint": "9.33.0",
"eslint-plugin-simple-import-sort": "12.1.1", "eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25", "esm": "3.2.25",
"jsdoc": "4.0.4", "jsdoc": "4.0.4",
@@ -49,7 +49,7 @@
"rcedit": "4.0.1", "rcedit": "4.0.1",
"rimraf": "6.0.1", "rimraf": "6.0.1",
"tslib": "2.8.1", "tslib": "2.8.1",
"typedoc": "0.28.13", "typedoc": "0.28.10",
"typedoc-plugin-missing-exports": "4.1.0" "typedoc-plugin-missing-exports": "4.1.0"
}, },
"optionalDependencies": { "optionalDependencies": {

View File

@@ -1,4 +1,5 @@
# The development license key for premium CKEditor features. # The development license key for premium CKEditor features.
# Note: This key must only be used for the Trilium Notes project. # Note: This key must only be used for the Trilium Notes project.
VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3ODcyNzA0MDAsImp0aSI6IjkyMWE1MWNlLTliNDMtNGRlMC1iOTQwLTc5ZjM2MDBkYjg1NyIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOiJ0cmlsaXVtIiwiZmVhdHVyZXMiOlsiVFJJTElVTSJdLCJ2YyI6ImU4YzRhMjBkIn0.hny77p-U4-jTkoqbwPytrEar5ylGCWBN7Ez3SlB8i6_mJCBIeCSTOlVQk_JMiOEq3AGykUMHzWXzjdMFwgniOw # Expires on: 2025-09-13
VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3NTc3MjE1OTksImp0aSI6ImFiN2E0NjZmLWJlZGMtNDNiYy1iMzU4LTk0NGQ0YWJhY2I3ZiIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsic2giLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkNNVCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJTRUUiLCJFQ0giLCJFSVMiXSwidmMiOiI1MzlkOWY5YyJ9.2rvKPql4hmukyXhEtWPZ8MLxKvzPIwzCdykO653g7IxRRZy2QJpeRszElZx9DakKYZKXekVRAwQKgHxwkgbE_w
VITE_CKEDITOR_ENABLE_INSPECTOR=false VITE_CKEDITOR_ENABLE_INSPECTOR=false

View File

@@ -1,21 +1,16 @@
{ {
"name": "@triliumnext/client", "name": "@triliumnext/client",
"version": "0.99.1", "version": "0.98.0",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)", "description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true, "private": true,
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"author": { "author": {
"name": "Trilium Notes Team", "name": "Trilium Notes Team",
"email": "contact@eliandoran.me", "email": "contact@eliandoran.me",
"url": "https://github.com/TriliumNext/Trilium" "url": "https://github.com/TriliumNext/Notes"
},
"scripts": {
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
"test": "vitest",
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
}, },
"dependencies": { "dependencies": {
"@eslint/js": "9.37.0", "@eslint/js": "9.33.0",
"@excalidraw/excalidraw": "0.18.0", "@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19", "@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19", "@fullcalendar/daygrid": "6.1.19",
@@ -24,7 +19,7 @@
"@fullcalendar/multimonth": "6.1.19", "@fullcalendar/multimonth": "6.1.19",
"@fullcalendar/timegrid": "6.1.19", "@fullcalendar/timegrid": "6.1.19",
"@maplibre/maplibre-gl-leaflet": "0.1.3", "@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.2.0", "@mermaid-js/layout-elk": "0.1.9",
"@mind-elixir/node-menu": "5.0.0", "@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8", "@popperjs/core": "2.11.8",
"@triliumnext/ckeditor5": "workspace:*", "@triliumnext/ckeditor5": "workspace:*",
@@ -33,31 +28,31 @@
"@triliumnext/highlightjs": "workspace:*", "@triliumnext/highlightjs": "workspace:*",
"@triliumnext/share-theme": "workspace:*", "@triliumnext/share-theme": "workspace:*",
"autocomplete.js": "0.38.1", "autocomplete.js": "0.38.1",
"bootstrap": "5.3.8", "bootstrap": "5.3.7",
"boxicons": "2.1.4", "boxicons": "2.1.4",
"dayjs": "1.11.18", "dayjs": "1.11.13",
"dayjs-plugin-utc": "0.1.2", "dayjs-plugin-utc": "0.1.2",
"debounce": "2.2.0", "debounce": "2.2.0",
"draggabilly": "3.0.0", "draggabilly": "3.0.0",
"force-graph": "1.51.0", "force-graph": "1.50.1",
"globals": "16.4.0", "globals": "16.3.0",
"i18next": "25.5.3", "i18next": "25.3.6",
"i18next-http-backend": "3.0.2", "i18next-http-backend": "3.0.2",
"jquery": "3.7.1", "jquery": "3.7.1",
"jquery.fancytree": "2.38.5", "jquery.fancytree": "2.38.5",
"jsplumb": "2.15.6", "jsplumb": "2.15.6",
"katex": "0.16.23", "katex": "0.16.22",
"knockout": "3.5.1", "knockout": "3.5.1",
"leaflet": "1.9.4", "leaflet": "1.9.4",
"leaflet-gpx": "2.2.0", "leaflet-gpx": "2.2.0",
"mark.js": "8.11.1", "mark.js": "8.11.1",
"marked": "16.3.0", "marked": "16.2.0",
"mermaid": "11.12.0", "mermaid": "11.10.0",
"mind-elixir": "5.1.1", "mind-elixir": "5.0.6",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"panzoom": "9.4.3", "panzoom": "9.4.3",
"preact": "10.27.2", "preact": "10.27.1",
"react-i18next": "16.0.0", "react-i18next": "15.6.1",
"split.js": "1.6.5", "split.js": "1.6.5",
"svg-pan-zoom": "3.6.2", "svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1", "tabulator-tables": "6.3.1",
@@ -67,14 +62,27 @@
"@ckeditor/ckeditor5-inspector": "5.0.0", "@ckeditor/ckeditor5-inspector": "5.0.0",
"@preact/preset-vite": "2.10.2", "@preact/preset-vite": "2.10.2",
"@types/bootstrap": "5.2.10", "@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33", "@types/jquery": "3.5.32",
"@types/leaflet": "1.9.20", "@types/leaflet": "1.9.20",
"@types/leaflet-gpx": "1.3.8", "@types/leaflet-gpx": "1.3.7",
"@types/mark.js": "8.11.12", "@types/mark.js": "8.11.12",
"@types/tabulator-tables": "6.2.11", "@types/tabulator-tables": "6.2.10",
"copy-webpack-plugin": "13.0.1", "copy-webpack-plugin": "13.0.1",
"happy-dom": "19.0.2", "happy-dom": "18.0.1",
"script-loader": "0.7.2", "script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.3" "vite-plugin-static-copy": "3.1.1"
},
"nx": {
"name": "client",
"targets": {
"serve": {
"dependsOn": [
"^build"
]
},
"circular-deps": {
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
}
}
} }
} }

View File

@@ -7,9 +7,6 @@
"display": "standalone", "display": "standalone",
"scope": "/", "scope": "/",
"start_url": "/", "start_url": "/",
"display_override": [
"window-controls-overlay"
],
"icons": [ "icons": [
{ {
"src": "icon.png", "src": "icon.png",

View File

@@ -1,6 +1,6 @@
import froca from "../services/froca.js"; import froca from "../services/froca.js";
import RootCommandExecutor from "./root_command_executor.js"; import RootCommandExecutor from "./root_command_executor.js";
import Entrypoints from "./entrypoints.js"; import Entrypoints, { type SqlExecuteResults } from "./entrypoints.js";
import options from "../services/options.js"; import options from "../services/options.js";
import utils, { hasTouchBar } from "../services/utils.js"; import utils, { hasTouchBar } from "../services/utils.js";
import zoomComponent from "./zoom.js"; import zoomComponent from "./zoom.js";
@@ -31,14 +31,16 @@ import { StartupChecks } from "./startup_checks.js";
import type { CreateNoteOpts } from "../services/note_create.js"; import type { CreateNoteOpts } from "../services/note_create.js";
import { ColumnComponent } from "tabulator-tables"; import { ColumnComponent } from "tabulator-tables";
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx"; import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
import type RootContainer from "../widgets/containers/root_container.js";
import { SqlExecuteResults } from "@triliumnext/commons";
interface Layout { interface Layout {
getRootWidget: (appContext: AppContext) => RootContainer; getRootWidget: (appContext: AppContext) => RootWidget;
} }
export interface BeforeUploadListener extends Component { interface RootWidget extends Component {
render: () => JQuery<HTMLElement>;
}
interface BeforeUploadListener extends Component {
beforeUnloadEvent(): boolean; beforeUnloadEvent(): boolean;
} }
@@ -83,6 +85,7 @@ export type CommandMappings = {
focusTree: CommandData; focusTree: CommandData;
focusOnTitle: CommandData; focusOnTitle: CommandData;
focusOnDetail: CommandData; focusOnDetail: CommandData;
focusOnSearchDefinition: Required<CommandData>;
searchNotes: CommandData & { searchNotes: CommandData & {
searchString?: string; searchString?: string;
ancestorNoteId?: string | null; ancestorNoteId?: string | null;
@@ -90,11 +93,6 @@ export type CommandMappings = {
closeTocCommand: CommandData; closeTocCommand: CommandData;
closeHlt: CommandData; closeHlt: CommandData;
showLaunchBarSubtree: CommandData; showLaunchBarSubtree: CommandData;
showHiddenSubtree: CommandData;
showSQLConsoleHistory: CommandData;
logout: CommandData;
switchToMobileVersion: CommandData;
switchToDesktopVersion: CommandData;
showRevisions: CommandData & { showRevisions: CommandData & {
noteId?: string | null; noteId?: string | null;
}; };
@@ -116,7 +114,7 @@ export type CommandMappings = {
openedFileUpdated: CommandData & { openedFileUpdated: CommandData & {
entityType: string; entityType: string;
entityId: string; entityId: string;
lastModifiedMs?: number; lastModifiedMs: number;
filePath: string; filePath: string;
}; };
focusAndSelectTitle: CommandData & { focusAndSelectTitle: CommandData & {
@@ -140,7 +138,6 @@ export type CommandMappings = {
showLeftPane: CommandData; showLeftPane: CommandData;
showAttachments: CommandData; showAttachments: CommandData;
showSearchHistory: CommandData; showSearchHistory: CommandData;
showShareSubtree: CommandData;
hoistNote: CommandData & { noteId: string }; hoistNote: CommandData & { noteId: string };
leaveProtectedSession: CommandData; leaveProtectedSession: CommandData;
enterProtectedSession: CommandData; enterProtectedSession: CommandData;
@@ -326,7 +323,6 @@ export type CommandMappings = {
printActiveNote: CommandData; printActiveNote: CommandData;
exportAsPdf: CommandData; exportAsPdf: CommandData;
openNoteExternally: CommandData; openNoteExternally: CommandData;
openNoteCustom: CommandData;
renderActiveNote: CommandData; renderActiveNote: CommandData;
unhoist: CommandData; unhoist: CommandData;
reloadFrontendApp: CommandData; reloadFrontendApp: CommandData;
@@ -530,7 +526,7 @@ export type FilteredCommandNames<T extends CommandData> = keyof Pick<CommandMapp
export class AppContext extends Component { export class AppContext extends Component {
isMainWindow: boolean; isMainWindow: boolean;
components: Component[]; components: Component[];
beforeUnloadListeners: (WeakRef<BeforeUploadListener> | (() => boolean))[]; beforeUnloadListeners: WeakRef<BeforeUploadListener>[];
tabManager!: TabManager; tabManager!: TabManager;
layout?: Layout; layout?: Layout;
noteTreeWidget?: NoteTreeWidget; noteTreeWidget?: NoteTreeWidget;
@@ -623,7 +619,7 @@ export class AppContext extends Component {
component.triggerCommand(commandName, { $el: $(this) }); component.triggerCommand(commandName, { $el: $(this) });
}); });
this.child(rootWidget as Component); this.child(rootWidget);
this.triggerEvent("initialRenderComplete", {}); this.triggerEvent("initialRenderComplete", {});
} }
@@ -650,20 +646,16 @@ export class AppContext extends Component {
} }
getComponentByEl(el: HTMLElement) { getComponentByEl(el: HTMLElement) {
return $(el).closest("[data-component-id]").prop("component"); return $(el).closest(".component").prop("component");
} }
addBeforeUnloadListener(obj: BeforeUploadListener | (() => boolean)) { addBeforeUnloadListener(obj: BeforeUploadListener) {
if (typeof WeakRef !== "function") { if (typeof WeakRef !== "function") {
// older browsers don't support WeakRef // older browsers don't support WeakRef
return; return;
} }
if (typeof obj === "object") { this.beforeUnloadListeners.push(new WeakRef<BeforeUploadListener>(obj));
this.beforeUnloadListeners.push(new WeakRef<BeforeUploadListener>(obj));
} else {
this.beforeUnloadListeners.push(obj);
}
} }
} }
@@ -673,29 +665,25 @@ const appContext = new AppContext(window.glob.isMainWindow);
$(window).on("beforeunload", () => { $(window).on("beforeunload", () => {
let allSaved = true; let allSaved = true;
appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter((wr) => typeof wr === "function" || !!wr.deref()); appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter((wr) => !!wr.deref());
for (const listener of appContext.beforeUnloadListeners) { for (const weakRef of appContext.beforeUnloadListeners) {
if (typeof listener === "object") { const component = weakRef.deref();
const component = listener.deref();
if (!component) { if (!component) {
continue; continue;
} }
if (!component.beforeUnloadEvent()) { if (!component.beforeUnloadEvent()) {
console.log(`Component ${component.componentId} is not finished saving its state.`); console.log(`Component ${component.componentId} is not finished saving its state.`);
allSaved = false;
} toast.showMessage(t("app_context.please_wait_for_save"), 10000);
} else {
if (!listener()) { allSaved = false;
allSaved = false;
}
} }
} }
if (!allSaved) { if (!allSaved) {
toast.showMessage(t("app_context.please_wait_for_save"), 10000);
return "some string"; return "some string";
} }
}); });

View File

@@ -1,8 +1,6 @@
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import type { CommandMappings, CommandNames, EventData, EventNames } from "./app_context.js"; import type { CommandMappings, CommandNames, EventData, EventNames } from "./app_context.js";
type EventHandler = ((data: any) => void);
/** /**
* Abstract class for all components in the Trilium's frontend. * Abstract class for all components in the Trilium's frontend.
* *
@@ -21,7 +19,6 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
initialized: Promise<void> | null; initialized: Promise<void> | null;
parent?: TypedComponent<any>; parent?: TypedComponent<any>;
_position!: number; _position!: number;
private listeners: Record<string, EventHandler[]> | null = {};
constructor() { constructor() {
this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`; this.componentId = `${this.sanitizedClassName}-${utils.randomString(8)}`;
@@ -79,14 +76,6 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
handleEventInChildren<T extends EventNames>(name: T, data: EventData<T>): Promise<unknown[] | unknown> | null { handleEventInChildren<T extends EventNames>(name: T, data: EventData<T>): Promise<unknown[] | unknown> | null {
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
// Handle React children.
if (this.listeners?.[name]) {
for (const listener of this.listeners[name]) {
listener(data);
}
}
// Handle legacy children.
for (const child of this.children) { for (const child of this.children) {
const ret = child.handleEvent(name, data) as Promise<void>; const ret = child.handleEvent(name, data) as Promise<void>;
@@ -131,35 +120,6 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
return promise; return promise;
} }
registerHandler<T extends EventNames>(name: T, handler: EventHandler) {
if (!this.listeners) {
this.listeners = {};
}
if (!this.listeners[name]) {
this.listeners[name] = [];
}
if (this.listeners[name].includes(handler)) {
return;
}
this.listeners[name].push(handler);
}
removeHandler<T extends EventNames>(name: T, handler: EventHandler) {
if (!this.listeners?.[name]?.includes(handler)) {
return;
}
this.listeners[name] = this.listeners[name]
.filter(listener => listener !== handler);
if (!this.listeners[name].length) {
delete this.listeners[name];
}
}
} }
export default class Component extends TypedComponent<Component> {} export default class Component extends TypedComponent<Component> {}

View File

@@ -10,7 +10,22 @@ import bundleService from "../services/bundle.js";
import froca from "../services/froca.js"; import froca from "../services/froca.js";
import linkService from "../services/link.js"; import linkService from "../services/link.js";
import { t } from "../services/i18n.js"; import { t } from "../services/i18n.js";
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons"; import type FNote from "../entities/fnote.js";
// TODO: Move somewhere else nicer.
export type SqlExecuteResults = string[][][];
// TODO: Deduplicate with server.
interface SqlExecuteResponse {
success: boolean;
error?: string;
results: SqlExecuteResults;
}
// TODO: Deduplicate with server.
interface CreateChildrenResponse {
note: FNote;
}
export default class Entrypoints extends Component { export default class Entrypoints extends Component {
constructor() { constructor() {
@@ -19,7 +34,7 @@ export default class Entrypoints extends Component {
openDevToolsCommand() { openDevToolsCommand() {
if (utils.isElectron()) { if (utils.isElectron()) {
utils.dynamicRequire("@electron/remote").getCurrentWindow().webContents.toggleDevTools(); utils.dynamicRequire("@electron/remote").getCurrentWindow().toggleDevTools();
} }
} }
@@ -109,7 +124,7 @@ export default class Entrypoints extends Component {
if (utils.isElectron()) { if (utils.isElectron()) {
// standard JS version does not work completely correctly in electron // standard JS version does not work completely correctly in electron
const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents(); const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents();
const activeIndex = webContents.navigationHistory.getActiveIndex(); const activeIndex = parseInt(webContents.navigationHistory.getActiveIndex());
webContents.goToIndex(activeIndex - 1); webContents.goToIndex(activeIndex - 1);
} else { } else {
@@ -121,7 +136,7 @@ export default class Entrypoints extends Component {
if (utils.isElectron()) { if (utils.isElectron()) {
// standard JS version does not work completely correctly in electron // standard JS version does not work completely correctly in electron
const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents(); const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents();
const activeIndex = webContents.navigationHistory.getActiveIndex(); const activeIndex = parseInt(webContents.navigationHistory.getActiveIndex());
webContents.goToIndex(activeIndex + 1); webContents.goToIndex(activeIndex + 1);
} else { } else {

View File

@@ -43,6 +43,8 @@ export default class RootCommandExecutor extends Component {
const noteContext = await appContext.tabManager.openTabWithNoteWithHoisting(searchNote.noteId, { const noteContext = await appContext.tabManager.openTabWithNoteWithHoisting(searchNote.noteId, {
activate: true activate: true
}); });
appContext.triggerCommand("focusOnSearchDefinition", { ntxId: noteContext.ntxId });
} }
async searchInSubtreeCommand({ notePath }: CommandListenerData<"searchInSubtree">) { async searchInSubtreeCommand({ notePath }: CommandListenerData<"searchInSubtree">) {

View File

@@ -433,9 +433,6 @@ export default class TabManager extends Component {
$autocompleteEl.autocomplete("close"); $autocompleteEl.autocomplete("close");
} }
// close dangling tooltips
$("body > div.tooltip").remove();
const noteContextsToRemove = noteContextToRemove.getSubContexts(); const noteContextsToRemove = noteContextToRemove.getSubContexts();
const ntxIdsToRemove = noteContextsToRemove.map((nc) => nc.ntxId); const ntxIdsToRemove = noteContextsToRemove.map((nc) => nc.ntxId);
@@ -603,18 +600,18 @@ export default class TabManager extends Component {
} }
async moveTabToNewWindowCommand({ ntxId }: { ntxId: string }) { async moveTabToNewWindowCommand({ ntxId }: { ntxId: string }) {
const { notePath, hoistedNoteId, viewScope } = this.getNoteContextById(ntxId); const { notePath, hoistedNoteId } = this.getNoteContextById(ntxId);
const removed = await this.removeNoteContext(ntxId); const removed = await this.removeNoteContext(ntxId);
if (removed) { if (removed) {
this.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope }); this.triggerCommand("openInWindow", { notePath, hoistedNoteId });
} }
} }
async copyTabToNewWindowCommand({ ntxId }: { ntxId: string }) { async copyTabToNewWindowCommand({ ntxId }: { ntxId: string }) {
const { notePath, hoistedNoteId, viewScope } = this.getNoteContextById(ntxId); const { notePath, hoistedNoteId } = this.getNoteContextById(ntxId);
this.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope }); this.triggerCommand("openInWindow", { notePath, hoistedNoteId });
} }
async reopenLastTabCommand() { async reopenLastTabCommand() {

View File

@@ -23,11 +23,11 @@ export default class TouchBarComponent extends Component {
this.$widget = $("<div>"); this.$widget = $("<div>");
$(window).on("focusin", async (e) => { $(window).on("focusin", async (e) => {
const focusedEl = e.target as unknown as HTMLElement; const $target = $(e.target);
const $target = $(focusedEl);
this.$activeModal = $target.closest(".modal-dialog"); this.$activeModal = $target.closest(".modal-dialog");
this.lastFocusedComponent = appContext.getComponentByEl(focusedEl); const parentComponentEl = $target.closest(".component");
this.lastFocusedComponent = appContext.getComponentByEl(parentComponentEl[0]);
this.#refreshTouchBar(); this.#refreshTouchBar();
}); });
} }

View File

@@ -8,9 +8,10 @@ import electronContextMenu from "./menus/electron_context_menu.js";
import glob from "./services/glob.js"; import glob from "./services/glob.js";
import { t } from "./services/i18n.js"; import { t } from "./services/i18n.js";
import options from "./services/options.js"; import options from "./services/options.js";
import server from "./services/server.js";
import type ElectronRemote from "@electron/remote"; import type ElectronRemote from "@electron/remote";
import type Electron from "electron"; import type Electron from "electron";
import "bootstrap/dist/css/bootstrap.min.css"; import "./stylesheets/bootstrap.scss";
import "boxicons/css/boxicons.min.css"; import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js"; import "autocomplete.js/index_jquery.js";
@@ -45,10 +46,6 @@ if (utils.isElectron()) {
electronContextMenu.setupContextMenu(); electronContextMenu.setupContextMenu();
} }
if (utils.isPWA()) {
initPWATopbarColor();
}
function initOnElectron() { function initOnElectron() {
const electron: typeof Electron = utils.dynamicRequire("electron"); const electron: typeof Electron = utils.dynamicRequire("electron");
electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName)); electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName));
@@ -117,20 +114,3 @@ function initDarkOrLightMode(style: CSSStyleDeclaration) {
const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote; const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote;
nativeTheme.themeSource = themeSource; nativeTheme.themeSource = themeSource;
} }
function initPWATopbarColor() {
const tracker = $("#background-color-tracker");
if (tracker.length) {
const applyThemeColor = () => {
let meta = $("meta[name='theme-color']");
if (!meta.length) {
meta = $(`<meta name="theme-color">`).appendTo($("head"));
}
meta.attr("content", tracker.css("color"));
};
tracker.on("transitionend", applyThemeColor);
applyThemeColor();
}
}

View File

@@ -64,7 +64,7 @@ export interface NoteMetaData {
/** /**
* Note is the main node and concept in Trilium. * Note is the main node and concept in Trilium.
*/ */
export default class FNote { class FNote {
private froca: Froca; private froca: Froca;
noteId!: string; noteId!: string;
@@ -256,20 +256,18 @@ export default class FNote {
return this.children; return this.children;
} }
async getSubtreeNoteIds(includeArchived = false) { async getSubtreeNoteIds() {
let noteIds: (string | string[])[] = []; let noteIds: (string | string[])[] = [];
for (const child of await this.getChildNotes()) { for (const child of await this.getChildNotes()) {
if (child.isArchived && !includeArchived) continue;
noteIds.push(child.noteId); noteIds.push(child.noteId);
noteIds.push(await child.getSubtreeNoteIds(includeArchived)); noteIds.push(await child.getSubtreeNoteIds());
} }
return noteIds.flat(); return noteIds.flat();
} }
async getSubtreeNotes() { async getSubtreeNotes() {
const noteIds = await this.getSubtreeNoteIds(); const noteIds = await this.getSubtreeNoteIds();
return (await this.froca.getNotes(noteIds)); return this.froca.getNotes(noteIds);
} }
async getChildNotes() { async getChildNotes() {
@@ -836,7 +834,7 @@ export default class FNote {
if (a.noteId === b.noteId) { if (a.noteId === b.noteId) {
return a.position < b.position ? -1 : 1; return a.position < b.position ? -1 : 1;
} else { } else {
// inherited promoted attributes should stay grouped: https://github.com/zadam/trilium/issues/3761 // inherited promoted attributes should stay grouped: https://github.com/TriliumNext/Trilium/issues/3761
return a.noteId < b.noteId ? -1 : 1; return a.noteId < b.noteId ? -1 : 1;
} }
}); });
@@ -907,8 +905,8 @@ export default class FNote {
return this.getBlob(); return this.getBlob();
} }
getBlob() { async getBlob() {
return this.froca.getBlob("notes", this.noteId); return await this.froca.getBlob("notes", this.noteId);
} }
toString() { toString() {
@@ -1022,14 +1020,6 @@ export default class FNote {
return this.noteId.startsWith("_options"); return this.noteId.startsWith("_options");
} }
isTriliumSqlite() {
return this.mime === "text/x-sqlite;schema=trilium";
}
isTriliumScript() {
return this.mime.startsWith("application/javascript");
}
/** /**
* Provides note's date metadata. * Provides note's date metadata.
*/ */
@@ -1037,3 +1027,5 @@ export default class FNote {
return await server.get<NoteMetaData>(`notes/${this.noteId}/metadata`); return await server.get<NoteMetaData>(`notes/${this.noteId}/metadata`);
} }
} }
export default FNote;

View File

@@ -1,47 +1,78 @@
import FlexContainer from "../widgets/containers/flex_container.js"; import FlexContainer from "../widgets/containers/flex_container.js";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import TabRowWidget from "../widgets/tab_row.js"; import TabRowWidget from "../widgets/tab_row.js";
import TitleBarButtonsWidget from "../widgets/title_bar_buttons.js";
import LeftPaneContainer from "../widgets/containers/left_pane_container.js"; import LeftPaneContainer from "../widgets/containers/left_pane_container.js";
import NoteTreeWidget from "../widgets/note_tree.js"; import NoteTreeWidget from "../widgets/note_tree.js";
import NoteTitleWidget from "../widgets/note_title.jsx"; import NoteTitleWidget from "../widgets/note_title.js";
import OwnedAttributeListWidget from "../widgets/ribbon_widgets/owned_attribute_list.js";
import NoteActionsWidget from "../widgets/buttons/note_actions.js";
import NoteDetailWidget from "../widgets/note_detail.js"; import NoteDetailWidget from "../widgets/note_detail.js";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; import RibbonContainer from "../widgets/containers/ribbon_container.js";
import NoteIconWidget from "../widgets/note_icon.jsx"; import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
import InheritedAttributesWidget from "../widgets/ribbon_widgets/inherited_attribute_list.js";
import NoteListWidget from "../widgets/note_list.js";
import SearchDefinitionWidget from "../widgets/ribbon_widgets/search_definition.js";
import SqlResultWidget from "../widgets/sql_result.js";
import SqlTableSchemasWidget from "../widgets/sql_table_schemas.js";
import FilePropertiesWidget from "../widgets/ribbon_widgets/file_properties.js";
import ImagePropertiesWidget from "../widgets/ribbon_widgets/image_properties.js";
import NotePropertiesWidget from "../widgets/ribbon_widgets/note_properties.js";
import NoteIconWidget from "../widgets/note_icon.js";
import SearchResultWidget from "../widgets/search_result.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js"; import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import RootContainer from "../widgets/containers/root_container.js"; import RootContainer from "../widgets/containers/root_container.js";
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js"; import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
import SpacerWidget from "../widgets/spacer.js"; import SpacerWidget from "../widgets/spacer.js";
import QuickSearchWidget from "../widgets/quick_search.js"; import QuickSearchWidget from "../widgets/quick_search.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js"; import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import LeftPaneToggleWidget from "../widgets/buttons/left_pane_toggle.js";
import CreatePaneButton from "../widgets/buttons/create_pane_button.js"; import CreatePaneButton from "../widgets/buttons/create_pane_button.js";
import ClosePaneButton from "../widgets/buttons/close_pane_button.js"; import ClosePaneButton from "../widgets/buttons/close_pane_button.js";
import BasicPropertiesWidget from "../widgets/ribbon_widgets/basic_properties.js";
import NoteInfoWidget from "../widgets/ribbon_widgets/note_info_widget.js";
import BookPropertiesWidget from "../widgets/ribbon_widgets/book_properties.js";
import NoteMapRibbonWidget from "../widgets/ribbon_widgets/note_map.js";
import NotePathsWidget from "../widgets/ribbon_widgets/note_paths.js";
import SimilarNotesWidget from "../widgets/ribbon_widgets/similar_notes.js";
import RightPaneContainer from "../widgets/containers/right_pane_container.js"; import RightPaneContainer from "../widgets/containers/right_pane_container.js";
import EditButton from "../widgets/floating_buttons/edit_button.js";
import EditedNotesWidget from "../widgets/ribbon_widgets/edited_notes.js";
import ShowTocWidgetButton from "../widgets/buttons/show_toc_widget_button.js";
import ShowHighlightsListWidgetButton from "../widgets/buttons/show_highlights_list_widget_button.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js"; import NoteWrapperWidget from "../widgets/note_wrapper.js";
import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
import SharedInfoWidget from "../widgets/shared_info.js";
import FindWidget from "../widgets/find.js"; import FindWidget from "../widgets/find.js";
import TocWidget from "../widgets/toc.js"; import TocWidget from "../widgets/toc.js";
import HighlightsListWidget from "../widgets/highlights_list.js"; import HighlightsListWidget from "../widgets/highlights_list.js";
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js"; import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
import FloatingButtons from "../widgets/floating_buttons/floating_buttons.js";
import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js";
import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js";
import LauncherContainer from "../widgets/containers/launcher_container.js"; import LauncherContainer from "../widgets/containers/launcher_container.js";
import RevisionsButton from "../widgets/buttons/revisions_button.js";
import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js";
import ApiLogWidget from "../widgets/api_log.js";
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
import ScriptExecutorWidget from "../widgets/ribbon_widgets/script_executor.js";
import MovePaneButton from "../widgets/buttons/move_pane_button.js"; import MovePaneButton from "../widgets/buttons/move_pane_button.js";
import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js"; import UploadAttachmentsDialog from "../widgets/dialogs/upload_attachments.js";
import ScrollPadding from "../widgets/scroll_padding.js"; import CopyImageReferenceButton from "../widgets/floating_buttons/copy_image_reference_button.js";
import ScrollPaddingWidget from "../widgets/scroll_padding.js";
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
import options from "../services/options.js"; import options from "../services/options.js";
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import GeoMapButtons from "../widgets/floating_buttons/geo_map_button.js";
import ContextualHelpButton from "../widgets/floating_buttons/help_button.js";
import CloseZenButton from "../widgets/close_zen_button.js";
import type { AppContext } from "../components/app_context.js"; import type { AppContext } from "../components/app_context.js";
import type { WidgetsByParent } from "../services/bundle.js"; import type { WidgetsByParent } from "../services/bundle.js";
import SwitchSplitOrientationButton from "../widgets/floating_buttons/switch_layout_button.js";
import ToggleReadOnlyButton from "../widgets/floating_buttons/toggle_read_only_button.js";
import PngExportButton from "../widgets/floating_buttons/png_export_button.js";
import RefreshButton from "../widgets/floating_buttons/refresh_button.js";
import { applyModals } from "./layout_commons.js"; import { applyModals } from "./layout_commons.js";
import Ribbon from "../widgets/ribbon/Ribbon.jsx";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { DESKTOP_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import SearchResult from "../widgets/search_result.jsx";
import GlobalMenu from "../widgets/buttons/global_menu.jsx";
import SqlResults from "../widgets/sql_result.js";
import SqlTableSchemas from "../widgets/sql_table_schemas.js";
import TitleBarButtons from "../widgets/title_bar_buttons.jsx";
import LeftPaneToggle from "../widgets/buttons/left_pane_toggle.js";
import ApiLog from "../widgets/api_log.jsx";
import CloseZenModeButton from "../widgets/close_zen_button.jsx";
import SharedInfo from "../widgets/shared_info.jsx";
import NoteList from "../widgets/collections/NoteList.jsx";
export default class DesktopLayout { export default class DesktopLayout {
@@ -76,9 +107,9 @@ export default class DesktopLayout {
new FlexContainer("row") new FlexContainer("row")
.class("tab-row-container") .class("tab-row-container")
.child(new FlexContainer("row").id("tab-row-left-spacer")) .child(new FlexContainer("row").id("tab-row-left-spacer"))
.optChild(launcherPaneIsHorizontal, <LeftPaneToggle isHorizontalLayout={true} />) .optChild(launcherPaneIsHorizontal, new LeftPaneToggleWidget(true))
.child(new TabRowWidget().class("full-width")) .child(new TabRowWidget().class("full-width"))
.optChild(customTitleBarButtons, <TitleBarButtons />) .optChild(customTitleBarButtons, new TitleBarButtonsWidget())
.css("height", "40px") .css("height", "40px")
.css("background-color", "var(--launcher-pane-background-color)") .css("background-color", "var(--launcher-pane-background-color)")
.setParent(appContext) .setParent(appContext)
@@ -99,7 +130,7 @@ export default class DesktopLayout {
new FlexContainer("column") new FlexContainer("column")
.id("rest-pane") .id("rest-pane")
.css("flex-grow", "1") .css("flex-grow", "1")
.optChild(!fullWidthTabBar, new FlexContainer("row").child(new TabRowWidget()).optChild(customTitleBarButtons, <TitleBarButtons />).css("height", "40px")) .optChild(!fullWidthTabBar, new FlexContainer("row").child(new TabRowWidget()).optChild(customTitleBarButtons, new TitleBarButtonsWidget()).css("height", "40px"))
.child( .child(
new FlexContainer("row") new FlexContainer("row")
.filling() .filling()
@@ -120,30 +151,69 @@ export default class DesktopLayout {
.css("min-height", "50px") .css("min-height", "50px")
.css("align-items", "center") .css("align-items", "center")
.cssBlock(".title-row > * { margin: 5px; }") .cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />) .child(new NoteIconWidget())
.child(<NoteTitleWidget />) .child(new NoteTitleWidget())
.child(new SpacerWidget(0, 1)) .child(new SpacerWidget(0, 1))
.child(<MovePaneButton direction="left" />) .child(new MovePaneButton(true))
.child(<MovePaneButton direction="right" />) .child(new MovePaneButton(false))
.child(<ClosePaneButton />) .child(new ClosePaneButton())
.child(<CreatePaneButton />) .child(new CreatePaneButton())
) )
.child(<Ribbon />) .child(
.child(<SharedInfo />) new RibbonContainer()
// the order of the widgets matter. Some of these want to "activate" themselves
// when visible. When this happens to multiple of them, the first one "wins".
// promoted attributes should always win.
.ribbon(new ClassicEditorToolbar())
.ribbon(new ScriptExecutorWidget())
.ribbon(new SearchDefinitionWidget())
.ribbon(new EditedNotesWidget())
.ribbon(new BookPropertiesWidget())
.ribbon(new NotePropertiesWidget())
.ribbon(new FilePropertiesWidget())
.ribbon(new ImagePropertiesWidget())
.ribbon(new BasicPropertiesWidget())
.ribbon(new OwnedAttributeListWidget())
.ribbon(new InheritedAttributesWidget())
.ribbon(new NotePathsWidget())
.ribbon(new NoteMapRibbonWidget())
.ribbon(new SimilarNotesWidget())
.ribbon(new NoteInfoWidget())
.button(new RevisionsButton())
.button(new NoteActionsWidget())
)
.child(new SharedInfoWidget())
.child(new WatchedFileUpdateStatusWidget()) .child(new WatchedFileUpdateStatusWidget())
.child(<FloatingButtons items={DESKTOP_FLOATING_BUTTONS} />) .child(
new FloatingButtons()
.child(new RefreshButton())
.child(new SwitchSplitOrientationButton())
.child(new ToggleReadOnlyButton())
.child(new EditButton())
.child(new ShowTocWidgetButton())
.child(new ShowHighlightsListWidgetButton())
.child(new CodeButtonsWidget())
.child(new RelationMapButtons())
.child(new GeoMapButtons())
.child(new CopyImageReferenceButton())
.child(new SvgExportButton())
.child(new PngExportButton())
.child(new BacklinksWidget())
.child(new ContextualHelpButton())
.child(new HideFloatingButtonsButton())
)
.child( .child(
new ScrollingContainer() new ScrollingContainer()
.filling() .filling()
.child(new PromotedAttributesWidget()) .child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />) .child(new SqlTableSchemasWidget())
.child(new NoteDetailWidget()) .child(new NoteDetailWidget())
.child(<NoteList />) .child(new NoteListWidget(false))
.child(<SearchResult />) .child(new SearchResultWidget())
.child(<SqlResults />) .child(new SqlResultWidget())
.child(<ScrollPadding />) .child(new ScrollPaddingWidget())
) )
.child(<ApiLog />) .child(new ApiLogWidget())
.child(new FindWidget()) .child(new FindWidget())
.child( .child(
...this.customWidgets.get("node-detail-pane"), // typo, let's keep it for a while as BC ...this.customWidgets.get("node-detail-pane"), // typo, let's keep it for a while as BC
@@ -162,11 +232,11 @@ export default class DesktopLayout {
) )
) )
) )
.child(<CloseZenModeButton />) .child(new CloseZenButton())
// Desktop-specific dialogs. // Desktop-specific dialogs.
.child(<PasswordNoteSetDialog />) .child(new PasswordNoteSetDialog())
.child(<UploadAttachmentsDialog />); .child(new UploadAttachmentsDialog());
applyModals(rootContainer); applyModals(rootContainer);
return rootContainer; return rootContainer;
@@ -176,18 +246,14 @@ export default class DesktopLayout {
let launcherPane; let launcherPane;
if (isHorizontal) { if (isHorizontal) {
launcherPane = new FlexContainer("row") launcherPane = new FlexContainer("row").css("height", "53px").class("horizontal").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true));
.css("height", "53px")
.class("horizontal")
.child(new LauncherContainer(true))
.child(<GlobalMenu isHorizontalLayout={true} />);
} else { } else {
launcherPane = new FlexContainer("column") launcherPane = new FlexContainer("column")
.css("width", "53px") .css("width", "53px")
.class("vertical") .class("vertical")
.child(<GlobalMenu isHorizontalLayout={false} />) .child(new GlobalMenuWidget(false))
.child(new LauncherContainer(false)) .child(new LauncherContainer(false))
.child(<LeftPaneToggle isHorizontalLayout={false} />); .child(new LeftPaneToggleWidget(false));
} }
launcherPane.id("launcher-pane"); launcherPane.id("launcher-pane");

View File

@@ -24,48 +24,48 @@ import InfoDialog from "../widgets/dialogs/info.js";
import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js"; import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js";
import PopupEditorDialog from "../widgets/dialogs/popup_editor.js"; import PopupEditorDialog from "../widgets/dialogs/popup_editor.js";
import FlexContainer from "../widgets/containers/flex_container.js"; import FlexContainer from "../widgets/containers/flex_container.js";
import NoteIconWidget from "../widgets/note_icon"; import NoteIconWidget from "../widgets/note_icon.js";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; import NoteTitleWidget from "../widgets/note_title.js";
import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolbar.js";
import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
import NoteDetailWidget from "../widgets/note_detail.js"; import NoteDetailWidget from "../widgets/note_detail.js";
import CallToActionDialog from "../widgets/dialogs/call_to_action.jsx"; import NoteListWidget from "../widgets/note_list.js";
import NoteTitleWidget from "../widgets/note_title.jsx"; import { CallToActionDialog } from "../widgets/dialogs/call_to_action.jsx";
import { PopupEditorFormattingToolbar } from "../widgets/ribbon/FormattingToolbar.js";
import NoteList from "../widgets/collections/NoteList.jsx";
export function applyModals(rootContainer: RootContainer) { export function applyModals(rootContainer: RootContainer) {
rootContainer rootContainer
.child(<BulkActionsDialog />) .child(new BulkActionsDialog())
.child(<AboutDialog />) .child(new AboutDialog())
.child(<HelpDialog />) .child(new HelpDialog())
.child(<RecentChangesDialog />) .child(new RecentChangesDialog())
.child(<BranchPrefixDialog />) .child(new BranchPrefixDialog())
.child(<SortChildNotesDialog />) .child(new SortChildNotesDialog())
.child(<IncludeNoteDialog />) .child(new IncludeNoteDialog())
.child(<NoteTypeChooserDialog />) .child(new NoteTypeChooserDialog())
.child(<JumpToNoteDialog />) .child(new JumpToNoteDialog())
.child(<AddLinkDialog />) .child(new AddLinkDialog())
.child(<CloneToDialog />) .child(new CloneToDialog())
.child(<MoveToDialog />) .child(new MoveToDialog())
.child(<ImportDialog />) .child(new ImportDialog())
.child(<ExportDialog />) .child(new ExportDialog())
.child(<MarkdownImportDialog />) .child(new MarkdownImportDialog())
.child(<ProtectedSessionPasswordDialog />) .child(new ProtectedSessionPasswordDialog())
.child(<RevisionsDialog />) .child(new RevisionsDialog())
.child(<DeleteNotesDialog />) .child(new DeleteNotesDialog())
.child(<InfoDialog />) .child(new InfoDialog())
.child(<ConfirmDialog />) .child(new ConfirmDialog())
.child(<PromptDialog />) .child(new PromptDialog())
.child(<IncorrectCpuArchDialog />) .child(new IncorrectCpuArchDialog())
.child(new PopupEditorDialog() .child(new PopupEditorDialog()
.child(new FlexContainer("row") .child(new FlexContainer("row")
.class("title-row") .class("title-row")
.css("align-items", "center") .css("align-items", "center")
.cssBlock(".title-row > * { margin: 5px; }") .cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />) .child(new NoteIconWidget())
.child(<NoteTitleWidget />)) .child(new NoteTitleWidget()))
.child(<PopupEditorFormattingToolbar />) .child(new ClassicEditorToolbar())
.child(new PromotedAttributesWidget()) .child(new PromotedAttributesWidget())
.child(new NoteDetailWidget()) .child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />)) .child(new NoteListWidget(true)))
.child(<CallToActionDialog />); .child(new CallToActionDialog());
} }

View File

@@ -3,27 +3,30 @@ import NoteTitleWidget from "../widgets/note_title.js";
import NoteDetailWidget from "../widgets/note_detail.js"; import NoteDetailWidget from "../widgets/note_detail.js";
import QuickSearchWidget from "../widgets/quick_search.js"; import QuickSearchWidget from "../widgets/quick_search.js";
import NoteTreeWidget from "../widgets/note_tree.js"; import NoteTreeWidget from "../widgets/note_tree.js";
import ToggleSidebarButtonWidget from "../widgets/mobile_widgets/toggle_sidebar_button.js";
import MobileDetailMenuWidget from "../widgets/mobile_widgets/mobile_detail_menu.js";
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js"; import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js"; import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import FilePropertiesWidget from "../widgets/ribbon_widgets/file_properties.js";
import FloatingButtons from "../widgets/floating_buttons/floating_buttons.js";
import EditButton from "../widgets/floating_buttons/edit_button.js";
import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons.js";
import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js";
import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
import NoteListWidget from "../widgets/note_list.js";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js"; import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import LauncherContainer from "../widgets/containers/launcher_container.js"; import LauncherContainer from "../widgets/containers/launcher_container.js";
import RootContainer from "../widgets/containers/root_container.js"; import RootContainer from "../widgets/containers/root_container.js";
import SharedInfoWidget from "../widgets/shared_info.js"; import SharedInfoWidget from "../widgets/shared_info.js";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js"; import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
import type AppContext from "../components/app_context.js"; import type AppContext from "../components/app_context.js";
import TabRowWidget from "../widgets/tab_row.js"; import TabRowWidget from "../widgets/tab_row.js";
import MobileEditorToolbar from "../widgets/type_widgets/ckeditor/mobile_editor_toolbar.js"; import RefreshButton from "../widgets/floating_buttons/refresh_button.js";
import MobileEditorToolbar from "../widgets/ribbon_widgets/mobile_editor_toolbar.js";
import { applyModals } from "./layout_commons.js"; import { applyModals } from "./layout_commons.js";
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx"; import CloseZenButton from "../widgets/close_zen_button.js";
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 = ` const MOBILE_CSS = `
<style> <style>
@@ -132,33 +135,38 @@ export default class MobileLayout {
.child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS))) .child(new FlexContainer("column").filling().id("mobile-sidebar-wrapper").child(new QuickSearchWidget()).child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS)))
) )
.child( .child(
new ScreenContainer("detail", "row") new ScreenContainer("detail", "column")
.id("detail-container") .id("detail-container")
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9") .class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-9")
.child( .child(
new NoteWrapperWidget() new FlexContainer("row")
.child( .contentSized()
new FlexContainer("row") .css("font-size", "larger")
.contentSized() .css("align-items", "center")
.css("font-size", "larger") .child(new ToggleSidebarButtonWidget().contentSized())
.css("align-items", "center") .child(new NoteTitleWidget().contentSized().css("position", "relative").css("padding-left", "0.5em"))
.child(<ToggleSidebarButton />) .child(new MobileDetailMenuWidget(true).contentSized())
.child(<NoteTitleWidget />)
.child(<MobileDetailMenu />)
)
.child(<SharedInfoWidget />)
.child(<FloatingButtons items={MOBILE_FLOATING_BUTTONS} />)
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)
) )
.child(new SharedInfoWidget())
.child(
new FloatingButtons()
.child(new RefreshButton())
.child(new EditButton())
.child(new RelationMapButtons())
.child(new SvgExportButton())
.child(new BacklinksWidget())
.child(new HideFloatingButtonsButton())
)
.child(new PromotedAttributesWidget())
.child(
new ScrollingContainer()
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(new NoteListWidget(false))
.child(new FilePropertiesWidget().css("font-size", "smaller"))
)
.child(new MobileEditorToolbar())
) )
) )
.child( .child(
@@ -166,25 +174,10 @@ export default class MobileLayout {
.contentSized() .contentSized()
.id("mobile-bottom-bar") .id("mobile-bottom-bar")
.child(new TabRowWidget().css("height", "40px")) .child(new TabRowWidget().css("height", "40px"))
.child(new FlexContainer("row") .child(new FlexContainer("row").class("horizontal").css("height", "53px").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true)).id("launcher-pane"))
.class("horizontal")
.css("height", "53px")
.child(new LauncherContainer(true))
.child(<GlobalMenuWidget isHorizontalLayout />)
.id("launcher-pane"))
) )
.child(<CloseZenModeButton />); .child(new CloseZenButton());
applyModals(rootContainer); applyModals(rootContainer);
return rootContainer; return rootContainer;
} }
} }
function FilePropertiesWrapper() {
const { note } = useNoteContext();
return (
<div>
{note?.type === "file" && <FilePropertiesTab note={note} />}
</div>
);
}

View File

@@ -1,4 +1,4 @@
import "bootstrap/dist/css/bootstrap.min.css"; import "./stylesheets/bootstrap.scss";
// @ts-ignore - module = undefined // @ts-ignore - module = undefined
// Required for correct loading of scripts in Electron // Required for correct loading of scripts in Electron

View File

@@ -1,8 +1,6 @@
import { KeyboardActionNames } from "@triliumnext/commons"; import keyboardActionService from "../services/keyboard_actions.js";
import keyboardActionService, { getActionSync } from "../services/keyboard_actions.js";
import note_tooltip from "../services/note_tooltip.js"; import note_tooltip from "../services/note_tooltip.js";
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import { should } from "vitest";
export interface ContextMenuOptions<T> { export interface ContextMenuOptions<T> {
x: number; x: number;
@@ -15,13 +13,8 @@ export interface ContextMenuOptions<T> {
onHide?: () => void; onHide?: () => void;
} }
export interface MenuSeparatorItem { interface MenuSeparatorItem {
kind: "separator"; title: "----";
}
export interface MenuHeader {
title: string;
kind: "header";
} }
export interface MenuItemBadge { export interface MenuItemBadge {
@@ -45,13 +38,12 @@ export interface MenuCommandItem<T> {
handler?: MenuHandler<T>; handler?: MenuHandler<T>;
items?: MenuItem<T>[] | null; items?: MenuItem<T>[] | null;
shortcut?: string; shortcut?: string;
keyboardShortcut?: KeyboardActionNames;
spellingSuggestion?: string; spellingSuggestion?: string;
checked?: boolean; checked?: boolean;
columns?: number; columns?: number;
} }
export type MenuItem<T> = MenuCommandItem<T> | MenuSeparatorItem | MenuHeader; export type MenuItem<T> = MenuCommandItem<T> | MenuSeparatorItem;
export type MenuHandler<T> = (item: MenuCommandItem<T>, e: JQuery.MouseDownEvent<HTMLElement, undefined, HTMLElement, HTMLElement>) => void; export type MenuHandler<T> = (item: MenuCommandItem<T>, e: JQuery.MouseDownEvent<HTMLElement, undefined, HTMLElement, HTMLElement>) => void;
export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEvent; export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEvent;
@@ -156,51 +148,14 @@ class ContextMenu {
.addClass("show"); .addClass("show");
} }
addItems($parent: JQuery<HTMLElement>, items: MenuItem<any>[], multicolumn = false) { addItems($parent: JQuery<HTMLElement>, items: MenuItem<any>[]) {
let $group = $parent; // The current group or parent element to which items are being appended for (const item of items) {
let shouldStartNewGroup = false; // If true, the next item will start a new group
let shouldResetGroup = false; // If true, the next item will be the last one from the group
for (let index = 0; index < items.length; index++) {
const item = items[index];
if (!item) { if (!item) {
continue; continue;
} }
// If the current item is a header, start a new group. This group will contain the if (item.title === "----") {
// header and the next item that follows the header. $parent.append($("<div>").addClass("dropdown-divider"));
if ("kind" in item && item.kind === "header") {
if (multicolumn && !shouldResetGroup) {
shouldStartNewGroup = true;
}
}
// If the next item is a separator, start a new group. This group will contain the
// current item, the separator, and the next item after the separator.
const nextItem = (index < items.length - 1) ? items[index + 1] : null;
if (multicolumn && nextItem && "kind" in nextItem && nextItem.kind === "separator") {
if (!shouldResetGroup) {
shouldStartNewGroup = true;
} else {
shouldResetGroup = true; // Continue the current group
}
}
// 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
// for columns.
if (shouldStartNewGroup) {
$group = $("<div class='dropdown-no-break'>");
$parent.append($group);
shouldStartNewGroup = false;
}
if ("kind" in item && item.kind === "separator") {
$group.append($("<div>").addClass("dropdown-divider"));
shouldResetGroup = true; // End the group after the next item
} else if ("kind" in item && item.kind === "header") {
$group.append($("<h6>").addClass("dropdown-header").text(item.title));
shouldResetGroup = true;
} else { } else {
const $icon = $("<span>"); const $icon = $("<span>");
@@ -230,23 +185,7 @@ class ContextMenu {
} }
} }
if ("keyboardShortcut" in item && item.keyboardShortcut) { if ("shortcut" in item && item.shortcut) {
const shortcuts = getActionSync(item.keyboardShortcut).effectiveShortcuts;
if (shortcuts) {
const allShortcuts: string[] = [];
for (const effectiveShortcut of shortcuts) {
allShortcuts.push(effectiveShortcut.split("+")
.map(key => `<kbd>${key}</kbd>`)
.join("+"));
}
if (allShortcuts.length) {
const container = $("<span>").addClass("keyboard-shortcut");
container.append($(allShortcuts.join(",")));
$link.append(container);
}
}
} else if ("shortcut" in item && item.shortcut) {
$link.append($("<kbd>").text(item.shortcut)); $link.append($("<kbd>").text(item.shortcut));
} }
@@ -302,24 +241,16 @@ class ContextMenu {
$link.addClass("dropdown-toggle"); $link.addClass("dropdown-toggle");
const $subMenu = $("<ul>").addClass("dropdown-menu"); const $subMenu = $("<ul>").addClass("dropdown-menu");
const hasColumns = !!item.columns && item.columns > 1; if (!this.isMobile && item.columns) {
if (!this.isMobile && hasColumns) { $subMenu.css("column-count", item.columns);
$subMenu.css("column-count", item.columns!);
} }
this.addItems($subMenu, item.items, hasColumns); this.addItems($subMenu, item.items);
$item.append($subMenu); $item.append($subMenu);
} }
$group.append($item); $parent.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) {
$group = $parent;
shouldResetGroup = false;
};
} }
} }
} }

View File

@@ -37,7 +37,7 @@ function setupContextMenu() {
handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord) handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
}); });
items.push({ kind: "separator" }); items.push({ title: `----` });
} }
if (params.isEditable) { if (params.isEditable) {
@@ -112,7 +112,7 @@ function setupContextMenu() {
// Replace the placeholder with the real search keyword. // Replace the placeholder with the real search keyword.
let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText)); let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText));
items.push({ kind: "separator" }); items.push({ title: "----" });
items.push({ items.push({
title: t("electron_context_menu.search_online", { term: shortenedSelection, searchEngine: searchEngineName }), title: t("electron_context_menu.search_online", { term: shortenedSelection, searchEngine: searchEngineName }),

View File

@@ -45,16 +45,16 @@ export default class LauncherContextMenu implements SelectMenuItemEventListener<
isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-script-launcher"), command: "addScriptLauncher", uiIcon: "bx bx-code-curly" } : null, isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-script-launcher"), command: "addScriptLauncher", uiIcon: "bx bx-code-curly" } : null,
isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-custom-widget"), command: "addWidgetLauncher", uiIcon: "bx bx-customize" } : null, isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-custom-widget"), command: "addWidgetLauncher", uiIcon: "bx bx-customize" } : null,
isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-spacer"), command: "addSpacerLauncher", uiIcon: "bx bx-dots-horizontal" } : null, isVisibleRoot || isAvailableRoot ? { title: t("launcher_context_menu.add-spacer"), command: "addSpacerLauncher", uiIcon: "bx bx-dots-horizontal" } : null,
isVisibleRoot || isAvailableRoot ? { kind: "separator" } : null, isVisibleRoot || isAvailableRoot ? { title: "----" } : null,
isAvailableItem ? { title: t("launcher_context_menu.move-to-visible-launchers"), command: "moveLauncherToVisible", uiIcon: "bx bx-show", enabled: true } : null, isAvailableItem ? { title: t("launcher_context_menu.move-to-visible-launchers"), command: "moveLauncherToVisible", uiIcon: "bx bx-show", enabled: true } : null,
isVisibleItem ? { title: t("launcher_context_menu.move-to-available-launchers"), command: "moveLauncherToAvailable", uiIcon: "bx bx-hide", enabled: true } : null, isVisibleItem ? { title: t("launcher_context_menu.move-to-available-launchers"), command: "moveLauncherToAvailable", uiIcon: "bx bx-hide", enabled: true } : null,
isVisibleItem || isAvailableItem ? { kind: "separator" } : null, isVisibleItem || isAvailableItem ? { title: "----" } : null,
{ title: `${t("launcher_context_menu.duplicate-launcher")}`, command: "duplicateSubtree", uiIcon: "bx bx-outline", enabled: isItem }, { title: `${t("launcher_context_menu.duplicate-launcher")}`, command: "duplicateSubtree", uiIcon: "bx bx-outline", enabled: isItem },
{ title: `${t("launcher_context_menu.delete")}`, command: "deleteNotes", uiIcon: "bx bx-trash destructive-action-icon", enabled: canBeDeleted }, { title: `${t("launcher_context_menu.delete")}`, command: "deleteNotes", uiIcon: "bx bx-trash destructive-action-icon", enabled: canBeDeleted },
{ kind: "separator" }, { title: "----" },
{ title: t("launcher_context_menu.reset"), command: "resetLauncher", uiIcon: "bx bx-reset destructive-action-icon", enabled: canBeReset } { title: t("launcher_context_menu.reset"), command: "resetLauncher", uiIcon: "bx bx-reset destructive-action-icon", enabled: canBeReset }
]; ];

View File

@@ -13,8 +13,6 @@ import type NoteTreeWidget from "../widgets/note_tree.js";
import type FAttachment from "../entities/fattachment.js"; import type FAttachment from "../entities/fattachment.js";
import type { SelectMenuItemEventListener } from "../components/events.js"; import type { SelectMenuItemEventListener } from "../components/events.js";
import utils from "../services/utils.js"; import utils from "../services/utils.js";
import attributes from "../services/attributes.js";
import { executeBulkActions } from "../services/bulk_action.js";
// TODO: Deduplicate once client/server is well split. // TODO: Deduplicate once client/server is well split.
interface ConvertToAttachmentResponse { interface ConvertToAttachmentResponse {
@@ -63,11 +61,6 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
// the only exception is when the only selected note is the one that was right-clicked, then // the only exception is when the only selected note is the one that was right-clicked, then
// it's clear what the user meant to do. // it's clear what the user meant to do.
const selNodes = this.treeWidget.getSelectedNodes(); const selNodes = this.treeWidget.getSelectedNodes();
const selectedNotes = await froca.getNotes(selNodes.map(node => node.data.noteId));
if (note && !selectedNotes.includes(note)) selectedNotes.push(note);
const isArchived = selectedNotes.every(note => note.isArchived);
const canToggleArchived = !selectedNotes.some(note => note.isArchived !== isArchived);
const noSelectedNotes = selNodes.length === 0 || (selNodes.length === 1 && selNodes[0] === this.node); const noSelectedNotes = selNodes.length === 0 || (selNodes.length === 1 && selNodes[0] === this.node);
const notSearch = note?.type !== "search"; const notSearch = note?.type !== "search";
@@ -76,29 +69,27 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNotSearch; const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNotSearch;
const items: (MenuItem<TreeCommandNames> | null)[] = [ const items: (MenuItem<TreeCommandNames> | null)[] = [
{ title: t("tree-context-menu.open-in-a-new-tab"), command: "openInTab", shortcut: "Ctrl+Click", uiIcon: "bx bx-link-external", enabled: noSelectedNotes }, { title: `${t("tree-context-menu.open-in-a-new-tab")}`, command: "openInTab", uiIcon: "bx bx-link-external", enabled: noSelectedNotes },
{ title: t("tree-context-menu.open-in-a-new-split"), command: "openNoteInSplit", uiIcon: "bx bx-dock-right", enabled: noSelectedNotes }, { title: t("tree-context-menu.open-in-a-new-split"), command: "openNoteInSplit", uiIcon: "bx bx-dock-right", enabled: noSelectedNotes },
{ title: t("tree-context-menu.open-in-popup"), command: "openNoteInPopup", uiIcon: "bx bx-edit", enabled: noSelectedNotes }, { title: t("tree-context-menu.open-in-popup"), command: "openNoteInPopup", uiIcon: "bx bx-edit", enabled: noSelectedNotes },
isHoisted isHoisted
? null ? null
: { : {
title: `${t("tree-context-menu.hoist-note")}`, title: `${t("tree-context-menu.hoist-note")} <kbd data-command="toggleNoteHoisting"></kbd>`,
command: "toggleNoteHoisting", command: "toggleNoteHoisting",
keyboardShortcut: "toggleNoteHoisting",
uiIcon: "bx bxs-chevrons-up", uiIcon: "bx bxs-chevrons-up",
enabled: noSelectedNotes && notSearch enabled: noSelectedNotes && notSearch
}, },
!isHoisted || !isNotRoot !isHoisted || !isNotRoot
? null ? null
: { title: t("tree-context-menu.unhoist-note"), command: "toggleNoteHoisting", keyboardShortcut: "toggleNoteHoisting", uiIcon: "bx bx-door-open" }, : { title: `${t("tree-context-menu.unhoist-note")} <kbd data-command="toggleNoteHoisting"></kbd>`, command: "toggleNoteHoisting", uiIcon: "bx bx-door-open" },
{ kind: "separator" }, { title: "----" },
{ {
title: t("tree-context-menu.insert-note-after"), title: `${t("tree-context-menu.insert-note-after")}<kbd data-command="createNoteAfter"></kbd>`,
command: "insertNoteAfter", command: "insertNoteAfter",
keyboardShortcut: "createNoteAfter",
uiIcon: "bx bx-plus", uiIcon: "bx bx-plus",
items: insertNoteAfterEnabled ? await noteTypesService.getNoteTypeItems("insertNoteAfter") : null, items: insertNoteAfterEnabled ? await noteTypesService.getNoteTypeItems("insertNoteAfter") : null,
enabled: insertNoteAfterEnabled && noSelectedNotes && notOptionsOrHelp, enabled: insertNoteAfterEnabled && noSelectedNotes && notOptionsOrHelp,
@@ -106,22 +97,21 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
}, },
{ {
title: t("tree-context-menu.insert-child-note"), title: `${t("tree-context-menu.insert-child-note")}<kbd data-command="createNoteInto"></kbd>`,
command: "insertChildNote", command: "insertChildNote",
keyboardShortcut: "createNoteInto",
uiIcon: "bx bx-plus", uiIcon: "bx bx-plus",
items: notSearch ? await noteTypesService.getNoteTypeItems("insertChildNote") : null, items: notSearch ? await noteTypesService.getNoteTypeItems("insertChildNote") : null,
enabled: notSearch && noSelectedNotes && notOptionsOrHelp, enabled: notSearch && noSelectedNotes && notOptionsOrHelp,
columns: 2 columns: 2
}, },
{ kind: "separator" }, { title: "----" },
{ title: t("tree-context-menu.protect-subtree"), command: "protectSubtree", uiIcon: "bx bx-check-shield", enabled: noSelectedNotes }, { title: t("tree-context-menu.protect-subtree"), command: "protectSubtree", uiIcon: "bx bx-check-shield", enabled: noSelectedNotes },
{ title: t("tree-context-menu.unprotect-subtree"), command: "unprotectSubtree", uiIcon: "bx bx-shield", enabled: noSelectedNotes }, { title: t("tree-context-menu.unprotect-subtree"), command: "unprotectSubtree", uiIcon: "bx bx-shield", enabled: noSelectedNotes },
{ kind: "separator" }, { title: "----" },
{ {
title: t("tree-context-menu.advanced"), title: t("tree-context-menu.advanced"),
@@ -130,52 +120,48 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
items: [ items: [
{ title: t("tree-context-menu.apply-bulk-actions"), command: "openBulkActionsDialog", uiIcon: "bx bx-list-plus", enabled: true }, { title: t("tree-context-menu.apply-bulk-actions"), command: "openBulkActionsDialog", uiIcon: "bx bx-list-plus", enabled: true },
{ kind: "separator" }, { title: "----" },
{ {
title: t("tree-context-menu.edit-branch-prefix"), title: `${t("tree-context-menu.edit-branch-prefix")} <kbd data-command="editBranchPrefix"></kbd>`,
command: "editBranchPrefix", command: "editBranchPrefix",
keyboardShortcut: "editBranchPrefix",
uiIcon: "bx bx-rename", uiIcon: "bx bx-rename",
enabled: isNotRoot && parentNotSearch && noSelectedNotes && notOptionsOrHelp enabled: isNotRoot && parentNotSearch && noSelectedNotes && notOptionsOrHelp
}, },
{ title: t("tree-context-menu.convert-to-attachment"), command: "convertNoteToAttachment", uiIcon: "bx bx-paperclip", enabled: isNotRoot && !isHoisted && notOptionsOrHelp }, { title: t("tree-context-menu.convert-to-attachment"), command: "convertNoteToAttachment", uiIcon: "bx bx-paperclip", enabled: isNotRoot && !isHoisted && notOptionsOrHelp },
{ kind: "separator" }, { title: "----" },
{ title: t("tree-context-menu.expand-subtree"), command: "expandSubtree", keyboardShortcut: "expandSubtree", uiIcon: "bx bx-expand", enabled: noSelectedNotes }, { title: `${t("tree-context-menu.expand-subtree")} <kbd data-command="expandSubtree"></kbd>`, command: "expandSubtree", uiIcon: "bx bx-expand", enabled: noSelectedNotes },
{ title: t("tree-context-menu.collapse-subtree"), command: "collapseSubtree", keyboardShortcut: "collapseSubtree", uiIcon: "bx bx-collapse", enabled: noSelectedNotes }, { title: `${t("tree-context-menu.collapse-subtree")} <kbd data-command="collapseSubtree"></kbd>`, command: "collapseSubtree", uiIcon: "bx bx-collapse", enabled: noSelectedNotes },
{ {
title: t("tree-context-menu.sort-by"), title: `${t("tree-context-menu.sort-by")} <kbd data-command="sortChildNotes"></kbd>`,
command: "sortChildNotes", command: "sortChildNotes",
keyboardShortcut: "sortChildNotes",
uiIcon: "bx bx-sort-down", uiIcon: "bx bx-sort-down",
enabled: noSelectedNotes && notSearch enabled: noSelectedNotes && notSearch
}, },
{ kind: "separator" }, { title: "----" },
{ title: t("tree-context-menu.copy-note-path-to-clipboard"), command: "copyNotePathToClipboard", uiIcon: "bx bx-directions", enabled: true }, { title: t("tree-context-menu.copy-note-path-to-clipboard"), command: "copyNotePathToClipboard", uiIcon: "bx bx-directions", enabled: true },
{ title: t("tree-context-menu.recent-changes-in-subtree"), command: "recentChangesInSubtree", uiIcon: "bx bx-history", enabled: noSelectedNotes && notOptionsOrHelp } { title: t("tree-context-menu.recent-changes-in-subtree"), command: "recentChangesInSubtree", uiIcon: "bx bx-history", enabled: noSelectedNotes && notOptionsOrHelp }
] ]
}, },
{ kind: "separator" }, { title: "----" },
{ {
title: t("tree-context-menu.cut"), title: `${t("tree-context-menu.cut")} <kbd data-command="cutNotesToClipboard"></kbd>`,
command: "cutNotesToClipboard", command: "cutNotesToClipboard",
keyboardShortcut: "cutNotesToClipboard",
uiIcon: "bx bx-cut", uiIcon: "bx bx-cut",
enabled: isNotRoot && !isHoisted && parentNotSearch enabled: isNotRoot && !isHoisted && parentNotSearch
}, },
{ title: t("tree-context-menu.copy-clone"), command: "copyNotesToClipboard", keyboardShortcut: "copyNotesToClipboard", uiIcon: "bx bx-copy", enabled: isNotRoot && !isHoisted }, { title: `${t("tree-context-menu.copy-clone")} <kbd data-command="copyNotesToClipboard"></kbd>`, command: "copyNotesToClipboard", uiIcon: "bx bx-copy", enabled: isNotRoot && !isHoisted },
{ {
title: t("tree-context-menu.paste-into"), title: `${t("tree-context-menu.paste-into")} <kbd data-command="pasteNotesFromClipboard"></kbd>`,
command: "pasteNotesFromClipboard", command: "pasteNotesFromClipboard",
keyboardShortcut: "pasteNotesFromClipboard",
uiIcon: "bx bx-paste", uiIcon: "bx bx-paste",
enabled: !clipboard.isClipboardEmpty() && notSearch && noSelectedNotes enabled: !clipboard.isClipboardEmpty() && notSearch && noSelectedNotes
}, },
@@ -188,71 +174,39 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
}, },
{ {
title: t("tree-context-menu.move-to"), title: `${t("tree-context-menu.move-to")} <kbd data-command="moveNotesTo"></kbd>`,
command: "moveNotesTo", command: "moveNotesTo",
keyboardShortcut: "moveNotesTo",
uiIcon: "bx bx-transfer", uiIcon: "bx bx-transfer",
enabled: isNotRoot && !isHoisted && parentNotSearch enabled: isNotRoot && !isHoisted && parentNotSearch
}, },
{ title: t("tree-context-menu.clone-to"), command: "cloneNotesTo", keyboardShortcut: "cloneNotesTo", uiIcon: "bx bx-duplicate", enabled: isNotRoot && !isHoisted }, { title: `${t("tree-context-menu.clone-to")} <kbd data-command="cloneNotesTo"></kbd>`, command: "cloneNotesTo", uiIcon: "bx bx-duplicate", enabled: isNotRoot && !isHoisted },
{ {
title: t("tree-context-menu.duplicate"), title: `${t("tree-context-menu.duplicate")} <kbd data-command="duplicateSubtree">`,
command: "duplicateSubtree", command: "duplicateSubtree",
keyboardShortcut: "duplicateSubtree",
uiIcon: "bx bx-outline", uiIcon: "bx bx-outline",
enabled: parentNotSearch && isNotRoot && !isHoisted && notOptionsOrHelp enabled: parentNotSearch && isNotRoot && !isHoisted && notOptionsOrHelp
}, },
{ {
title: !isArchived ? t("tree-context-menu.archive") : t("tree-context-menu.unarchive"), title: `${t("tree-context-menu.delete")} <kbd data-command="deleteNotes"></kbd>`,
uiIcon: !isArchived ? "bx bx-archive" : "bx bx-archive-out",
enabled: canToggleArchived,
handler: () => {
if (!selectedNotes.length) return;
if (selectedNotes.length == 1) {
const note = selectedNotes[0];
if (!isArchived) {
attributes.addLabel(note.noteId, "archived");
} else {
attributes.removeOwnedLabelByName(note, "archived");
}
} else {
const noteIds = selectedNotes.map(note => note.noteId);
if (!isArchived) {
executeBulkActions(noteIds, [{
name: "addLabel", labelName: "archived"
}]);
} else {
executeBulkActions(noteIds, [{
name: "deleteLabel", labelName: "archived"
}]);
}
}
}
},
{
title: t("tree-context-menu.delete"),
command: "deleteNotes", command: "deleteNotes",
keyboardShortcut: "deleteNotes",
uiIcon: "bx bx-trash destructive-action-icon", uiIcon: "bx bx-trash destructive-action-icon",
enabled: isNotRoot && !isHoisted && parentNotSearch && notOptionsOrHelp enabled: isNotRoot && !isHoisted && parentNotSearch && notOptionsOrHelp
}, },
{ kind: "separator" }, { title: "----" },
{ title: t("tree-context-menu.import-into-note"), command: "importIntoNote", uiIcon: "bx bx-import", enabled: notSearch && noSelectedNotes && notOptionsOrHelp }, { title: t("tree-context-menu.import-into-note"), command: "importIntoNote", uiIcon: "bx bx-import", enabled: notSearch && noSelectedNotes && notOptionsOrHelp },
{ title: t("tree-context-menu.export"), command: "exportNote", uiIcon: "bx bx-export", enabled: notSearch && noSelectedNotes && notOptionsOrHelp }, { title: t("tree-context-menu.export"), command: "exportNote", uiIcon: "bx bx-export", enabled: notSearch && noSelectedNotes && notOptionsOrHelp },
{ kind: "separator" }, { title: "----" },
{ {
title: t("tree-context-menu.search-in-subtree"), title: `${t("tree-context-menu.search-in-subtree")} <kbd data-command="searchInSubtree"></kbd>`,
command: "searchInSubtree", command: "searchInSubtree",
keyboardShortcut: "searchInSubtree",
uiIcon: "bx bx-search", uiIcon: "bx bx-search",
enabled: notSearch && noSelectedNotes enabled: notSearch && noSelectedNotes
} }

View File

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

View File

@@ -2,7 +2,6 @@ import server from "./server.js";
import froca from "./froca.js"; import froca from "./froca.js";
import type FNote from "../entities/fnote.js"; import type FNote from "../entities/fnote.js";
import type { AttributeRow } from "./load_results.js"; import type { AttributeRow } from "./load_results.js";
import { AttributeType } from "@triliumnext/commons";
async function addLabel(noteId: string, name: string, value: string = "", isInheritable = false) { async function addLabel(noteId: string, name: string, value: string = "", isInheritable = false) {
await server.put(`notes/${noteId}/attribute`, { await server.put(`notes/${noteId}/attribute`, {
@@ -26,14 +25,6 @@ async function removeAttributeById(noteId: string, attributeId: string) {
await server.remove(`notes/${noteId}/attributes/${attributeId}`); await server.remove(`notes/${noteId}/attributes/${attributeId}`);
} }
export async function removeOwnedAttributesByNameOrType(note: FNote, type: AttributeType, name: string) {
for (const attr of note.getOwnedAttributes()) {
if (attr.type === type && attr.name === name) {
await server.remove(`notes/${note.noteId}/attributes/${attr.attributeId}`);
}
}
}
/** /**
* Removes a label identified by its name from the given note, if it exists. Note that the label must be owned, i.e. * Removes a label identified by its name from the given note, if it exists. Note that the label must be owned, i.e.
* it will not remove inherited attributes. * it will not remove inherited attributes.
@@ -61,7 +52,7 @@ function removeOwnedLabelByName(note: FNote, labelName: string) {
* @param value the value of the attribute to set. * @param value the value of the attribute to set.
*/ */
export async function setAttribute(note: FNote, type: "label" | "relation", name: string, value: string | null | undefined) { export async function setAttribute(note: FNote, type: "label" | "relation", name: string, value: string | null | undefined) {
if (value !== null && value !== undefined) { if (value) {
// Create or update the attribute. // Create or update the attribute.
await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value }); await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value });
} else { } else {

View File

@@ -210,7 +210,7 @@ function makeToast(id: string, message: string): ToastOptions {
} }
ws.subscribeToMessages(async (message) => { ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "deleteNotes") { if (message.taskType !== "deleteNotes") {
return; return;
} }
@@ -228,7 +228,7 @@ ws.subscribeToMessages(async (message) => {
}); });
ws.subscribeToMessages(async (message) => { ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "undeleteNotes") { if (message.taskType !== "undeleteNotes") {
return; return;
} }

View File

@@ -18,7 +18,7 @@ import type FNote from "../entities/fnote.js";
import toast from "./toast.js"; import toast from "./toast.js";
import { BulkAction } from "@triliumnext/commons"; import { BulkAction } from "@triliumnext/commons";
export const ACTION_GROUPS = [ const ACTION_GROUPS = [
{ {
title: t("bulk_actions.labels"), title: t("bulk_actions.labels"),
actions: [AddLabelBulkAction, UpdateLabelValueBulkAction, RenameLabelBulkAction, DeleteLabelBulkAction] actions: [AddLabelBulkAction, UpdateLabelValueBulkAction, RenameLabelBulkAction, DeleteLabelBulkAction]

View File

@@ -78,7 +78,7 @@ export class WidgetsByParent {
this.byParent[parentName] this.byParent[parentName]
// previously, custom widgets were provided as a single instance, but that has the disadvantage // previously, custom widgets were provided as a single instance, but that has the disadvantage
// for splits where we actually need multiple instaces and thus having a class to instantiate is better // for splits where we actually need multiple instaces and thus having a class to instantiate is better
// https://github.com/zadam/trilium/issues/4274 // https://github.com/TriliumNext/Trilium/issues/4274
.map((w: any) => (w.prototype ? new w() : w)) .map((w: any) => (w.prototype ? new w() : w))
); );
} }

View File

@@ -78,7 +78,7 @@ async function copy(branchIds: string[]) {
clipboardMode = "copy"; clipboardMode = "copy";
if (utils.isElectron()) { if (utils.isElectron()) {
// https://github.com/zadam/trilium/issues/2401 // https://github.com/TriliumNext/Trilium/issues/2401
const { clipboard } = require("electron"); const { clipboard } = require("electron");
const links: string[] = []; const links: string[] = [];

View File

@@ -256,19 +256,8 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
</button> </button>
`); `);
$downloadButton.on("click", (e) => { $downloadButton.on("click", () => openService.downloadFileNote(entity.noteId));
e.stopPropagation(); $openButton.on("click", () => openService.openNoteExternally(entity.noteId, entity.mime));
openService.downloadFileNote(entity.noteId)
});
$openButton.on("click", async (e) => {
const iconEl = $openButton.find("> .bx");
iconEl.removeClass("bx bx-link-external");
iconEl.addClass("bx bx-loader spin");
e.stopPropagation();
await openService.openNoteExternally(entity.noteId, entity.mime)
iconEl.removeClass("bx bx-loader spin");
iconEl.addClass("bx bx-link-external");
});
// open doesn't work for protected notes since it works through a browser which isn't in protected session // open doesn't work for protected notes since it works through a browser which isn't in protected session
$openButton.toggle(!entity.isProtected); $openButton.toggle(!entity.isProtected);

View File

@@ -60,7 +60,7 @@ async function confirmDeleteNoteBoxWithNote(title: string) {
return new Promise<ConfirmDialogResult | undefined>((res) => appContext.triggerCommand("showConfirmDeleteNoteBoxWithNoteDialog", { title, callback: res })); return new Promise<ConfirmDialogResult | undefined>((res) => appContext.triggerCommand("showConfirmDeleteNoteBoxWithNoteDialog", { title, callback: res }));
} }
export async function prompt(props: PromptDialogOptions) { async function prompt(props: PromptDialogOptions) {
return new Promise<string | null>((res) => appContext.triggerCommand("showPromptDialog", { ...props, callback: res })); return new Promise<string | null>((res) => appContext.triggerCommand("showPromptDialog", { ...props, callback: res }));
} }

View File

@@ -48,6 +48,6 @@ function getUrl(docNameValue: string, language: string) {
// Cannot have spaces in the URL due to how JQuery.load works. // Cannot have spaces in the URL due to how JQuery.load works.
docNameValue = docNameValue.replaceAll(" ", "%20"); docNameValue = docNameValue.replaceAll(" ", "%20");
const basePath = window.glob.isDev ? window.glob.assetPath + "/.." : window.glob.assetPath; const basePath = window.glob.isDev ? new URL(window.glob.assetPath).pathname : window.glob.assetPath;
return `${basePath}/doc_notes/${language}/${docNameValue}.html`; return `${basePath}/doc_notes/${language}/${docNameValue}.html`;
} }

View File

@@ -1,8 +1,16 @@
import ws from "./ws.js"; import ws from "./ws.js";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
import { OpenedFileUpdateStatus } from "@triliumnext/commons";
const fileModificationStatus: Record<string, Record<string, OpenedFileUpdateStatus>> = { // TODO: Deduplicate
interface Message {
type: string;
entityType: string;
entityId: string;
lastModifiedMs: number;
filePath: string;
}
const fileModificationStatus: Record<string, Record<string, Message>> = {
notes: {}, notes: {},
attachments: {} attachments: {}
}; };
@@ -31,7 +39,7 @@ function ignoreModification(entityType: string, entityId: string) {
delete fileModificationStatus[entityType][entityId]; delete fileModificationStatus[entityType][entityId];
} }
ws.subscribeToMessages(async message => { ws.subscribeToMessages(async (message: Message) => {
if (message.type !== "openedFileUpdated") { if (message.type !== "openedFileUpdated") {
return; return;
} }

View File

@@ -8,7 +8,6 @@ import FAttribute, { type FAttributeRow } from "../entities/fattribute.js";
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js"; import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
import type { default as FNote, FNoteRow } from "../entities/fnote.js"; import type { default as FNote, FNoteRow } from "../entities/fnote.js";
import type { EntityChange } from "../server_types.js"; import type { EntityChange } from "../server_types.js";
import type { OptionNames } from "@triliumnext/commons";
async function processEntityChanges(entityChanges: EntityChange[]) { async function processEntityChanges(entityChanges: EntityChange[]) {
const loadResults = new LoadResults(entityChanges); const loadResults = new LoadResults(entityChanges);
@@ -31,8 +30,9 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
continue; // only noise continue; // only noise
} }
options.set(attributeEntity.name as OptionNames, attributeEntity.value); options.set(attributeEntity.name, attributeEntity.value);
loadResults.addOption(attributeEntity.name as OptionNames);
loadResults.addOption(attributeEntity.name);
} else if (ec.entityName === "attachments") { } else if (ec.entityName === "attachments") {
processAttachment(loadResults, ec); processAttachment(loadResults, ec);
} else if (ec.entityName === "blobs") { } else if (ec.entityName === "blobs") {

View File

@@ -21,7 +21,6 @@ import dayjs from "dayjs";
import type NoteContext from "../components/note_context.js"; import type NoteContext from "../components/note_context.js";
import type NoteDetailWidget from "../widgets/note_detail.js"; import type NoteDetailWidget from "../widgets/note_detail.js";
import type Component from "../components/component.js"; import type Component from "../components/component.js";
import { formatLogMessage } from "@triliumnext/commons";
/** /**
* A whole number * A whole number
@@ -456,7 +455,7 @@ export interface Api {
/** /**
* Log given message to the log pane in UI * Log given message to the log pane in UI
*/ */
log(message: string | object): void; log(message: string): void;
} }
/** /**
@@ -697,7 +696,7 @@ function FrontendScriptApi(this: Api, startNote: FNote, currentNote: FNote, orig
this.log = (message) => { this.log = (message) => {
const { noteId } = this.startNote; const { noteId } = this.startNote;
message = `${utils.now()}: ${formatLogMessage(message)}`; message = `${utils.now()}: ${message}`;
console.log(`Script ${noteId}: ${message}`); console.log(`Script ${noteId}: ${message}`);

View File

@@ -1,7 +1,7 @@
import { t } from "./i18n.js"; import { t } from "./i18n.js";
import toastService, { showError } from "./toast.js"; import toastService, { showError } from "./toast.js";
export function copyImageReferenceToClipboard($imageWrapper: JQuery<HTMLElement>) { function copyImageReferenceToClipboard($imageWrapper: JQuery<HTMLElement>) {
try { try {
$imageWrapper.attr("contenteditable", "true"); $imageWrapper.attr("contenteditable", "true");
selectImage($imageWrapper.get(0)); selectImage($imageWrapper.get(0));

View File

@@ -4,7 +4,6 @@ import ws from "./ws.js";
import utils from "./utils.js"; import utils from "./utils.js";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
import { t } from "./i18n.js"; import { t } from "./i18n.js";
import { WebSocketMessage } from "@triliumnext/commons";
type BooleanLike = boolean | "true" | "false"; type BooleanLike = boolean | "true" | "false";
@@ -67,7 +66,7 @@ function makeToast(id: string, message: string): ToastOptions {
} }
ws.subscribeToMessages(async (message) => { ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "importNotes") { if (message.taskType !== "importNotes") {
return; return;
} }
@@ -88,8 +87,8 @@ ws.subscribeToMessages(async (message) => {
} }
}); });
ws.subscribeToMessages(async (message: WebSocketMessage) => { ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "importAttachments") { if (message.taskType !== "importAttachments") {
return; return;
} }

View File

@@ -1,43 +0,0 @@
import { NoteType } from "@triliumnext/commons";
import FNote from "../entities/fnote";
import { ViewTypeOptions } from "../widgets/collections/interface";
export const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
canvas: null,
code: null,
contentWidget: null,
doc: null,
file: null,
image: null,
launcher: null,
mermaid: null,
mindMap: null,
noteMap: null,
relationMap: null,
render: null,
search: null,
text: null,
webView: null,
aiChat: null
};
export const byBookType: Record<ViewTypeOptions, string | null> = {
list: "mULW0Q3VojwY",
grid: "8QqnMzx393bx",
calendar: "xWbu3jpNWapp",
table: "2FvYrpmOXm29",
geoMap: "81SGnPGMk7Xc",
board: "CtBQqbwXDx1w"
};
export function getHelpUrlForNote(note: FNote | null | undefined) {
if (note && note.type !== "book" && byNoteType[note.type]) {
return byNoteType[note.type];
} else if (note?.hasLabel("calendarRoot")) {
return "l0tKav7yLHGF";
} else if (note?.hasLabel("textSnippet")) {
return "pwc194wlRzcH";
} else if (note && note.type === "book") {
return byBookType[note.getAttributeValue("label", "viewType") as ViewTypeOptions ?? ""]
}
}

View File

@@ -62,10 +62,6 @@ async function getAction(actionName: string, silent = false) {
return action; return action;
} }
export function getActionSync(actionName: string) {
return keyboardActionRepo[actionName];
}
function updateDisplayedShortcuts($container: JQuery<HTMLElement>) { function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
//@ts-ignore //@ts-ignore
//TODO: each() does not support async callbacks. //TODO: each() does not support async callbacks.

View File

@@ -35,7 +35,8 @@ async function getLinkIcon(noteId: string, viewMode: ViewMode | undefined) {
return icon; return icon;
} }
export type ViewMode = "default" | "source" | "attachments" | "contextual-help"; // TODO: Remove `string` once all the view modes have been mapped.
type ViewMode = "default" | "source" | "attachments" | "contextual-help" | string;
export interface ViewScope { export interface ViewScope {
/** /**
@@ -506,7 +507,7 @@ $(document).on("dblclick", "a", (e) => {
$(document).on("mousedown", "a", (e) => { $(document).on("mousedown", "a", (e) => {
if (e.which === 2) { if (e.which === 2) {
// prevent paste on middle click // prevent paste on middle click
// https://github.com/zadam/trilium/issues/2995 // https://github.com/TriliumNext/Trilium/issues/2995
// https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions // https://developer.mozilla.org/en-US/docs/Web/API/Element/auxclick_event#preventing_default_actions
e.preventDefault(); e.preventDefault();
return false; return false;

View File

@@ -1,4 +1,4 @@
import type { AttachmentRow, EtapiTokenRow, OptionNames } from "@triliumnext/commons"; import type { AttachmentRow, EtapiTokenRow } from "@triliumnext/commons";
import type { AttributeType } from "../entities/fattribute.js"; import type { AttributeType } from "../entities/fattribute.js";
import type { EntityChange } from "../server_types.js"; import type { EntityChange } from "../server_types.js";
@@ -67,7 +67,7 @@ export default class LoadResults {
private revisionRows: RevisionRow[]; private revisionRows: RevisionRow[];
private noteReorderings: string[]; private noteReorderings: string[];
private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[]; private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
private optionNames: OptionNames[]; private optionNames: string[];
private attachmentRows: AttachmentRow[]; private attachmentRows: AttachmentRow[];
public hasEtapiTokenChanges: boolean = false; public hasEtapiTokenChanges: boolean = false;
@@ -180,11 +180,11 @@ export default class LoadResults {
return this.contentNoteIdToComponentId.find((l) => l.noteId === noteId && l.componentId !== componentId); return this.contentNoteIdToComponentId.find((l) => l.noteId === noteId && l.componentId !== componentId);
} }
addOption(name: OptionNames) { addOption(name: string) {
this.optionNames.push(name); this.optionNames.push(name);
} }
isOptionReloaded(name: OptionNames) { isOptionReloaded(name: string) {
return this.optionNames.includes(name); return this.optionNames.includes(name);
} }

View File

@@ -36,8 +36,6 @@ export interface Suggestion {
commandId?: string; commandId?: string;
commandDescription?: string; commandDescription?: string;
commandShortcut?: string; commandShortcut?: string;
attributeSnippet?: string;
highlightedAttributeSnippet?: string;
} }
export interface Options { export interface Options {
@@ -325,33 +323,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
html += '</div>'; html += '</div>';
return html; return html;
} }
// Add special class for search-notes action return `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`;
const actionClass = suggestion.action === "search-notes" ? "search-notes-action" : "";
// Choose appropriate icon based on action
let iconClass = suggestion.icon ?? "bx bx-note";
if (suggestion.action === "search-notes") {
iconClass = "bx bx-search";
} else if (suggestion.action === "create-note") {
iconClass = "bx bx-plus";
} else if (suggestion.action === "external-link") {
iconClass = "bx bx-link-external";
}
// Simplified HTML structure without nested divs
let html = `<div class="note-suggestion ${actionClass}">`;
html += `<span class="icon ${iconClass}"></span>`;
html += `<span class="text">`;
html += `<span class="search-result-title">${suggestion.highlightedNotePathTitle}</span>`;
// Add attribute snippet inline if available
if (suggestion.highlightedAttributeSnippet) {
html += `<span class="search-result-attributes">${suggestion.highlightedAttributeSnippet}</span>`;
}
html += `</span>`;
html += `</div>`;
return html;
} }
}, },
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added // we can't cache identical searches because notes can be created / renamed, new recent notes can be added

View File

@@ -0,0 +1,71 @@
import type FNote from "../entities/fnote.js";
import BoardView from "../widgets/view_widgets/board_view/index.js";
import CalendarView from "../widgets/view_widgets/calendar_view.js";
import GeoView from "../widgets/view_widgets/geo_view/index.js";
import ListOrGridView from "../widgets/view_widgets/list_or_grid_view.js";
import TableView from "../widgets/view_widgets/table_view/index.js";
import type { ViewModeArgs } from "../widgets/view_widgets/view_mode.js";
import type ViewMode from "../widgets/view_widgets/view_mode.js";
const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board"] as const;
export type ArgsWithoutNoteId = Omit<ViewModeArgs, "noteIds">;
export type ViewTypeOptions = typeof allViewTypes[number];
export default class NoteListRenderer {
private viewType: ViewTypeOptions;
private args: ArgsWithoutNoteId;
public viewMode?: ViewMode<any>;
constructor(args: ArgsWithoutNoteId) {
this.args = args;
this.viewType = this.#getViewType(args.parentNote);
}
#getViewType(parentNote: FNote): ViewTypeOptions {
const viewType = parentNote.getLabelValue("viewType");
if (!(allViewTypes as readonly string[]).includes(viewType || "")) {
// when not explicitly set, decide based on the note type
return parentNote.type === "search" ? "list" : "grid";
} else {
return viewType as ViewTypeOptions;
}
}
get isFullHeight() {
switch (this.viewType) {
case "list":
case "grid":
return false;
default:
return true;
}
}
async renderList() {
const args = this.args;
const viewMode = this.#buildViewMode(args);
this.viewMode = viewMode;
await viewMode.beforeRender();
return await viewMode.renderList();
}
#buildViewMode(args: ViewModeArgs) {
switch (this.viewType) {
case "calendar":
return new CalendarView(args);
case "table":
return new TableView(args);
case "geoMap":
return new GeoView(args);
case "board":
return new BoardView(args);
case "list":
case "grid":
default:
return new ListOrGridView(this.viewType, args);
}
}
}

View File

@@ -99,7 +99,7 @@ async function mouseEnterHandler(this: HTMLElement) {
if ($link.filter(":hover").length > 0) { if ($link.filter(":hover").length > 0) {
$link.tooltip({ $link.tooltip({
container: "body", container: "body",
// https://github.com/zadam/trilium/issues/2794 https://github.com/zadam/trilium/issues/2988 // https://github.com/TriliumNext/Trilium/issues/2794 https://github.com/TriliumNext/Trilium/issues/2988
// with bottom this flickering happens a bit less // with bottom this flickering happens a bit less
placement: "bottom", placement: "bottom",
trigger: "manual", trigger: "manual",

View File

@@ -1,7 +1,7 @@
import { t } from "./i18n.js"; import { t } from "./i18n.js";
import froca from "./froca.js"; import froca from "./froca.js";
import server from "./server.js"; import server from "./server.js";
import type { MenuCommandItem, MenuItem, MenuItemBadge, MenuSeparatorItem } from "../menus/context_menu.js"; import type { MenuCommandItem, MenuItem, MenuItemBadge } from "../menus/context_menu.js";
import type { NoteType } from "../entities/fnote.js"; import type { NoteType } from "../entities/fnote.js";
import type { TreeCommandNames } from "../menus/tree_context_menu.js"; import type { TreeCommandNames } from "../menus/tree_context_menu.js";
@@ -73,7 +73,7 @@ const BETA_BADGE = {
title: t("note_types.beta-feature") title: t("note_types.beta-feature")
}; };
const SEPARATOR: MenuSeparatorItem = { kind: "separator" }; const SEPARATOR = { title: "----" };
const creationDateCache = new Map<string, Date>(); const creationDateCache = new Map<string, Date>();
let rootCreationDate: Date | undefined; let rootCreationDate: Date | undefined;
@@ -81,8 +81,8 @@ let rootCreationDate: Date | undefined;
async function getNoteTypeItems(command?: TreeCommandNames) { async function getNoteTypeItems(command?: TreeCommandNames) {
const items: MenuItem<TreeCommandNames>[] = [ const items: MenuItem<TreeCommandNames>[] = [
...getBlankNoteTypes(command), ...getBlankNoteTypes(command),
...await getBuiltInTemplates(null, command, false),
...await getBuiltInTemplates(t("note_types.collections"), command, true), ...await getBuiltInTemplates(t("note_types.collections"), command, true),
...await getBuiltInTemplates(null, command, false),
...await getUserTemplates(command) ...await getUserTemplates(command)
]; ];
@@ -121,10 +121,7 @@ async function getUserTemplates(command?: TreeCommandNames) {
} }
const items: MenuItem<TreeCommandNames>[] = [ const items: MenuItem<TreeCommandNames>[] = [
{ SEPARATOR
title: t("note_type_chooser.templates"),
kind: "header"
}
]; ];
for (const templateNote of templateNotes) { for (const templateNote of templateNotes) {
@@ -161,7 +158,8 @@ async function getBuiltInTemplates(title: string | null, command: TreeCommandNam
if (title) { if (title) {
items.push({ items.push({
title: title, title: title,
kind: "header" enabled: false,
uiIcon: "bx bx-empty"
}); });
} else { } else {
items.push(SEPARATOR); items.push(SEPARATOR);

View File

@@ -35,7 +35,7 @@ function download(url: string) {
} }
} }
export function downloadFileNote(noteId: string) { function downloadFileNote(noteId: string) {
const url = `${getFileUrl("notes", noteId)}?${Date.now()}`; // don't use cache const url = `${getFileUrl("notes", noteId)}?${Date.now()}`; // don't use cache
download(url); download(url);
@@ -163,7 +163,7 @@ async function openExternally(type: string, entityId: string, mime: string) {
} }
} }
export const openNoteExternally = async (noteId: string, mime: string) => await openExternally("notes", noteId, mime); const openNoteExternally = async (noteId: string, mime: string) => await openExternally("notes", noteId, mime);
const openAttachmentExternally = async (attachmentId: string, mime: string) => await openExternally("attachments", attachmentId, mime); const openAttachmentExternally = async (attachmentId: string, mime: string) => await openExternally("attachments", attachmentId, mime);
function getHost() { function getHost() {

View File

@@ -20,7 +20,7 @@ class Options {
this.arr = arr; this.arr = arr;
} }
get(key: OptionNames) { get(key: string) {
return this.arr?.[key] as string; return this.arr?.[key] as string;
} }
@@ -40,7 +40,7 @@ class Options {
} }
} }
getInt(key: OptionNames) { getInt(key: string) {
const value = this.arr?.[key]; const value = this.arr?.[key];
if (typeof value === "number") { if (typeof value === "number") {
return value; return value;
@@ -52,7 +52,7 @@ class Options {
return null; return null;
} }
getFloat(key: OptionNames) { getFloat(key: string) {
const value = this.arr?.[key]; const value = this.arr?.[key];
if (typeof value !== "string") { if (typeof value !== "string") {
return null; return null;
@@ -60,15 +60,15 @@ class Options {
return parseFloat(value); return parseFloat(value);
} }
is(key: OptionNames) { is(key: string) {
return this.arr[key] === "true"; return this.arr[key] === "true";
} }
set(key: OptionNames, value: OptionValue) { set(key: string, value: OptionValue) {
this.arr[key] = value; this.arr[key] = value;
} }
async save(key: OptionNames, value: OptionValue) { async save(key: string, value: OptionValue) {
this.set(key, value); this.set(key, value);
const payload: Record<string, OptionValue> = {}; const payload: Record<string, OptionValue> = {};
@@ -85,7 +85,7 @@ class Options {
await server.put<void>("options", newValues); await server.put<void>("options", newValues);
} }
async toggle(key: OptionNames) { async toggle(key: string) {
await this.save(key, (!this.is(key)).toString()); await this.save(key, (!this.is(key)).toString());
} }
} }

View File

@@ -107,11 +107,11 @@ function makeToast(message: Message, title: string, text: string): ToastOptions
} }
ws.subscribeToMessages(async (message) => { ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "protectNotes") { if (message.taskType !== "protectNotes") {
return; return;
} }
const isProtecting = message.data?.protect; const isProtecting = message.data.protect;
const title = isProtecting ? t("protected_session.protecting-title") : t("protected_session.unprotecting-title"); const title = isProtecting ? t("protected_session.protecting-title") : t("protected_session.unprotecting-title");
if (message.type === "taskError") { if (message.type === "taskError") {

View File

@@ -10,10 +10,6 @@ let leftInstance: ReturnType<typeof Split> | null;
let rightPaneWidth: number; let rightPaneWidth: number;
let rightInstance: ReturnType<typeof Split> | null; let rightInstance: ReturnType<typeof Split> | null;
const noteSplitMap = new Map<string[], ReturnType<typeof Split> | undefined>(); // key: a group of ntxIds, value: the corresponding Split instance
const noteSplitRafMap = new Map<string[], number>();
let splitNoteContainer: HTMLElement | undefined;
function setupLeftPaneResizer(leftPaneVisible: boolean) { function setupLeftPaneResizer(leftPaneVisible: boolean) {
if (leftInstance) { if (leftInstance) {
leftInstance.destroy(); leftInstance.destroy();
@@ -87,86 +83,7 @@ function setupRightPaneResizer() {
} }
} }
function findKeyByNtxId(ntxId: string): string[] | undefined {
// Find the corresponding key in noteSplitMap based on ntxId
for (const key of noteSplitMap.keys()) {
if (key.includes(ntxId)) return key;
}
return undefined;
}
function setupNoteSplitResizer(ntxIds: string[]) {
let targetNtxIds: string[] | undefined;
for (const ntxId of ntxIds) {
targetNtxIds = findKeyByNtxId(ntxId);
if (targetNtxIds) break;
}
if (targetNtxIds) {
noteSplitMap.get(targetNtxIds)?.destroy();
for (const id of ntxIds) {
if (!targetNtxIds.includes(id)) {
targetNtxIds.push(id)
};
}
} else {
targetNtxIds = [...ntxIds];
}
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
function delNoteSplitResizer(ntxIds: string[]) {
let targetNtxIds = findKeyByNtxId(ntxIds[0]);
if (!targetNtxIds) {
return;
}
noteSplitMap.get(targetNtxIds)?.destroy();
noteSplitMap.delete(targetNtxIds);
targetNtxIds = targetNtxIds.filter(id => !ntxIds.includes(id));
if (targetNtxIds.length >= 2) {
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
}
function moveNoteSplitResizer(ntxId: string) {
const targetNtxIds = findKeyByNtxId(ntxId);
if (!targetNtxIds) {
return;
}
noteSplitMap.get(targetNtxIds)?.destroy();
noteSplitMap.set(targetNtxIds, undefined);
createSplitInstance(targetNtxIds);
}
function createSplitInstance(targetNtxIds: string[]) {
const prevRafId = noteSplitRafMap.get(targetNtxIds);
if (prevRafId) {
cancelAnimationFrame(prevRafId);
}
const rafId = requestAnimationFrame(() => {
splitNoteContainer = splitNoteContainer ?? $("#center-pane").find(".split-note-container-widget")[0];
const splitPanels = [...splitNoteContainer.querySelectorAll<HTMLElement>(':scope > .note-split')]
.filter(el => targetNtxIds.includes(el.getAttribute('data-ntx-id') ?? ""));
const splitInstance = Split(splitPanels, {
gutterSize: DEFAULT_GUTTER_SIZE,
minSize: 150,
});
noteSplitMap.set(targetNtxIds, splitInstance);
noteSplitRafMap.delete(targetNtxIds);
});
noteSplitRafMap.set(targetNtxIds, rafId);
}
export default { export default {
setupLeftPaneResizer, setupLeftPaneResizer,
setupRightPaneResizer, setupRightPaneResizer
setupNoteSplitResizer,
delNoteSplitResizer,
moveNoteSplitResizer
}; };

View File

@@ -218,7 +218,7 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile
if (utils.isElectron()) { if (utils.isElectron()) {
const ipc = utils.dynamicRequire("electron").ipcRenderer; const ipc = utils.dynamicRequire("electron").ipcRenderer;
ipc.on("server-response", async (_, arg: Arg) => { ipc.on("server-response", async (event: string, arg: Arg) => {
if (arg.statusCode >= 200 && arg.statusCode < 300) { if (arg.statusCode >= 200 && arg.statusCode < 300) {
handleSuccessfulResponse(arg); handleSuccessfulResponse(arg);
} else { } else {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import shortcuts, { keyMatches, matchesShortcut, isIMEComposing } from "./shortcuts.js"; import shortcuts, { keyMatches, matchesShortcut } from "./shortcuts.js";
// Mock utils module // Mock utils module
vi.mock("./utils.js", () => ({ vi.mock("./utils.js", () => ({
@@ -119,6 +119,11 @@ describe("shortcuts", () => {
metaKey: options.metaKey || false metaKey: options.metaKey || false
} as KeyboardEvent); } as KeyboardEvent);
it("should match simple key shortcuts", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA" });
expect(matchesShortcut(event, "a")).toBe(true);
});
it("should match shortcuts with modifiers", () => { it("should match shortcuts with modifiers", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true }); const event = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true });
expect(matchesShortcut(event, "ctrl+a")).toBe(true); expect(matchesShortcut(event, "ctrl+a")).toBe(true);
@@ -143,28 +148,6 @@ describe("shortcuts", () => {
expect(matchesShortcut(event, "a")).toBe(false); expect(matchesShortcut(event, "a")).toBe(false);
}); });
it("should not match when no modifiers are used", () => {
const event = createKeyboardEvent({ key: "a", code: "KeyA" });
expect(matchesShortcut(event, "a")).toBe(false);
});
it("should match some keys even with no modifiers", () => {
// Bare function keys
let event = createKeyboardEvent({ key: "F1", code: "F1" });
expect(matchesShortcut(event, "F1")).toBeTruthy();
expect(matchesShortcut(event, "f1")).toBeTruthy();
// Function keys with shift
event = createKeyboardEvent({ key: "F1", code: "F1", shiftKey: true });
expect(matchesShortcut(event, "Shift+F1")).toBeTruthy();
// Special keys
for (const keyCode of [ "Delete", "Enter" ]) {
event = createKeyboardEvent({ key: keyCode, code: keyCode });
expect(matchesShortcut(event, keyCode), `Key ${keyCode}`).toBeTruthy();
}
});
it("should handle alternative modifier names", () => { it("should handle alternative modifier names", () => {
const ctrlEvent = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true }); const ctrlEvent = createKeyboardEvent({ key: "a", code: "KeyA", ctrlKey: true });
expect(matchesShortcut(ctrlEvent, "control+a")).toBe(true); expect(matchesShortcut(ctrlEvent, "control+a")).toBe(true);
@@ -337,36 +320,4 @@ describe("shortcuts", () => {
expect(event.preventDefault).not.toHaveBeenCalled(); expect(event.preventDefault).not.toHaveBeenCalled();
}); });
}); });
describe('isIMEComposing', () => {
it('should return true when event.isComposing is true', () => {
const event = { isComposing: true, keyCode: 65 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return true when keyCode is 229', () => {
const event = { isComposing: false, keyCode: 229 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return true when both isComposing is true and keyCode is 229', () => {
const event = { isComposing: true, keyCode: 229 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(true);
});
it('should return false for normal keys', () => {
const event = { isComposing: false, keyCode: 65 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(false);
});
it('should return false when isComposing is undefined and keyCode is not 229', () => {
const event = { keyCode: 13 } as KeyboardEvent;
expect(isIMEComposing(event)).toBe(false);
});
it('should handle null/undefined events gracefully', () => {
expect(isIMEComposing(null as any)).toBe(false);
expect(isIMEComposing(undefined as any)).toBe(false);
});
});
}); });

View File

@@ -36,35 +36,8 @@ const keyMap: { [key: string]: string[] } = {
}; };
// Function keys // Function keys
const functionKeyCodes: string[] = [];
for (let i = 1; i <= 19; i++) { for (let i = 1; i <= 19; i++) {
const keyCode = `F${i}`; keyMap[`f${i}`] = [`F${i}`];
functionKeyCodes.push(keyCode);
keyMap[`f${i}`] = [ keyCode ];
}
const KEYCODES_WITH_NO_MODIFIER = new Set([
"Delete",
"Enter",
...functionKeyCodes
]);
/**
* Check if IME (Input Method Editor) is composing
* This is used to prevent keyboard shortcuts from firing during IME composition
* @param e - The keyboard event to check
* @returns true if IME is currently composing, false otherwise
*/
export function isIMEComposing(e: KeyboardEvent): boolean {
// Handle null/undefined events gracefully
if (!e) {
return false;
}
// Standard check for composition state
// e.isComposing is true when IME is actively composing
// e.keyCode === 229 is a fallback for older browsers where 229 indicates IME processing
return e.isComposing || e.keyCode === 229;
} }
function removeGlobalShortcut(namespace: string) { function removeGlobalShortcut(namespace: string) {
@@ -95,13 +68,6 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
} }
const e = evt as KeyboardEvent; const e = evt as KeyboardEvent;
// Skip processing if IME is composing to prevent shortcuts from
// interfering with text input in CJK languages
if (isIMEComposing(e)) {
return;
}
if (matchesShortcut(e, keyboardShortcut)) { if (matchesShortcut(e, keyboardShortcut)) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
@@ -171,12 +137,6 @@ export function matchesShortcut(e: KeyboardEvent, shortcut: string): boolean {
const expectedShift = modifiers.includes('shift'); const expectedShift = modifiers.includes('shift');
const expectedMeta = modifiers.includes('meta') || modifiers.includes('cmd') || modifiers.includes('command'); const expectedMeta = modifiers.includes('meta') || modifiers.includes('cmd') || modifiers.includes('command');
// Refuse key combinations that don't include modifiers because they interfere with the normal usage of the application.
// Some keys such as function keys are an exception.
if (!(expectedCtrl || expectedAlt || expectedShift || expectedMeta) && !KEYCODES_WITH_NO_MODIFIER.has(e.code)) {
return false;
}
return e.ctrlKey === expectedCtrl && return e.ctrlKey === expectedCtrl &&
e.altKey === expectedAlt && e.altKey === expectedAlt &&
e.shiftKey === expectedShift && e.shiftKey === expectedShift &&

View File

@@ -1,9 +1,10 @@
import ws from "./ws.js";
import utils from "./utils.js"; import utils from "./utils.js";
export interface ToastOptions { export interface ToastOptions {
id?: string; id?: string;
icon: string; icon: string;
title?: string; title: string;
message: string; message: string;
delay?: number; delay?: number;
autohide?: boolean; autohide?: boolean;
@@ -11,32 +12,20 @@ export interface ToastOptions {
} }
function toast(options: ToastOptions) { function toast(options: ToastOptions) {
const $toast = $(options.title const $toast = $(
? `\ `<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true"> <div class="toast-header">
<div class="toast-header"> <strong class="me-auto">
<strong class="me-auto">
<span class="bx bx-${options.icon}"></span>
<span class="toast-title"></span>
</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body"></div>
</div>`
: `
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-icon">
<span class="bx bx-${options.icon}"></span> <span class="bx bx-${options.icon}"></span>
</div> <span class="toast-title"></span>
<div class="toast-body"></div> </strong>
<div class="toast-header"> <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> </div>
</div> <div class="toast-body"></div>
</div>` </div>`
); );
$toast.toggleClass("no-title", !options.title); $toast.find(".toast-title").text(options.title);
$toast.find(".toast-title").text(options.title ?? "");
$toast.find(".toast-body").html(options.message); $toast.find(".toast-body").html(options.message);
if (options.id) { if (options.id) {
@@ -81,6 +70,7 @@ function showMessage(message: string, delay = 2000) {
console.debug(utils.now(), "message:", message); console.debug(utils.now(), "message:", message);
toast({ toast({
title: "Info",
icon: "check", icon: "check",
message: message, message: message,
autohide: true, autohide: true,
@@ -92,6 +82,7 @@ export function showError(message: string, delay = 10000) {
console.log(utils.now(), "error: ", message); console.log(utils.now(), "error: ", message);
toast({ toast({
title: "Error",
icon: "alert", icon: "alert",
message: message, message: message,
autohide: true, autohide: true,

View File

@@ -1,6 +1,5 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import type { ViewScope } from "./link.js"; import type { ViewScope } from "./link.js";
import FNote from "../entities/fnote";
const SVG_MIME = "image/svg+xml"; const SVG_MIME = "image/svg+xml";
@@ -47,6 +46,27 @@ function parseDate(str: string) {
} }
} }
// Source: https://stackoverflow.com/a/30465299/4898894
function getMonthsInDateRange(startDate: string, endDate: string) {
const start = startDate.split("-");
const end = endDate.split("-");
const startYear = parseInt(start[0]);
const endYear = parseInt(end[0]);
const dates: string[] = [];
for (let i = startYear; i <= endYear; i++) {
const endMonth = i != endYear ? 11 : parseInt(end[1]) - 1;
const startMon = i === startYear ? parseInt(start[1]) - 1 : 0;
for (let j = startMon; j <= endMonth; j = j > 12 ? j % 12 || 11 : j + 1) {
const month = j + 1;
const displayMonth = month < 10 ? "0" + month : month;
dates.push([i, displayMonth].join("-"));
}
}
return dates;
}
function padNum(num: number) { function padNum(num: number) {
return `${num <= 9 ? "0" : ""}${num}`; return `${num <= 9 ? "0" : ""}${num}`;
} }
@@ -128,19 +148,7 @@ export function isElectron() {
return !!(window && window.process && window.process.type); return !!(window && window.process && window.process.type);
} }
/** function isMac() {
* Returns `true` if the client is running as a PWA, otherwise `false`.
*/
export function isPWA() {
return (
window.matchMedia('(display-mode: standalone)').matches
|| window.matchMedia('(display-mode: window-controls-overlay)').matches
|| window.navigator.standalone
|| window.navigator.windowControlsOverlay
);
}
export function isMac() {
return navigator.platform.indexOf("Mac") > -1; return navigator.platform.indexOf("Mac") > -1;
} }
@@ -177,11 +185,7 @@ export function escapeQuotes(value: string) {
return value.replaceAll('"', "&quot;"); return value.replaceAll('"', "&quot;");
} }
export function formatSize(size: number | null | undefined) { function formatSize(size: number) {
if (size === null || size === undefined) {
return "";
}
size = Math.max(Math.round(size / 1024), 1); size = Math.max(Math.round(size / 1024), 1);
if (size < 1024) { if (size < 1024) {
@@ -288,55 +292,7 @@ function isHtmlEmpty(html: string) {
); );
} }
function formatHtml(html: string) { async function clearBrowserCache() {
let indent = "\n";
const tab = "\t";
let i = 0;
let pre: { indent: string; tag: string }[] = [];
html = html
.replace(new RegExp("<pre>([\\s\\S]+?)?</pre>"), function (x) {
pre.push({ indent: "", tag: x });
return "<--TEMPPRE" + i++ + "/-->";
})
.replace(new RegExp("<[^<>]+>[^<]?", "g"), function (x) {
let ret;
const tagRegEx = /<\/?([^\s/>]+)/.exec(x);
let tag = tagRegEx ? tagRegEx[1] : "";
let p = new RegExp("<--TEMPPRE(\\d+)/-->").exec(x);
if (p) {
const pInd = parseInt(p[1]);
pre[pInd].indent = indent;
}
if (["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"].indexOf(tag) >= 0) {
// self closing tag
ret = indent + x;
} else {
if (x.indexOf("</") < 0) {
//open tag
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + tab + x.substr(x.length - 1, x.length);
else ret = indent + x;
!p && (indent += tab);
} else {
//close tag
indent = indent.substr(0, indent.length - 1);
if (x.charAt(x.length - 1) !== ">") ret = indent + x.substr(0, x.length - 1) + indent + x.substr(x.length - 1, x.length);
else ret = indent + x;
}
}
return ret;
});
for (i = pre.length; i--;) {
html = html.replace("<--TEMPPRE" + i + "/-->", pre[i].tag.replace("<pre>", "<pre>\n").replace("</pre>", pre[i].indent + "</pre>"));
}
return html.charAt(0) === "\n" ? html.substr(1, html.length - 1) : html;
}
export async function clearBrowserCache() {
if (isElectron()) { if (isElectron()) {
const win = dynamicRequire("@electron/remote").getCurrentWindow(); const win = dynamicRequire("@electron/remote").getCurrentWindow();
await win.webContents.session.clearCache(); await win.webContents.session.clearCache();
@@ -350,13 +306,7 @@ function copySelectionToClipboard() {
} }
} }
type dynamicRequireMappings = { export function dynamicRequire(moduleName: string) {
"@electron/remote": typeof import("@electron/remote"),
"electron": typeof import("electron"),
"child_process": typeof import("child_process")
};
export function dynamicRequire<T extends keyof dynamicRequireMappings>(moduleName: T): Awaited<dynamicRequireMappings[T]>{
if (typeof __non_webpack_require__ !== "undefined") { if (typeof __non_webpack_require__ !== "undefined") {
return __non_webpack_require__(moduleName); return __non_webpack_require__(moduleName);
} else { } else {
@@ -487,7 +437,7 @@ function sleep(time_ms: number) {
}); });
} }
export function escapeRegExp(str: string) { function escapeRegExp(str: string) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
} }
@@ -620,7 +570,8 @@ function copyHtmlToClipboard(content: string) {
document.removeEventListener("copy", listener); document.removeEventListener("copy", listener);
} }
export function createImageSrcUrl(note: FNote) { // TODO: Set to FNote once the file is ported.
function createImageSrcUrl(note: { noteId: string; title: string }) {
return `api/images/${note.noteId}/${encodeURIComponent(note.title)}?timestamp=${Date.now()}`; return `api/images/${note.noteId}/${encodeURIComponent(note.title)}?timestamp=${Date.now()}`;
} }
@@ -789,7 +740,7 @@ function isUpdateAvailable(latestVersion: string | null | undefined, currentVers
return compareVersions(latestVersion, currentVersion) > 0; return compareVersions(latestVersion, currentVersion) > 0;
} }
export function isLaunchBarConfig(noteId: string) { function isLaunchBarConfig(noteId: string) {
return ["_lbRoot", "_lbAvailableLaunchers", "_lbVisibleLaunchers", "_lbMobileRoot", "_lbMobileAvailableLaunchers", "_lbMobileVisibleLaunchers"].includes(noteId); return ["_lbRoot", "_lbAvailableLaunchers", "_lbVisibleLaunchers", "_lbMobileRoot", "_lbMobileAvailableLaunchers", "_lbMobileVisibleLaunchers"].includes(noteId);
} }
@@ -837,43 +788,12 @@ export function arrayEqual<T>(a: T[], b: T[]) {
return true; return true;
} }
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.
*
* @param items the objects to be numbered.
* @returns the same object for convenience, with the type changed to indicate the new index field.
*/
export function numberObjectsInPlace<T extends object>(items: T[]): Indexed<T>[] {
let index = 0;
for (const item of items) {
(item as Indexed<T>).index = index++;
}
return items as Indexed<T>[];
}
export function mapToKeyValueArray<K extends string | number | symbol, V>(map: Record<K, V>) {
const values: { key: K, value: V }[] = [];
for (const [ key, value ] of Object.entries(map)) {
values.push({ key: key as K, value: value as V });
}
return values;
}
export function getErrorMessage(e: unknown) {
if (e && typeof e === "object" && "message" in e && typeof e.message === "string") {
return e.message;
} else {
return "Unknown error";
}
}
export default { export default {
reloadFrontendApp, reloadFrontendApp,
restartDesktopApp, restartDesktopApp,
reloadTray, reloadTray,
parseDate, parseDate,
getMonthsInDateRange,
formatDateISO, formatDateISO,
formatDateTime, formatDateTime,
formatTimeInterval, formatTimeInterval,
@@ -881,7 +801,6 @@ export default {
localNowDateTime, localNowDateTime,
now, now,
isElectron, isElectron,
isPWA,
isMac, isMac,
isCtrlKey, isCtrlKey,
assertArguments, assertArguments,
@@ -894,7 +813,6 @@ export default {
getNoteTypeClass, getNoteTypeClass,
getMimeTypeClass, getMimeTypeClass,
isHtmlEmpty, isHtmlEmpty,
formatHtml,
clearBrowserCache, clearBrowserCache,
copySelectionToClipboard, copySelectionToClipboard,
dynamicRequire, dynamicRequire,

View File

@@ -6,11 +6,9 @@ import frocaUpdater from "./froca_updater.js";
import appContext from "../components/app_context.js"; import appContext from "../components/app_context.js";
import { t } from "./i18n.js"; import { t } from "./i18n.js";
import type { EntityChange } from "../server_types.js"; import type { EntityChange } from "../server_types.js";
import { WebSocketMessage } from "@triliumnext/commons";
import toast from "./toast.js";
type MessageHandler = (message: WebSocketMessage) => void; type MessageHandler = (message: any) => void;
let messageHandlers: MessageHandler[] = []; const messageHandlers: MessageHandler[] = [];
let ws: WebSocket; let ws: WebSocket;
let lastAcceptedEntityChangeId = window.glob.maxEntityChangeIdAtLoad; let lastAcceptedEntityChangeId = window.glob.maxEntityChangeIdAtLoad;
@@ -49,14 +47,10 @@ function logInfo(message: string) {
window.logError = logError; window.logError = logError;
window.logInfo = logInfo; window.logInfo = logInfo;
export function subscribeToMessages(messageHandler: MessageHandler) { function subscribeToMessages(messageHandler: MessageHandler) {
messageHandlers.push(messageHandler); messageHandlers.push(messageHandler);
} }
export function unsubscribeToMessage(messageHandler: MessageHandler) {
messageHandlers = messageHandlers.filter(handler => handler !== messageHandler);
}
// used to serialize frontend update operations // used to serialize frontend update operations
let consumeQueuePromise: Promise<void> | null = null; let consumeQueuePromise: Promise<void> | null = null;
@@ -279,17 +273,13 @@ function connectWebSocket() {
async function sendPing() { async function sendPing() {
if (Date.now() - lastPingTs > 30000) { if (Date.now() - lastPingTs > 30000) {
console.warn(utils.now(), "Lost websocket connection to the backend"); console.log(
toast.showPersistent({ utils.now(),
id: "lost-websocket-connection", "Lost websocket connection to the backend. If you keep having this issue repeatedly, you might want to check your reverse proxy (nginx, apache) configuration and allow/unblock WebSocket."
title: t("ws.lost-websocket-connection-title"), );
message: t("ws.lost-websocket-connection-message"),
icon: "no-signal"
});
} }
if (ws.readyState === ws.OPEN) { if (ws.readyState === ws.OPEN) {
toast.closePersistent("lost-websocket-connection");
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
type: "ping", type: "ping",

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import "normalize.css"; import "normalize.css";
import "boxicons/css/boxicons.min.css"; import "boxicons/css/boxicons.min.css";
import "@triliumnext/ckeditor5/src/theme/ck-content.css"; import "@triliumnext/ckeditor5/content.css";
import "@triliumnext/share-theme/styles/index.css"; import "@triliumnext/share-theme/styles/index.css";
import "@triliumnext/share-theme/scripts/index.js"; import "@triliumnext/share-theme/scripts/index.js";

View File

@@ -0,0 +1,2 @@
/* Import all of Bootstrap's CSS */
@use "bootstrap/scss/bootstrap";

View File

@@ -31,7 +31,7 @@
#center-pane > *:not(.split-note-container-widget), #center-pane > *:not(.split-note-container-widget),
#right-pane, #right-pane,
.title-row .note-icon-widget, .title-row .note-icon-widget,
.title-row .icon-action, .title-row .button-widget,
.ribbon-container, .ribbon-container,
.promoted-attributes-widget, .promoted-attributes-widget,
.scroll-padding-widget, .scroll-padding-widget,
@@ -79,7 +79,7 @@ body {
height: unset !important; height: unset !important;
overflow: visible; overflow: visible;
position: unset; position: unset;
/* https://github.com/zadam/trilium/issues/3202 */ /* https://github.com/TriliumNext/Trilium/issues/3202 */
color: black; color: black;
} }

View File

@@ -28,28 +28,6 @@
--ck-mention-list-max-height: 500px; --ck-mention-list-max-height: 500px;
} }
body#trilium-app.motion-disabled *,
body#trilium-app.motion-disabled *::before,
body#trilium-app.motion-disabled *::after {
/* Disable transitions and animations */
transition: none !important;
animation: none !important;
}
body#trilium-app.shadows-disabled *,
body#trilium-app.shadows-disabled *::before,
body#trilium-app.shadows-disabled *::after {
/* Disable shadows */
box-shadow: none !important;
}
body#trilium-app.backdrop-effects-disabled *,
body#trilium-app.backdrop-effects-disabled *::before,
body#trilium-app.backdrop-effects-disabled *::after {
/* Disable backdrop effects */
backdrop-filter: none !important;
}
.table { .table {
--bs-table-bg: transparent !important; --bs-table-bg: transparent !important;
} }
@@ -62,7 +40,7 @@ body#trilium-app.backdrop-effects-disabled *::after {
} }
html { html {
/* this fixes FF filter vs. position fixed bug: https://github.com/zadam/trilium/issues/233 */ /* this fixes FF filter vs. position fixed bug: https://github.com/TriliumNext/Trilium/issues/233 */
height: 100vh; height: 100vh;
overscroll-behavior: none; overscroll-behavior: none;
} }
@@ -161,8 +139,7 @@ textarea,
color: var(--muted-text-color); color: var(--muted-text-color);
} }
.form-group.disabled, .form-group.disabled {
.form-checkbox.disabled {
opacity: 0.5; opacity: 0.5;
pointer-events: none; pointer-events: none;
} }
@@ -177,11 +154,6 @@ label.tn-checkbox + label.tn-checkbox {
margin-left: 12px; margin-left: 12px;
} }
label.tn-radio input[type="radio"],
label.tn-checkbox input[type="checkbox"] {
margin-right: .5em;
}
#left-pane input, #left-pane input,
#left-pane select, #left-pane select,
#left-pane textarea { #left-pane textarea {
@@ -252,6 +224,10 @@ button.close:hover {
color: var(--main-text-color) !important; color: var(--main-text-color) !important;
} }
.note-title[readonly] {
background: inherit;
}
.tdialog { .tdialog {
display: none; display: none;
} }
@@ -290,11 +266,6 @@ button.close:hover {
pointer-events: none; pointer-events: none;
} }
.icon-action.btn {
padding: 0 8px;
min-width: unset !important;
}
.ui-widget-content a:not(.ui-tabs-anchor) { .ui-widget-content a:not(.ui-tabs-anchor) {
color: #337ab7 !important; color: #337ab7 !important;
} }
@@ -363,24 +334,28 @@ button kbd {
.tabulator-popup-container { .tabulator-popup-container {
color: var(--menu-text-color) !important; color: var(--menu-text-color) !important;
font-size: inherit; font-size: inherit;
background: var(--menu-background-color) !important; background-color: var(--menu-background-color) !important;
user-select: none; user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
--bs-dropdown-zindex: 999; --bs-dropdown-zindex: 999;
--bs-dropdown-link-active-bg: var(--active-item-background-color) !important; --bs-dropdown-link-active-bg: var(--active-item-background-color) !important;
} }
.dropdown-menu .dropdown-divider {
break-before: avoid;
break-after: avoid;
}
body.desktop .dropdown-menu, body.desktop .dropdown-menu,
body.desktop .tabulator-popup-container { body.desktop .tabulator-popup-container {
border: 1px solid var(--dropdown-border-color); 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)); box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
animation: dropdown-menu-opening 100ms ease-in; animation: dropdown-menu-opening 100ms ease-in;
} }
@supports (animation-fill-mode: forwards) { @supports (animation-fill-mode: forwards) {
/* Delay the opening of submenus */ /* Delay the opening of submenus */
body.desktop:not(.motion-disabled) .dropdown-submenu .dropdown-menu { body.desktop .dropdown-submenu .dropdown-menu {
opacity: 0; opacity: 0;
animation-fill-mode: forwards; animation-fill-mode: forwards;
animation-delay: var(--submenu-opening-delay); animation-delay: var(--submenu-opening-delay);
@@ -415,7 +390,7 @@ body.desktop .tabulator-popup-container {
} }
.dropdown-menu a:hover:not(.disabled), .dropdown-menu a:hover:not(.disabled),
.dropdown-item:hover:not(.disabled, .dropdown-container-item), .dropdown-item:hover:not(.disabled, .dropdown-item-container),
.tabulator-menu-item:hover { .tabulator-menu-item:hover {
color: var(--hover-item-text-color) !important; color: var(--hover-item-text-color) !important;
background-color: var(--hover-item-background-color) !important; background-color: var(--hover-item-background-color) !important;
@@ -423,9 +398,9 @@ body.desktop .tabulator-popup-container {
cursor: pointer; cursor: pointer;
} }
.dropdown-container-item, .dropdown-item-container,
.dropdown-item.dropdown-container-item:hover, .dropdown-item-container:hover,
.dropdown-container-item:active { .dropdown-item-container:active {
background: transparent; background: transparent;
cursor: default; cursor: default;
} }
@@ -440,20 +415,14 @@ body #context-menu-container .dropdown-item > span {
align-items: center; align-items: center;
} }
.dropdown-item span.keyboard-shortcut, .dropdown-menu kbd {
.dropdown-item *:not(.keyboard-shortcut) > kbd {
flex-grow: 1; flex-grow: 1;
text-align: right; text-align: right;
padding-inline-start: 12px;
}
.dropdown-menu kbd {
color: var(--muted-text-color); color: var(--muted-text-color);
border: none; border: none;
background-color: transparent; background-color: transparent;
box-shadow: none; box-shadow: none;
padding-bottom: 0; padding-bottom: 0;
padding: 0;
} }
.dropdown-item, .dropdown-item,
@@ -462,12 +431,6 @@ body #context-menu-container .dropdown-item > span {
border: 1px solid transparent !important; border: 1px solid transparent !important;
} }
/* This is a workaround for Firefox not supporting break-before / break-after: avoid on columns.
* It usually wraps a menu item followed by a separator / header and another menu item. */
.dropdown-no-break {
break-inside: avoid;
}
.dropdown-item.disabled, .dropdown-item.disabled,
.dropdown-item.disabled kbd { .dropdown-item.disabled kbd {
color: #aaa !important; color: #aaa !important;
@@ -475,9 +438,9 @@ body #context-menu-container .dropdown-item > span {
.dropdown-item.active, .dropdown-item.active,
.dropdown-item:focus { .dropdown-item:focus {
color: var(--active-item-text-color); color: var(--active-item-text-color) !important;
background-color: var(--active-item-background-color); background-color: var(--active-item-background-color) !important;
border-color: var(--active-item-border-color); border-color: var(--active-item-border-color) !important;
outline: none; outline: none;
} }
@@ -580,7 +543,7 @@ button.btn-sm {
transform: translateX(7px); transform: translateX(7px);
color: var(--muted-text-color); color: var(--muted-text-color);
background-color: var(--main-background-color); background-color: var(--main-background-color);
/* Making this narrower because https://github.com/zadam/trilium/issues/502 (problem only in smaller font sizes) */ /* Making this narrower because https://github.com/TriliumNext/Trilium/issues/502 (problem only in smaller font sizes) */
min-width: 0; min-width: 0;
padding: 0; padding: 0;
z-index: 1000; z-index: 1000;
@@ -877,34 +840,10 @@ table.promoted-attributes-in-tooltip th {
.aa-dropdown-menu .aa-suggestion { .aa-dropdown-menu .aa-suggestion {
cursor: pointer; cursor: pointer;
padding: 6px 16px; padding: 5px;
margin: 0; margin: 0;
} }
.aa-dropdown-menu .aa-suggestion .icon {
display: inline-block;
line-height: inherit;
vertical-align: top;
}
.aa-dropdown-menu .aa-suggestion .text {
display: inline-block;
width: calc(100% - 20px);
padding-left: 4px;
}
.aa-dropdown-menu .aa-suggestion .search-result-title {
display: block;
}
.aa-dropdown-menu .aa-suggestion .search-result-attributes {
display: block;
font-size: 0.8em;
color: var(--muted-text-color);
opacity: 0.6;
line-height: 1;
}
.aa-dropdown-menu .aa-suggestion p { .aa-dropdown-menu .aa-suggestion p {
padding: 0; padding: 0;
margin: 0; margin: 0;
@@ -992,11 +931,6 @@ div[data-notify="container"] {
font-family: var(--monospace-font-family); font-family: var(--monospace-font-family);
} }
svg.ck-icon .note-icon {
color: var(--main-text-color);
font-size: 20px;
}
.ck-content { .ck-content {
--ck-content-font-family: var(--detail-font-family); --ck-content-font-family: var(--detail-font-family);
--ck-content-font-size: 1.1em; --ck-content-font-size: 1.1em;
@@ -1138,27 +1072,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.toast-body { .toast-body {
white-space: preserve-breaks; white-space: preserve-breaks;
overflow: hidden;
}
.toast.no-title {
display: flex;
flex-direction: row;
}
.toast.no-title .toast-icon {
display: flex;
align-items: center;
padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x);
}
.toast.no-title .toast-body {
padding-left: 0;
padding-right: 0;
}
.toast.no-title .toast-header {
background-color: unset !important;
} }
.ck-mentions .ck-button { .ck-mentions .ck-button {
@@ -1204,7 +1117,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
padding: 10px; padding: 10px;
border-radius: 10px; border-radius: 10px;
background-color: var(--accented-background-color); background-color: var(--accented-background-color);
display: flex; /* see https://github.com/zadam/trilium/issues/1590 */ display: flex; /* see https://github.com/TriliumNext/Trilium/issues/1590 */
} }
.include-note.ck-placeholder::before { .include-note.ck-placeholder::before {
@@ -1267,10 +1180,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
cursor: row-resize; cursor: row-resize;
} }
.hidden-ext.note-split + .gutter {
display: none;
}
#context-menu-cover.show { #context-menu-cover.show {
position: fixed; position: fixed;
top: 0; top: 0;
@@ -1342,7 +1251,7 @@ body.desktop li.dropdown-submenu:hover > ul.dropdown-menu {
left: 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; margin-top: -10px;
min-width: 15rem; min-width: 15rem;
/* to make submenu scrollable https://github.com/zadam/trilium/issues/3136 */ /* to make submenu scrollable https://github.com/TriliumNext/Trilium/issues/3136 */
max-height: 600px; max-height: 600px;
overflow: auto; overflow: auto;
} }
@@ -1492,7 +1401,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
cursor: pointer; cursor: pointer;
border: none; border: none;
color: var(--launcher-pane-text-color); color: var(--launcher-pane-text-color);
background: transparent; background-color: var(--launcher-pane-background-color);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -1800,6 +1709,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
} }
.note-split { .note-split {
flex-basis: 0; /* so that each split has same width */
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@@ -1863,37 +1773,20 @@ textarea {
font-size: 1em; font-size: 1em;
} }
.jump-to-note-dialog .modal-dialog {
max-width: 900px;
width: 90%;
}
.jump-to-note-dialog .modal-header { .jump-to-note-dialog .modal-header {
align-items: center; align-items: center;
} }
.jump-to-note-dialog .modal-body { .jump-to-note-dialog .modal-body {
padding: 0; padding: 0;
min-height: 200px;
} }
.jump-to-note-results .aa-dropdown-menu { .jump-to-note-results .aa-dropdown-menu {
max-height: calc(80vh - 200px); max-height: 40vh;
width: 100%;
max-width: none;
overflow-y: auto;
overflow-x: hidden;
text-overflow: ellipsis;
box-shadow: none;
}
.jump-to-note-results {
width: 100%;
} }
.jump-to-note-results .aa-suggestions { .jump-to-note-results .aa-suggestions {
padding: 0; padding: 1rem;
width: 100%;
} }
/* Command palette styling */ /* Command palette styling */
@@ -1911,24 +1804,8 @@ textarea {
.jump-to-note-dialog .aa-cursor .command-suggestion, .jump-to-note-dialog .aa-cursor .command-suggestion,
.jump-to-note-dialog .aa-suggestion:hover .command-suggestion { .jump-to-note-dialog .aa-suggestion:hover .command-suggestion {
background-color: transparent; border-left-color: var(--link-color);
} background-color: var(--hover-background-color);
.jump-to-note-dialog .show-in-full-search,
.jump-to-note-results .show-in-full-search {
border-top: 1px solid var(--main-border-color);
padding-top: 12px;
margin-top: 12px;
}
.jump-to-note-results .aa-suggestion .search-notes-action {
border-top: 1px solid var(--main-border-color);
margin-top: 8px;
padding-top: 8px;
}
.jump-to-note-results .aa-suggestion:has(.search-notes-action)::after {
display: none;
} }
.jump-to-note-dialog .command-icon { .jump-to-note-dialog .command-icon {
@@ -2025,16 +1902,12 @@ 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:has(.classic-toolbar-widget.visible) .ribbon-top-row,
body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget.visible)), body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget.visible)),
body.zen .note-icon-widget, body.zen .note-icon-widget,
body.zen .title-row .icon-action, body.zen .title-row .button-widget,
body.zen .floating-buttons-children > *:not(.bx-edit-alt), body.zen .floating-buttons-children > *:not(.bx-edit-alt),
body.zen .action-button { body.zen .action-button {
display: none !important; display: none !important;
} }
body.zen .split-note-container-widget > .gutter {
display: unset !important;
}
body.zen #launcher-pane { body.zen #launcher-pane {
position: absolute !important; position: absolute !important;
top: 0 !important; top: 0 !important;
@@ -2387,27 +2260,16 @@ footer.webview-footer button {
padding: 1px 10px 1px 10px; padding: 1px 10px 1px 10px;
} }
/* Search result highlighting */
.search-result-title b,
.search-result-content b {
font-weight: 900;
color: var(--admonition-warning-accent-color);
}
/* Customized icons */ /* Customized icons */
.bx-tn-toc::before { .bx-tn-toc::before {
content: "\ec24"; content: "\ec24";
transform: rotate(180deg); transform: rotate(180deg);
} }
/* 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 {
max-width: 25vw;
overflow: hidden;
text-overflow: ellipsis;
}
.revision-diff-added {
background: rgba(100, 200, 100, 0.5);
}
.revision-diff-removed {
background: rgba(255, 100, 100, 0.5);
text-decoration: line-through;
}

View File

@@ -1,16 +1,16 @@
:root { :root {
--theme-style: dark; --theme-style: dark;
--main-font-family: Montserrat, sans-serif; --main-font-family: Montserrat;
--main-font-size: normal; --main-font-size: normal;
--tree-font-family: Montserrat, sans-serif; --tree-font-family: Montserrat;
--tree-font-size: normal; --tree-font-size: normal;
--detail-font-family: Montserrat, sans-serif; --detail-font-family: Montserrat;
--detail-font-size: normal; --detail-font-size: normal;
--monospace-font-family: JetBrainsLight, monospace; --monospace-font-family: JetBrainsLight;
--monospace-font-size: normal; --monospace-font-size: normal;
--main-background-color: #333; --main-background-color: #333;

View File

@@ -5,16 +5,16 @@ html {
/* either light or dark, colored theme with darker tones are also dark, used e.g. for note map node colors */ /* either light or dark, colored theme with darker tones are also dark, used e.g. for note map node colors */
--theme-style: light; --theme-style: light;
--main-font-family: Montserrat, sans-serif; --main-font-family: Montserrat;
--main-font-size: normal; --main-font-size: normal;
--tree-font-family: Montserrat, sans-serif; --tree-font-family: Montserrat;
--tree-font-size: normal; --tree-font-size: normal;
--detail-font-family: Montserrat, sans-serif; --detail-font-family: Montserrat;
--detail-font-size: normal; --detail-font-size: normal;
--monospace-font-family: JetBrainsLight, monospace; --monospace-font-family: JetBrainsLight;
--monospace-font-size: normal; --monospace-font-size: normal;
--main-background-color: white; --main-background-color: white;

View File

@@ -13,13 +13,12 @@
--theme-style: dark; --theme-style: dark;
--native-titlebar-background: #00000000; --native-titlebar-background: #00000000;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: #272727; --main-background-color: #272727;
--main-text-color: #ccc; --main-text-color: #ccc;
--main-border-color: #454545; --main-border-color: #454545;
--subtle-border-color: #313131; --subtle-border-color: #313131;
--dropdown-border-color: #404040; --dropdown-border-color: #292929;
--dropdown-shadow-opacity: 0.6; --dropdown-shadow-opacity: 0.6;
--dropdown-item-icon-destructive-color: #de6e5b; --dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef; --disabled-tooltip-icon-color: #7fd2ef;
@@ -90,7 +89,6 @@
--menu-text-color: #e3e3e3; --menu-text-color: #e3e3e3;
--menu-background-color: #222222d9; --menu-background-color: #222222d9;
--menu-background-color-no-backdrop: #1b1b1b;
--menu-item-icon-color: #8c8c8c; --menu-item-icon-color: #8c8c8c;
--menu-item-disabled-opacity: 0.5; --menu-item-disabled-opacity: 0.5;
--menu-item-keyboard-shortcut-color: #ffffff8f; --menu-item-keyboard-shortcut-color: #ffffff8f;
@@ -122,8 +120,6 @@
--quick-search-focus-border: #80808095; --quick-search-focus-border: #80808095;
--quick-search-focus-background: #ffffff1f; --quick-search-focus-background: #ffffff1f;
--quick-search-focus-color: white; --quick-search-focus-color: white;
--quick-search-result-content-background: #0000004d;
--quick-search-result-highlight-color: #a4d995;
--left-pane-collapsed-border-color: #0009; --left-pane-collapsed-border-color: #0009;
--left-pane-background-color: #1f1f1f; --left-pane-background-color: #1f1f1f;
@@ -148,17 +144,14 @@
--launcher-pane-vert-button-hover-background: #ffffff1c; --launcher-pane-vert-button-hover-background: #ffffff1c;
--launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2); --launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.2);
--launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color); --launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-vert-background-color-bgfx: #00000026; /* When background effects enabled */
--launcher-pane-horiz-border-color: rgb(22, 22, 22); --launcher-pane-horiz-border-color: rgb(22, 22, 22);
--launcher-pane-horiz-background-color: #282828; --launcher-pane-horiz-background-color: #282828;
--launcher-pane-horiz-text-color: #b8b8b8; --launcher-pane-horiz-text-color: #909090;
--launcher-pane-horiz-button-hover-color: #ffffff; --launcher-pane-horiz-button-hover-color: #ffffff;
--launcher-pane-horiz-button-hover-background: #ffffff1c; --launcher-pane-horiz-button-hover-background: #ffffff1c;
--launcher-pane-horiz-button-hover-shadow: unset; --launcher-pane-horiz-button-hover-shadow: unset;
--launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color); --launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-horiz-background-color-bgfx: #ffffff17; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000080; /* When background effects enabled */
--protected-session-active-icon-color: #8edd8e; --protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871; --sync-status-error-pulse-color: #f47871;
@@ -172,10 +165,9 @@
--tab-close-button-hover-background: #a45353; --tab-close-button-hover-background: #a45353;
--tab-close-button-hover-color: white; --tab-close-button-hover-color: white;
--active-tab-background-color: #ffffff1c; --active-tab-background-color: #ffffff1c;
--active-tab-hover-background-color: var(--active-tab-background-color); --active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-icon-color: #a9a9a9;
--active-tab-text-color: #ffffffcd; --active-tab-text-color: #ffffffcd;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, 0.2), -1px -1px 3px rgba(0, 0, 0, 0.4); --active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, 0.2), -1px -1px 3px rgba(0, 0, 0, 0.4);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, 0.4); --active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, 0.4);

View File

@@ -13,7 +13,6 @@
--theme-style: light; --theme-style: light;
--native-titlebar-background: #ffffff00; --native-titlebar-background: #ffffff00;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: white; --main-background-color: white;
--main-text-color: black; --main-text-color: black;
@@ -84,7 +83,6 @@
--menu-text-color: #272727; --menu-text-color: #272727;
--menu-background-color: #ffffffd9; --menu-background-color: #ffffffd9;
--menu-background-color-no-backdrop: #fdfdfd;
--menu-item-icon-color: #727272; --menu-item-icon-color: #727272;
--menu-item-disabled-opacity: 0.6; --menu-item-disabled-opacity: 0.6;
--menu-item-keyboard-shortcut-color: #666666a8; --menu-item-keyboard-shortcut-color: #666666a8;
@@ -116,17 +114,15 @@
--quick-search-focus-border: #00000029; --quick-search-focus-border: #00000029;
--quick-search-focus-background: #ffffff80; --quick-search-focus-background: #ffffff80;
--quick-search-focus-color: #000; --quick-search-focus-color: #000;
--quick-search-result-content-background: #0000000f;
--quick-search-result-highlight-color: #c65050;
--left-pane-collapsed-border-color: #0000000d; --left-pane-collapsed-border-color: #0000000d;
--left-pane-background-color: #f2f2f2; --left-pane-background-color: #f2f2f2;
--left-pane-text-color: #383838; --left-pane-text-color: #383838;
--left-pane-item-hover-background: rgba(0, 0, 0, 0.032); --left-pane-item-hover-background: #eaeaea;
--left-pane-item-selected-background: white; --left-pane-item-selected-background: white;
--left-pane-item-selected-color: black; --left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); --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-background: #d7d7d7;
--left-pane-item-action-button-color: inherit; --left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white; --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-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, 0.15);
@@ -142,7 +138,6 @@
--launcher-pane-vert-button-hover-background: white; --launcher-pane-vert-button-hover-background: white;
--launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.075); --launcher-pane-vert-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, 0.075);
--launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color); --launcher-pane-vert-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-vert-background-color-bgfx: #00000009; /* When background effects enabled */
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.1); --launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.1);
--launcher-pane-horiz-background-color: #fafafa; --launcher-pane-horiz-background-color: #fafafa;
@@ -150,8 +145,6 @@
--launcher-pane-horiz-button-hover-background: var(--icon-button-hover-background); --launcher-pane-horiz-button-hover-background: var(--icon-button-hover-background);
--launcher-pane-horiz-button-hover-shadow: unset; --launcher-pane-horiz-button-hover-shadow: unset;
--launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color); --launcher-pane-horiz-button-focus-outline-color: var(--input-focus-outline-color);
--launcher-pane-horiz-background-color-bgfx: #ffffffb3; /* When background effects enabled */
--launcher-pane-horiz-border-color-bgfx: #00000026; /* When background effects enabled */
--protected-session-active-icon-color: #16b516; --protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528; --sync-status-error-pulse-color: #ff5528;
@@ -165,10 +158,9 @@
--tab-close-button-hover-background: #c95a5a; --tab-close-button-hover-background: #c95a5a;
--tab-close-button-hover-color: white; --tab-close-button-hover-color: white;
--active-tab-background-color: white; --active-tab-background-color: white;
--active-tab-hover-background-color: var(--active-tab-background-color); --active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-icon-color: gray;
--active-tab-text-color: black; --active-tab-text-color: black;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, 0.1), -1px -1px 3px rgba(0, 0, 0, 0.05); --active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, 0.1), -1px -1px 3px rgba(0, 0, 0, 0.05);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, 0.1); --active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, 0.1);

View File

@@ -26,7 +26,7 @@
--detail-font-family: var(--main-font-family); --detail-font-family: var(--main-font-family);
--detail-font-size: normal; --detail-font-size: normal;
--monospace-font-family: JetBrainsLight, monospace; --monospace-font-family: JetBrainsLight;
--monospace-font-size: normal; --monospace-font-size: normal;
--left-pane-item-selected-shadow-size: 2px; --left-pane-item-selected-shadow-size: 2px;
@@ -83,12 +83,6 @@
--tab-note-icons: true; --tab-note-icons: true;
} }
body.backdrop-effects-disabled {
/* Backdrop effects are disabled, replace the menu background color with the
* no-backdrop fallback color */
--menu-background-color: var(--menu-background-color-no-backdrop);
}
/* /*
* MENUS * MENUS
* *
@@ -102,6 +96,10 @@ body.backdrop-effects-disabled {
font-size: 0.9rem !important; font-size: 0.9rem !important;
} }
.dropdown-menu {
--scrollbar-background-color: var(--menu-background-color);
}
body.mobile .dropdown-menu { body.mobile .dropdown-menu {
backdrop-filter: var(--dropdown-backdrop-filter); backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius); border-radius: var(--dropdown-border-radius);
@@ -150,22 +148,12 @@ body.desktop .dropdown-submenu .dropdown-menu {
.dropdown-item, .dropdown-item,
body.mobile .dropdown-submenu .dropdown-toggle { body.mobile .dropdown-submenu .dropdown-toggle {
padding: 2px 2px 2px 8px !important; padding: 2px 2px 2px 8px !important;
padding-inline-end: 22px !important; padding-inline-end: 16px !important;
/* Note: the right padding should also accommodate the submenu arrow. */ /* Note: the right padding should also accommodate the submenu arrow. */
border-radius: 6px; border-radius: 6px;
cursor: default !important; cursor: default !important;
} }
:root .dropdown-item:focus-visible {
outline: 2px solid var(--input-focus-outline-color) !important;
background-color: transparent;
color: unset;
}
:root .dropdown-item:active {
background: unset;
}
body.mobile .dropdown-submenu { body.mobile .dropdown-submenu {
padding: 0 !important; padding: 0 !important;
} }
@@ -203,17 +191,13 @@ html body .dropdown-item[disabled] {
/* Menu item keyboard shortcut */ /* Menu item keyboard shortcut */
.dropdown-item kbd { .dropdown-item kbd {
margin-left: 16px;
font-family: unset !important; font-family: unset !important;
font-size: unset !important; font-size: unset !important;
color: var(--menu-item-keyboard-shortcut-color) !important; color: var(--menu-item-keyboard-shortcut-color) !important;
padding-top: 0; padding-top: 0;
} }
.dropdown-item span.keyboard-shortcut {
color: var(--menu-item-keyboard-shortcut-color) !important;
margin-left: 16px;
}
.dropdown-divider { .dropdown-divider {
position: relative; position: relative;
border-color: transparent !important; border-color: transparent !important;
@@ -295,20 +279,6 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
transform: rotate(270deg); transform: rotate(270deg);
} }
/* Dropdown item button (used in zoom buttons in global menu) */
li.dropdown-item a.dropdown-item-button {
border: unset;
}
li.dropdown-item a.dropdown-item-button.bx {
color: var(--menu-text-color) !important;
}
li.dropdown-item a.dropdown-item-button:focus-visible {
outline: 2px solid var(--input-focus-outline-color) !important;
}
/* /*
* TOASTS * TOASTS
*/ */
@@ -327,49 +297,28 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
--modal-control-button-color: var(--bs-toast-color); --modal-control-button-color: var(--bs-toast-color);
display: flex; display: flex;
flex-direction: column; flex-direction: row-reverse;
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
} }
#toast-container .toast .toast-header { #toast-container .toast .toast-header {
padding: 0 !important;
background: transparent !important; background: transparent !important;
border-bottom: none; border-bottom: none;
color: var(--toast-text-color) !important;
} }
#toast-container .toast .toast-header strong > * { #toast-container .toast .toast-header strong {
vertical-align: middle; /* The title of the toast is no longer displayed */
display: none;
} }
#toast-container .toast .toast-header .btn-close { #toast-container .toast .toast-header .btn-close {
margin: 0 0 0 12px; margin: 0 var(--bs-toast-padding-x) 0 12px;
}
#toast-container .toast.no-title {
flex-direction: row;
} }
#toast-container .toast .toast-body { #toast-container .toast .toast-body {
flex-grow: 1; flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
padding-top: 0;
}
#toast-container .toast:not(.no-title) .bx {
margin-right: 0.5em;
font-size: 1.1em;
opacity: 0.85;
}
#toast-container .toast.no-title .bx {
margin-right: 0;
font-size: 1.3em;
}
#toast-container .toast.no-title .toast-body {
padding-top: var(--bs-toast-padding-x);
color: var(--toast-text-color);
} }
/* /*
@@ -581,9 +530,10 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
} }
/* List item */ /* List item */
.jump-to-note-dialog .aa-suggestion, .jump-to-note-dialog .aa-suggestions div,
.note-detail-empty .aa-suggestion { .note-detail-empty .aa-suggestions div {
border-radius: 6px; border-radius: 6px;
padding: 6px 12px;
color: var(--menu-text-color); color: var(--menu-text-color);
cursor: default; cursor: default;
} }

View File

@@ -5,8 +5,7 @@
button.btn.btn-primary, button.btn.btn-primary,
button.btn.btn-secondary, button.btn.btn-secondary,
button.btn.btn-sm:not(.select-button), button.btn.btn-sm:not(.select-button),
button.btn.btn-success, button.btn.btn-success {
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -22,8 +21,7 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .c
button.btn.btn-primary:hover, button.btn.btn-primary:hover,
button.btn.btn-secondary:hover, button.btn.btn-secondary:hover,
button.btn.btn-sm:not(.select-button):hover, button.btn.btn-sm:not(.select-button):hover,
button.btn.btn-success:hover, button.btn.btn-success:hover {
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):hover {
background: var(--cmd-button-hover-background-color); background: var(--cmd-button-hover-background-color);
color: var(--cmd-button-hover-text-color); color: var(--cmd-button-hover-text-color);
} }
@@ -31,8 +29,7 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .c
button.btn.btn-primary:active, button.btn.btn-primary:active,
button.btn.btn-secondary:active, button.btn.btn-secondary:active,
button.btn.btn-sm:not(.select-button):active, button.btn.btn-sm:not(.select-button):active,
button.btn.btn-success:active, button.btn.btn-success:active {
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):active {
opacity: 0.85; opacity: 0.85;
box-shadow: unset; box-shadow: unset;
background: var(--cmd-button-background-color) !important; background: var(--cmd-button-background-color) !important;
@@ -43,16 +40,14 @@ button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .c
button.btn.btn-primary:disabled, button.btn.btn-primary:disabled,
button.btn.btn-secondary:disabled, button.btn.btn-secondary:disabled,
button.btn.btn-sm:not(.select-button):disabled, button.btn.btn-sm:not(.select-button):disabled,
button.btn.btn-success:disabled, button.btn.btn-success:disabled {
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text.ck-disabled {
opacity: var(--cmd-button-disabled-opacity); opacity: var(--cmd-button-disabled-opacity);
} }
button.btn.btn-primary:focus-visible, button.btn.btn-primary:focus-visible,
button.btn.btn-secondary:focus-visible, button.btn.btn-secondary:focus-visible,
button.btn.btn-sm:not(.select-button):focus-visible, button.btn.btn-sm:not(.select-button):focus-visible,
button.btn.btn-success:focus-visible, button.btn.btn-success:focus-visible {
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):focus-visible {
outline: 2px solid var(--input-focus-outline-color); outline: 2px solid var(--input-focus-outline-color);
} }
@@ -84,7 +79,7 @@ button.btn.btn-success kbd {
*/ */
:root .icon-action:not(.global-menu-button), :root .icon-action:not(.global-menu-button),
:root .tn-tool-button, :root .btn.tn-tool-button,
:root .btn-group .tn-tool-button:not(:last-child), :root .btn-group .tn-tool-button:not(:last-child),
:root .btn-group .tn-tool-button:last-child { :root .btn-group .tn-tool-button:last-child {
width: var(--icon-button-size); width: var(--icon-button-size);
@@ -96,11 +91,6 @@ button.btn.btn-success kbd {
color: var(--icon-button-color); color: var(--icon-button-color);
} }
:root .btn-group .icon-action:last-child {
border-top-left-radius: unset !important;
border-bottom-left-radius: unset !important;
}
.btn-group .tn-tool-button + .tn-tool-button { .btn-group .tn-tool-button + .tn-tool-button {
margin-left: 4px !important; margin-left: 4px !important;
} }
@@ -159,11 +149,8 @@ input[type="password"],
input[type="date"], input[type="date"],
input[type="time"], input[type="time"],
input[type="datetime-local"], input[type="datetime-local"],
:root input.ck.ck-input-text,
:root input.ck.ck-input-number,
textarea.form-control, textarea.form-control,
textarea, textarea,
:root textarea.ck.ck-textarea,
.tn-input-field { .tn-input-field {
outline: 3px solid transparent; outline: 3px solid transparent;
outline-offset: 6px; outline-offset: 6px;
@@ -180,11 +167,8 @@ input[type="password"]:hover,
input[type="date"]:hover, input[type="date"]:hover,
input[type="time"]:hover, input[type="time"]:hover,
input[type="datetime-local"]:hover, input[type="datetime-local"]:hover,
:root input.ck.ck-input-text:not([readonly="true"]):hover,
:root input.ck.ck-input-number:not([readonly="true"]):hover,
textarea.form-control:hover, textarea.form-control:hover,
textarea:hover, textarea:hover,
:root textarea.ck.ck-textarea:hover,
.tn-input-field:hover { .tn-input-field:hover {
background: var(--input-hover-background); background: var(--input-hover-background);
color: var(--input-hover-color); color: var(--input-hover-color);
@@ -197,11 +181,8 @@ input[type="password"]:focus,
input[type="date"]:focus, input[type="date"]:focus,
input[type="time"]:focus, input[type="time"]:focus,
input[type="datetime-local"]:focus, input[type="datetime-local"]:focus,
:root input.ck.ck-input-text:not([readonly="true"]):focus,
:root input.ck.ck-input-number:not([readonly="true"]):focus,
textarea.form-control:focus, textarea.form-control:focus,
textarea:focus, textarea:focus,
:root textarea.ck.ck-textarea:focus,
.tn-input-field:focus, .tn-input-field:focus,
.tn-input-field:focus-within { .tn-input-field:focus-within {
box-shadow: unset; box-shadow: unset;
@@ -474,7 +455,6 @@ optgroup {
left: 0; left: 0;
width: var(--box-size); width: var(--box-size);
height: 100%; height: 100%;
margin: unset;
opacity: 0 !important; opacity: 0 !important;
} }

View File

@@ -4,7 +4,6 @@
:root { :root {
--ck-font-face: var(--main-font-family); --ck-font-face: var(--main-font-family);
--ck-input-label-height: 1.5em;
} }
/* /*
@@ -308,11 +307,6 @@
fill: black !important; fill: black !important;
} }
/* Hex color input box prefix */
:root .ck.ck-color-selector .ck-color-picker__hash-view {
margin-top: var(--ck-input-label-height);
}
/* Numbered list */ /* Numbered list */
:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list { :root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list {
@@ -369,86 +363,19 @@
color: var(--accent); color: var(--accent);
} }
/* Text snippet dropdown */ /* Action buttons */
div.ck-template-form { :root .ck-link-actions button.ck-button,
padding: 8px; :root .ck-link-form button.ck-button {
--ck-border-radius: 6px;
background: transparent;
box-shadow: unset;
} }
div.ck-template-form .ck-labeled-field-view { :root .ck-link-actions button.ck-button:hover,
margin-bottom: 8px; :root .ck-link-form button.ck-button:hover {
} background: var(--hover-item-background-color);
/* Template item */
:root div.ck-template-form li.ck-list__item button.ck-template-button {
padding: 4px 8px;
}
/* Template icon */
:root .ck-template-form .ck-button__icon {
--ck-spacing-medium: 2px;
}
:root div.ck-template-form .note-icon {
color: var(--menu-item-icon-color);
}
/* Template name */
div.ck-template-form .ck-template-form__text-part {
color: var(--hover-item-text-color);
font-size: .9rem;
}
div.ck-template-form .ck-template-form__text-part mark {
background: unset;
color: var(--quick-search-result-highlight-color);
font-weight: bold;
}
/* Template description */
:root div.ck-template-form .ck-template-form__description {
opacity: .5;
font-size: .9em;
}
/* Messages */
div.ck-template-form .ck-search__info > span {
line-height: initial;
color: var(--muted-text-color);
}
div.ck-template-form .ck-search__info span:nth-child(2) {
display: block;
opacity: .5;
margin-top: 8px;
font-size: .9em;
}
/* Link dropdown */
:root .ck.ck-form.ck-link-form ul.ck-link-form__providers-list {
border-top: none;
}
/* Math popup */
.ck-math-form .ck-labeled-field-view {
--ck-input-label-height: 0;
margin-inline-end: 8px;
}
/* Emoji dropdown */
.ck-emoji-picker-form .ck-emoji__search .ck-button_with-text:not(.ck-list-item-button) {
margin-top: var(--ck-input-label-height);
}
/* Find and replace dialog */
.ck-find-and-replace-form .ck-find-and-replace-form__inputs button {
margin-top: var(--ck-input-label-height);
} }
/* Mention list (the autocompletion list for emojis, labels and relations) */ /* Mention list (the autocompletion list for emojis, labels and relations) */
@@ -465,58 +392,6 @@ div.ck-template-form .ck-search__info span:nth-child(2) {
background: transparent; background: transparent;
} }
/*
* FORMS
*/
/*
* Buttons
*/
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck-button_with-text {
--ck-color-text: var(--cmd-button-text-color);
min-width: 60px;
font-weight: 500;
}
/*
* Text boxes
*/
.ck.ck-labeled-field-view {
padding-top: var(--ck-input-label-height) !important; /* Create space for the label */
}
.ck.ck-labeled-field-view > .ck.ck-labeled-field-view__input-wrapper > label.ck.ck-label {
/* 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-left: 0 !important;
background: transparent;
font-size: .85em;
font-weight: 600;
}
:root input.ck.ck-input-text[readonly="true"] {
cursor: not-allowed;
background: var(--input-background-color);
}
/* Forms */
:root .ck.ck-form__row.ck-form__row_with-submit > :not(:first-child) {
margin-inline-start: 16px;
}
.ck.ck-form__row_with-submit button {
margin-top: var(--ck-input-label-height);
}
.ck.ck-form__header {
border-bottom: none;
}
/* /*
* EDITOR'S CONTENT * EDITOR'S CONTENT
*/ */

View File

@@ -96,6 +96,7 @@
background: var(--background) !important; background: var(--background) !important;
color: var(--color) !important; color: var(--color) !important;
line-height: unset; line-height: unset;
cursor: help;
} }
.sql-table-schemas-widget .sql-table-schemas button:hover, .sql-table-schemas-widget .sql-table-schemas button:hover,
@@ -105,15 +106,22 @@
--color: var(--main-text-color); --color: var(--main-text-color);
} }
/* Tooltip */
.tooltip .table-schema {
font-family: var(--monospace-font-family);
font-size: .85em;
}
/* Data type */
.tooltip .table-schema td:nth-child(2) {
color: var(--muted-text-color);
}
/* /*
* NOTE MAP * NOTE MAP
*/ */
.note-detail-note-map .fixnodes-type-switcher .tn-tool-button,
.note-map-widget .fixnodes-type-switcher .tn-tool-button {
padding: unset;
}
.note-detail-note-map .fixnodes-type-switcher .tn-tool-button.toggled { .note-detail-note-map .fixnodes-type-switcher .tn-tool-button.toggled {
color: var(--tab-close-button-hover-background); color: var(--tab-close-button-hover-background);
} }

View File

@@ -94,17 +94,18 @@ div.promoted-attributes-container {
/* Note type dropdown */ /* Note type dropdown */
ul.note-type-dropdown .check { div.note-type-dropdown .check {
margin-right: 6px; margin-right: 6px;
} }
ul.note-type-dropdown li.dropdown-item {
--menu-item-icon-vert-offset: 0;
}
/* Editability dropdown */ /* Editability dropdown */
ul.editability-dropdown li.dropdown-item > div { div.editability-dropdown a.dropdown-item {
padding: 4px 16px 4px 0;
align-items: start !important;
}
.editability-dropdown .dropdown-item .check {
margin-left: 4px; margin-left: 4px;
} }

View File

@@ -36,23 +36,32 @@ body.mobile {
/* #region Mica */ /* #region Mica */
body.background-effects.platform-win32 { body.background-effects.platform-win32 {
--background-material: tabbed; --launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.15);
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx); --launcher-pane-horiz-background-color: rgba(255, 255, 255, 0.7);
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx); --launcher-pane-vert-background-color: rgba(255, 255, 255, 0.055);
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx); --tab-background-color: transparent;
--tab-background-color: var(--window-background-color-bgfx); --new-tab-button-background: transparent;
--new-tab-button-background: var(--window-background-color-bgfx);
--active-tab-background-color: var(--launcher-pane-horiz-background-color); --active-tab-background-color: var(--launcher-pane-horiz-background-color);
--background-material: tabbed;
}
@media (prefers-color-scheme: dark) {
body.background-effects.platform-win32 {
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.5);
--launcher-pane-horiz-background-color: rgba(255, 255, 255, 0.09);
}
} }
body.background-effects.platform-win32.layout-vertical { body.background-effects.platform-win32.layout-vertical {
--left-pane-background-color: var(--window-background-color-bgfx); --left-pane-background-color: transparent;
--left-pane-item-hover-background: rgba(127, 127, 127, 0.05);
--background-material: mica; --background-material: mica;
} }
body.background-effects.platform-win32, body.background-effects.platform-win32,
body.background-effects.platform-win32 #root-widget { body.background-effects.platform-win32 #root-widget,
background: var(--window-background-color-bgfx) !important; body.background-effects.platform-win32 #launcher-pane .launcher-button {
background: transparent !important;
} }
body.background-effects.platform-win32.layout-horizontal #horizontal-main-container, body.background-effects.platform-win32.layout-horizontal #horizontal-main-container,
@@ -81,7 +90,7 @@ body.background-effects.zen #root-widget {
* Gutter * Gutter
*/ */
.gutter { .gutter {
background: var(--gutter-color) !important; background: var(--gutter-color) !important;
transition: background 150ms ease-out; transition: background 150ms ease-out;
} }
@@ -223,7 +232,7 @@ body.layout-horizontal > .horizontal {
} }
#launcher-pane .launcher-button:focus, #launcher-pane .launcher-button:focus,
#launcher-pane .global-menu :focus { #launcher-pane .global-menu button:focus {
outline: none; outline: none;
} }
@@ -304,11 +313,24 @@ body.layout-horizontal > .horizontal {
color: var(--tooltip-foreground-color) !important; color: var(--tooltip-foreground-color) !important;
} }
/*
* Global menu
*/
.global-menu div.zoom-buttons a {
border: unset;
}
.global-menu div.zoom-buttons a.bx {
color: var(--menu-text-color) !important;
}
/* /*
* Calendar * Calendar
*/ */
.calendar-dropdown-widget { .calendar-dropdown-widget {
width: unset !important;
padding: 12px; padding: 12px;
color: var(--calendar-color); color: var(--calendar-color);
user-select: none; user-select: none;
@@ -336,21 +358,6 @@ body.layout-horizontal > .horizontal {
--select-arrow-svg: initial; /* Disable the dropdown arrow */ --select-arrow-svg: initial; /* Disable the dropdown arrow */
} }
/* Week number column */
.calendar-dropdown-widget .calendar-week-number {
transform: rotate(270deg);
justify-content: center;
padding: 0;
opacity: 0.5;
font-size: 1em;
font-weight: 700;
letter-spacing: .5pt;
}
.calendar-dropdown-widget .calendar-week-number::after {
display: none;
}
@media (max-width: 992px) { @media (max-width: 992px) {
.calendar-dropdown-widget .calendar-header button { .calendar-dropdown-widget .calendar-header button {
margin: 0 !important; margin: 0 !important;
@@ -565,28 +572,29 @@ div.quick-search .search-button.show {
transition: background-color 100ms ease-out !important; transition: background-color 100ms ease-out !important;
} }
div.quick-search .dropdown-menu {
--quick-search-item-delimiter-color: transparent;
--menu-item-icon-vert-offset: -.065em;
}
/* /*
* TO FIX: The quick search results dropdown has a backdrop issue with the tree panel * Quick search results
* when background effects are enabled in Electron.
* As a temporary workaround, the backdrop and transparency are disabled for the
* vertical layout.
*/ */
body.layout-vertical.background-effects div.quick-search .dropdown-menu {
--menu-background-color: var(--menu-background-color-no-backdrop) !important;
}
/* Item */ /* Item */
.quick-search .dropdown-menu *.dropdown-item { .quick-search .dropdown-menu *.dropdown-item {
padding: 8px 12px !important; padding: 8px 12px !important;
} }
.quick-search .quick-search-item-icon { /* Note icon */
vertical-align: text-bottom; .quick-search .dropdown-menu .dropdown-item > .bx {
position: relative;
top: 1px;
}
/* Note title */
.quick-search .dropdown-menu .dropdown-item > a {
color: var(--menu-text-color);
}
.quick-search .dropdown-menu .dropdown-item > a:hover {
--hover-item-background-color: transparent;
text-decoration: underline;
} }
/* Note path */ /* Note path */
@@ -597,24 +605,6 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
overflow: hidden; overflow: hidden;
} }
/* Note content snippet */
:root .quick-search .search-result-content {
background-color: var(--quick-search-result-content-background);
border-radius: 4px;
}
/* Highlighted search terms */
:root .quick-search .search-result-title b,
:root .quick-search .search-result-content b,
:root .quick-search .search-result-attributes b {
color: var(--quick-search-result-highlight-color);
font-weight: 600;
}
.quick-search div.dropdown-divider {
margin: 8px 0;
}
/* /*
* TREE PANE * TREE PANE
*/ */
@@ -875,10 +865,7 @@ body.mobile .fancytree-node > span {
} }
.tab-row-container .toggle-button { .tab-row-container .toggle-button {
--icon-button-size: 30px; margin: 6px 10px !important;
--icon-button-icon-ratio: .6;
margin: 3px 6px auto 8px !important;
} }
.tab-row-container { .tab-row-container {
@@ -890,80 +877,6 @@ body.layout-horizontal .tab-row-container {
border-bottom: 1px solid var(--launcher-pane-horiz-border-color); border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
} }
body.electron.background-effects.layout-horizontal .tab-row-container {
border-bottom: unset !important;
}
body.electron.background-effects.layout-horizontal .note-tab-wrapper {
top: 1px;
}
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button {
position: relative;
}
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button:after {
content: "";
position: absolute;
bottom: 0;
left: -10px;
right: -10px;
top: 32px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left,
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right {
position: relative;
}
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;
left: 0px;
right: 0px;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:before {
content: "";
position: absolute;
bottom: 0;
left: -32768px;
top: var(--tab-height);
right: calc(100% - 1px);
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:after {
content: "";
position: absolute;
bottom: 0;
left: 100%;
top: var(--tab-height);
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.electron.background-effects.layout-horizontal .tab-row-container .note-new-tab:before {
content: "";
position: absolute;
bottom: 0;
left: -4px;
top: calc(var(--tab-height), -1);
right: 0;
width: 100vw;
height: 1px;
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
}
body.layout-vertical.electron.platform-darwin .tab-row-container { body.layout-vertical.electron.platform-darwin .tab-row-container {
border-bottom: 1px solid var(--subtle-border-color); border-bottom: 1px solid var(--subtle-border-color);
} }
@@ -1055,14 +968,6 @@ body.layout-horizontal .tab-row-widget .note-tab .note-tab-wrapper {
transform: translate3d(var(--tab-first-item-horiz-offset), 0, 0); transform: translate3d(var(--tab-first-item-horiz-offset), 0, 0);
} }
:root .tab-row-widget .note-tab .note-tab-icon {
padding-right: 5px; /* The gap between the icon and the title */
}
.tab-row-widget .note-tab[active] .note-tab-icon {
color: var(--active-tab-icon-color);
}
.tab-row-widget .note-tab .note-tab-title { .tab-row-widget .note-tab .note-tab-title {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@@ -1187,11 +1092,6 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
/* will-change: opacity; -- causes some weird artifacts to the note menu in split view */ /* will-change: opacity; -- causes some weird artifacts to the note menu in split view */
} }
.split-note-container-widget > .gutter {
background: var(--root-background) !important;
transition: background 150ms ease-out;
}
/* /*
* Ribbon & note header * Ribbon & note header
*/ */
@@ -1200,6 +1100,10 @@ body.layout-vertical .tab-row-widget-is-sorting .note-tab.note-tab-is-dragging .
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.note-split:not(.hidden-ext) + .note-split:not(.hidden-ext) {
border-left: 4px solid var(--root-background);
}
@keyframes note-entrance { @keyframes note-entrance {
from { from {
opacity: 0; opacity: 0;
@@ -1410,13 +1314,6 @@ div.promoted-attribute-cell .multiplicity:has(span) {
margin-left: 8px; margin-left: 8px;
margin-right: calc(var(--pa-card-padding-left) - var(--pa-card-padding-right)); margin-right: calc(var(--pa-card-padding-left) - var(--pa-card-padding-right));
font-size: 0; /* Prevent whitespaces creating a gap between buttons */ font-size: 0; /* Prevent whitespaces creating a gap between buttons */
display: flex;
}
div.promoted-attribute-cell .multiplicity:has(span) span {
display: flex;
align-items: center;
justify-content: center;
} }
/* /*
@@ -1478,7 +1375,7 @@ div.floating-buttons-children .floating-button:active {
} }
/* The first visible floating button */ /* The first visible floating button */
div.floating-buttons-children > *:first-child { div.floating-buttons-children > *:nth-child(1 of .visible) {
--border-radius: var(--border-radius-size) 0 0 var(--border-radius-size); --border-radius: var(--border-radius-size) 0 0 var(--border-radius-size);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
@@ -1580,6 +1477,13 @@ div.floating-buttons-children .close-floating-buttons:has(.close-floating-button
padding-inline-start: 8px; padding-inline-start: 8px;
} }
/* Copy image reference */
.floating-buttons .copy-image-reference-button .hidden-image-copy {
/* Take out of the the hidden image from flexbox to prevent the layout being affected */
position: absolute;
}
/* Code, relation map buttons */ /* Code, relation map buttons */
.floating-buttons .code-buttons-widget, .floating-buttons .code-buttons-widget,

View File

@@ -1,5 +0,0 @@
{
"about": {
"title": "حول تريليوم للملاحظات"
}
}

View File

@@ -121,7 +121,7 @@
"sat": "Ds", "sat": "Ds",
"sun": "Dg", "sun": "Dg",
"january": "Gener", "january": "Gener",
"february": "Febrer", "febuary": "Febrer",
"march": "Març", "march": "Març",
"april": "Abril", "april": "Abril",
"may": "Maig", "may": "Maig",

View File

@@ -276,12 +276,7 @@
"mime": "MIME 类型: ", "mime": "MIME 类型: ",
"file_size": "文件大小:", "file_size": "文件大小:",
"preview": "预览:", "preview": "预览:",
"preview_not_available": "无法预览此类型的笔记。", "preview_not_available": "无法预览此类型的笔记。"
"diff_on": "显示差异",
"diff_off": "显示内容",
"diff_on_hint": "点击以显示笔记源代码差异",
"diff_off_hint": "点击以显示笔记内容",
"diff_not_available": "差异不可用。"
}, },
"sort_child_notes": { "sort_child_notes": {
"sort_children_by": "按...排序子笔记", "sort_children_by": "按...排序子笔记",
@@ -582,7 +577,7 @@
"cannot_find_day_note": "无法找到日记", "cannot_find_day_note": "无法找到日记",
"cannot_find_week_note": "无法找到周记", "cannot_find_week_note": "无法找到周记",
"january": "一月", "january": "一月",
"february": "二月", "febuary": "二月",
"march": "三月", "march": "三月",
"april": "四月", "april": "四月",
"may": "五月", "may": "五月",
@@ -592,18 +587,7 @@
"september": "九月", "september": "九月",
"october": "十月", "october": "十月",
"november": "十一月", "november": "十一月",
"december": "十二月", "december": "十二月"
"week_previous": "上周",
"week_next": "下周",
"month_previous": "上个月",
"month_next": "下个月",
"year": "年",
"year_previous": "上一年",
"year_next": "明年",
"today": "今天",
"week": "周",
"month": "月",
"list": "列表"
}, },
"close_pane_button": { "close_pane_button": {
"close_this_pane": "关闭此面板" "close_this_pane": "关闭此面板"
@@ -748,8 +732,7 @@
"note_type": "笔记类型", "note_type": "笔记类型",
"editable": "可编辑", "editable": "可编辑",
"basic_properties": "基本属性", "basic_properties": "基本属性",
"language": "语言", "language": "语言"
"configure_code_notes": "配置代码注释..."
}, },
"book_properties": { "book_properties": {
"view_type": "视图类型", "view_type": "视图类型",
@@ -764,8 +747,7 @@
"book_properties": "集合属性", "book_properties": "集合属性",
"table": "表格", "table": "表格",
"geo-map": "地理地图", "geo-map": "地理地图",
"board": "看板", "board": "看板"
"include_archived_notes": "展示归档笔记"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "今天还没有编辑过的笔记...", "no_edited_notes_found": "今天还没有编辑过的笔记...",
@@ -866,7 +848,7 @@
"debug": "调试", "debug": "调试",
"debug_description": "调试将打印额外的调试信息到控制台,以帮助调试复杂查询", "debug_description": "调试将打印额外的调试信息到控制台,以帮助调试复杂查询",
"action": "操作", "action": "操作",
"search_button": "搜索", "search_button": "搜索 <kbd>回车</kbd>",
"search_execute": "搜索并执行操作", "search_execute": "搜索并执行操作",
"save_to_note": "保存到笔记", "save_to_note": "保存到笔记",
"search_parameters": "搜索参数", "search_parameters": "搜索参数",
@@ -966,9 +948,7 @@
"no_attachments": "此笔记没有附件。" "no_attachments": "此笔记没有附件。"
}, },
"book": { "book": {
"no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> 了解详情。", "no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> 了解详情。"
"drag_locked_title": "锁定编辑",
"drag_locked_message": "无法拖拽,因为集合已被锁定编辑。"
}, },
"editable_code": { "editable_code": {
"placeholder": "在这里输入您的代码笔记内容..." "placeholder": "在这里输入您的代码笔记内容..."
@@ -1353,7 +1333,7 @@
"oauth_title": "OAuth/OpenID 认证", "oauth_title": "OAuth/OpenID 认证",
"oauth_description": "OpenID 是一种标准化方式,允许您使用其他服务(如 Google的账号登录网站来验证您的身份。默认的身份提供者是 Google但您可以更改为任何其他 OpenID 提供者。点击<a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">这里</a>了解更多信息。请参阅这些 <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">指南</a> 通过 Google 设置 OpenID 服务。", "oauth_description": "OpenID 是一种标准化方式,允许您使用其他服务(如 Google的账号登录网站来验证您的身份。默认的身份提供者是 Google但您可以更改为任何其他 OpenID 提供者。点击<a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">这里</a>了解更多信息。请参阅这些 <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">指南</a> 通过 Google 设置 OpenID 服务。",
"oauth_description_warning": "要启用 OAuth/OpenID您需要设置 config.ini 文件中的 OAuth/OpenID 基础 URL、客户端 ID 和客户端密钥,并重新启动应用程序。如果要从环境变量设置,请设置 TRILIUM_OAUTH_BASE_URL、TRILIUM_OAUTH_CLIENT_ID 和 TRILIUM_OAUTH_CLIENT_SECRET 环境变量。", "oauth_description_warning": "要启用 OAuth/OpenID您需要设置 config.ini 文件中的 OAuth/OpenID 基础 URL、客户端 ID 和客户端密钥,并重新启动应用程序。如果要从环境变量设置,请设置 TRILIUM_OAUTH_BASE_URL、TRILIUM_OAUTH_CLIENT_ID 和 TRILIUM_OAUTH_CLIENT_SECRET 环境变量。",
"oauth_missing_vars": "缺少以下设置项:{{-variables}}", "oauth_missing_vars": "缺少以下设置项:{{variables}}",
"oauth_user_account": "用户账号: ", "oauth_user_account": "用户账号: ",
"oauth_user_email": "用户邮箱: ", "oauth_user_email": "用户邮箱: ",
"oauth_user_not_logged_in": "未登录!" "oauth_user_not_logged_in": "未登录!"
@@ -1426,7 +1406,7 @@
"button-tree-map": "树形地图" "button-tree-map": "树形地图"
}, },
"tree-context-menu": { "tree-context-menu": {
"open-in-a-new-tab": "在新标签页中打开", "open-in-a-new-tab": "在新标签页中打开 <kbd>Ctrl+Click</kbd>",
"open-in-a-new-split": "在新分栏中打开", "open-in-a-new-split": "在新分栏中打开",
"insert-note-after": "在后面插入笔记", "insert-note-after": "在后面插入笔记",
"insert-child-note": "插入子笔记", "insert-child-note": "插入子笔记",
@@ -1456,14 +1436,12 @@
"converted-to-attachments": "{{count}} 个笔记已被转换为附件。", "converted-to-attachments": "{{count}} 个笔记已被转换为附件。",
"convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?", "convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?",
"duplicate": "复制", "duplicate": "复制",
"open-in-popup": "快速编辑", "open-in-popup": "快速编辑"
"archive": "归档",
"unarchive": "解压"
}, },
"shared_info": { "shared_info": {
"help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。", "shared_publicly": "此笔记已公开分享于",
"shared_publicly": "笔记已在 {{- link}} 上公开分享", "shared_locally": "笔记已在本地分享",
"shared_locally": "此笔记在本地通过 {{- link}} 进行共享。" "help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。"
}, },
"note_types": { "note_types": {
"text": "文本", "text": "文本",
@@ -1541,8 +1519,7 @@
"hoist-this-note-workspace": "聚焦此笔记(工作区)", "hoist-this-note-workspace": "聚焦此笔记(工作区)",
"refresh-saved-search-results": "刷新保存的搜索结果", "refresh-saved-search-results": "刷新保存的搜索结果",
"create-child-note": "创建子笔记", "create-child-note": "创建子笔记",
"unhoist": "取消聚焦", "unhoist": "取消聚焦"
"toggle-sidebar": "切换侧边栏"
}, },
"title_bar_buttons": { "title_bar_buttons": {
"window-on-top": "保持此窗口置顶" "window-on-top": "保持此窗口置顶"
@@ -1623,9 +1600,7 @@
"ws": { "ws": {
"sync-check-failed": "同步检查失败!", "sync-check-failed": "同步检查失败!",
"consistency-checks-failed": "一致性检查失败!请查看日志了解详细信息。", "consistency-checks-failed": "一致性检查失败!请查看日志了解详细信息。",
"encountered-error": "遇到错误 \"{{message}}\",请查看控制台。", "encountered-error": "遇到错误 \"{{message}}\",请查看控制台。"
"lost-websocket-connection-title": "与服务器的连线中断",
"lost-websocket-connection-message": "检查您的反向代理(如 nginx 或 Apache设置以确保 Websocket 连线没有被阻挡。"
}, },
"hoisted_note": { "hoisted_note": {
"confirm_unhoisting": "请求的笔记 '{{requestedNote}}' 位于聚焦的笔记 '{{hoistedNote}}' 的子树之外,您必须取消聚焦才能访问该笔记。是否继续取消聚焦?" "confirm_unhoisting": "请求的笔记 '{{requestedNote}}' 位于聚焦的笔记 '{{hoistedNote}}' 的子树之外,您必须取消聚焦才能访问该笔记。是否继续取消聚焦?"
@@ -1701,7 +1676,7 @@
"native-title-bar": "原生标题栏", "native-title-bar": "原生标题栏",
"native-title-bar-description": "对于 Windows 和 macOS关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。", "native-title-bar-description": "对于 Windows 和 macOS关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。",
"background-effects": "启用背景效果(仅适用于 Windows 11", "background-effects": "启用背景效果(仅适用于 Windows 11",
"background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。", "background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。",
"restart-app-button": "重启应用程序以查看更改", "restart-app-button": "重启应用程序以查看更改",
"zoom-factor": "缩放系数" "zoom-factor": "缩放系数"
}, },
@@ -1896,12 +1871,7 @@
"selected_provider": "已选提供商", "selected_provider": "已选提供商",
"selected_provider_description": "选择用于聊天和补全功能的AI提供商", "selected_provider_description": "选择用于聊天和补全功能的AI提供商",
"select_model": "选择模型...", "select_model": "选择模型...",
"select_provider": "选择提供商...", "select_provider": "选择提供商..."
"ai_enabled": "已启用 AI 功能",
"ai_disabled": "已禁用 AI 功能",
"no_models_found_online": "找不到模型。请检查您的 API 密钥及设置。",
"no_models_found_ollama": "找不到 Ollama 模型。请确认 Ollama 是否正在运行。",
"error_fetching": "获取模型失败:{{error}}"
}, },
"code-editor-options": { "code-editor-options": {
"title": "编辑器" "title": "编辑器"
@@ -1954,11 +1924,7 @@
"editorfeatures": { "editorfeatures": {
"title": "功能", "title": "功能",
"emoji_completion_enabled": "启用表情自动补全", "emoji_completion_enabled": "启用表情自动补全",
"note_completion_enabled": "启用笔记自动补全", "note_completion_enabled": "启用笔记自动补全"
"emoji_completion_description": "如果启用,表情可以轻易地经由输入 `:` 加上表情名称来插入。",
"note_completion_description": "如果启用,导向笔记的链接可以经由输入 `@` 加上笔记标题来创建。",
"slash_commands_enabled": "启用斜杠命令",
"slash_commands_description": "如果启用,可以经由输入 `/` 来触发命令,如插入换行符或标题。"
}, },
"table_view": { "table_view": {
"new-row": "新增行", "new-row": "新增行",
@@ -1994,21 +1960,14 @@
"delete_row": "删除行" "delete_row": "删除行"
}, },
"board_view": { "board_view": {
"delete-note": "删除笔记...", "delete-note": "删除笔记",
"move-to": "移动到", "move-to": "移动到",
"insert-above": "在上方插入", "insert-above": "在上方插入",
"insert-below": "在下方插入", "insert-below": "在下方插入",
"delete-column": "删除列", "delete-column": "删除列",
"delete-column-confirmation": "确定要删除此列吗?此列下所有笔记中对应的属性也将被删除。", "delete-column-confirmation": "确定要删除此列吗?此列下所有笔记中对应的属性也将被删除。",
"new-item": "新增项目", "new-item": "新增项目",
"add-column": "添加列", "add-column": "添加列"
"archive-note": "存档笔记",
"unarchive-note": "解压笔记",
"new-item-placeholder": "输入笔记标题...",
"add-column-placeholder": "请输入列名...",
"edit-note-title": "点击编辑笔记标题",
"edit-column-title": "点击编辑列标题",
"remove-from-board": "从看板上移除"
}, },
"command_palette": { "command_palette": {
"tree-action-name": "树形:{{name}}", "tree-action-name": "树形:{{name}}",
@@ -2040,30 +1999,5 @@
"next_theme_message": "当前使用旧版主题,要试用新主题吗?", "next_theme_message": "当前使用旧版主题,要试用新主题吗?",
"next_theme_button": "试用新主题", "next_theme_button": "试用新主题",
"dismiss": "关闭" "dismiss": "关闭"
},
"settings": {
"related_settings": "相关设置"
},
"settings_appearance": {
"related_code_blocks": "文本笔记中代码块的色彩方案",
"related_code_notes": "代码笔记的色彩方案"
},
"units": {
"percentage": "%"
},
"ui-performance": {
"title": "性能",
"enable-motion": "启用过渡和动画",
"enable-shadows": "启用阴影",
"enable-backdrop-effects": "启用菜单、弹窗和面板的背景效果",
"enable-smooth-scroll": "启用平滑滚动",
"app-restart-required": "(需重启程序以应用更改)"
},
"pagination": {
"page_title": "第 {{startIndex}} 页 - 第 {{endIndex}} 页",
"total_notes": "{{count}} 笔记"
},
"collections": {
"rendering_error": "出现错误无法显示内容。"
} }
} }

View File

@@ -1,41 +0,0 @@
{
"about": {
"title": "O Trilium Notes",
"homepage": "Domovská stránka:",
"app_version": "Verze aplikace:",
"db_version": "Verze DB:",
"sync_version": "Verze sync:",
"build_date": "Datum sestavení:",
"build_revision": "Revize sestavení:",
"data_directory": "Datový adresář:"
},
"toast": {
"critical-error": {
"title": "Kritická chyba",
"message": "Nastala kritická chyba která aplikaci brání ve spuštění:\n\n{{message}}\n\nPravděpodobně neočekávaným způsobem selhal skript. Pokuste se restartovat aplikaci v safe módu a problém napravit."
},
"widget-error": {
"title": "Nepodařilo se inicializovat widget",
"message-custom": "Uživatelský widget z poznámky s ID \"{{id}}\" a názvem \"{{title}}\" nemohl být inicializován z důvodu: \n\n{{message}}",
"message-unknown": "Neznámý widget nemohl být inicializován z důvodu:\n\n{{message}}"
},
"bundle-error": {
"title": "Načtení uživatelského skriptu selhalo",
"message": "Uživatelský skript z poznámky s ID \"{{id}}\" a názvem \"{{title}}\" nemohl být spuštěn z důvodu: \n\n{{message}}"
}
},
"ai_llm": {
"n_notes_queued_0": "{{ count }} poznámka ve frontě k indexaci",
"n_notes_queued_1": "{{ count }} poznámky ve frontě k indexaci",
"n_notes_queued_2": "{{ count }} poznámek ve frontě k indexaci",
"notes_indexed_0": "{{ count }} poznámka indexována",
"notes_indexed_1": "{{ count }} poznámky indexovány",
"notes_indexed_2": "{{ count }} poznámek indexováno"
},
"add_link": {
"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"
}
}

View File

@@ -202,12 +202,11 @@
"okButton": "OK" "okButton": "OK"
}, },
"jump_to_note": { "jump_to_note": {
"search_button": "Suche im Volltext", "search_button": "Suche im Volltext"
"search_placeholder": "Suche nach Notiz anhand ihres Titels oder gib > ein für Kommandos..."
}, },
"markdown_import": { "markdown_import": {
"dialog_title": "Markdown-Import", "dialog_title": "Markdown-Import",
"modal_body_text": "Aufgrund der Browser-Sandbox ist es nicht möglich, die Zwischenablage direkt aus JavaScript zu lesen. Bitte füge den zu importierenden Markdown in den Textbereich unten ein und klicke auf die Schaltfläche „Importieren“", "modal_body_text": "Aufgrund der Browser-Sandbox ist es nicht möglich, die Zwischenablage direkt aus JavaScript zu lesen. Bitte füge den zu importierenden Markdown in den Textbereich unten ein und klicke auf die Schaltfläche „Importieren“.",
"import_button": "Importieren", "import_button": "Importieren",
"import_success": "Markdown-Inhalt wurde in das Dokument importiert." "import_success": "Markdown-Inhalt wurde in das Dokument importiert."
}, },
@@ -218,26 +217,21 @@
"search_placeholder": "Suche nach einer Notiz anhand ihres Namens", "search_placeholder": "Suche nach einer Notiz anhand ihres Namens",
"move_button": "Zur ausgewählten Notiz wechseln", "move_button": "Zur ausgewählten Notiz wechseln",
"error_no_path": "Kein Weg, auf den man sich bewegen kann.", "error_no_path": "Kein Weg, auf den man sich bewegen kann.",
"move_success_message": "Ausgewählte Notizen wurden verschoben in " "move_success_message": "Ausgewählte Notizen wurden verschoben"
}, },
"note_type_chooser": { "note_type_chooser": {
"modal_title": "Wähle den Notiztyp aus", "modal_title": "Wähle den Notiztyp aus",
"modal_body": "Wähle den Notiztyp / die Vorlage der neuen Notiz:", "modal_body": "Wähle den Notiztyp / die Vorlage der neuen Notiz:",
"templates": "Vorlagen", "templates": "Vorlagen"
"change_path_prompt": "Ändern wo die neue Notiz erzeugt wird:",
"search_placeholder": "Durchsuche Pfad nach Namen (Standard falls leer)",
"builtin_templates": "Eingebaute Vorlage"
}, },
"password_not_set": { "password_not_set": {
"title": "Das Passwort ist nicht festgelegt", "title": "Das Passwort ist nicht festgelegt",
"body1": "Geschützte Notizen werden mit einem Benutzerpasswort verschlüsselt, es wurde jedoch noch kein Passwort festgelegt.", "body1": "Geschützte Notizen werden mit einem Benutzerpasswort verschlüsselt, es wurde jedoch noch kein Passwort festgelegt."
"body2": "Um Notizen zu schützen, klicke den unteren Button um den Optionsdialog zu öffnen und dein Passwort festzulegen.",
"go_to_password_options": "Gehe zu Passwortoptionen"
}, },
"prompt": { "prompt": {
"title": "Eingabeaufforderung", "title": "Prompt",
"ok": "OK", "ok": "OK",
"defaultTitle": "Eingabeaufforderung" "defaultTitle": "Prompt"
}, },
"protected_session_password": { "protected_session_password": {
"modal_title": "Geschützte Sitzung", "modal_title": "Geschützte Sitzung",
@@ -271,17 +265,10 @@
"maximum_revisions": "Maximale Revisionen für aktuelle Notiz: {{number}}.", "maximum_revisions": "Maximale Revisionen für aktuelle Notiz: {{number}}.",
"settings": "Einstellungen für Notizrevisionen", "settings": "Einstellungen für Notizrevisionen",
"download_button": "Herunterladen", "download_button": "Herunterladen",
"mime": "MIME: ", "mime": "MIME:",
"file_size": "Dateigröße:", "file_size": "Dateigröße:",
"preview": "Vorschau:", "preview": "Vorschau:",
"preview_not_available": "Für diesen Notiztyp ist keine Vorschau verfügbar.", "preview_not_available": "Für diesen Notiztyp ist keine Vorschau verfügbar."
"restore_button": "Wiederherstellen",
"delete_button": "Löschen",
"diff_on": "Zeige Differenz",
"diff_off": "Zeige Inhalt",
"diff_on_hint": "Klicke, um die Differenz des Notiz-Quellcodes zu zeigen",
"diff_off_hint": "Klicke, um den Notizinhalt zu zeigen",
"diff_not_available": "Differenz-Abgleich ist nicht verfügbar."
}, },
"sort_child_notes": { "sort_child_notes": {
"sort_children_by": "Unternotizen sortieren nach...", "sort_children_by": "Unternotizen sortieren nach...",
@@ -361,7 +348,7 @@
"sorted": "Hält untergeordnete Notizen alphabetisch nach Titel sortiert", "sorted": "Hält untergeordnete Notizen alphabetisch nach Titel sortiert",
"sort_direction": "ASC (Standard) oder DESC", "sort_direction": "ASC (Standard) oder DESC",
"sort_folders_first": "Ordner (Notizen mit Unternotizen) sollten oben sortiert werden", "sort_folders_first": "Ordner (Notizen mit Unternotizen) sollten oben sortiert werden",
"top": "Behalte die angegebene Notiz oben in der übergeordneten Notiz (gilt nur für sortierte übergeordnete Notizen)", "top": "Behalte die angegebene Notiz oben in der übergeordneten Notiz (gilt nur für sortierte übergeordnete Notizen).",
"hide_promoted_attributes": "Heraufgestufte Attribute für diese Notiz ausblenden", "hide_promoted_attributes": "Heraufgestufte Attribute für diese Notiz ausblenden",
"read_only": "Der Editor befindet sich im schreibgeschützten Modus. Funktioniert nur für Text- und Codenotizen.", "read_only": "Der Editor befindet sich im schreibgeschützten Modus. Funktioniert nur für Text- und Codenotizen.",
"auto_read_only_disabled": "Text-/Codenotizen können automatisch in den Lesemodus versetzt werden, wenn sie zu groß sind. Du kannst dieses Verhalten für jede einzelne Notiz deaktivieren, indem du diese Beschriftung zur Notiz hinzufügst", "auto_read_only_disabled": "Text-/Codenotizen können automatisch in den Lesemodus versetzt werden, wenn sie zu groß sind. Du kannst dieses Verhalten für jede einzelne Notiz deaktivieren, indem du diese Beschriftung zur Notiz hinzufügst",
@@ -384,10 +371,10 @@
"inbox": "Standard-Inbox-Position für neue Notizen wenn du eine Notiz über den \"Neue Notiz\"-Button in der Seitenleiste erstellst, wird die Notiz als untergeordnete Notiz der Notiz erstellt, die mit dem <code>#inbox</code>-Label markiert ist.", "inbox": "Standard-Inbox-Position für neue Notizen wenn du eine Notiz über den \"Neue Notiz\"-Button in der Seitenleiste erstellst, wird die Notiz als untergeordnete Notiz der Notiz erstellt, die mit dem <code>#inbox</code>-Label markiert ist.",
"workspace_inbox": "Standard-Posteingangsspeicherort für neue Notizen, wenn sie zu einem Vorgänger dieser Arbeitsbereichsnotiz verschoben werden", "workspace_inbox": "Standard-Posteingangsspeicherort für neue Notizen, wenn sie zu einem Vorgänger dieser Arbeitsbereichsnotiz verschoben werden",
"sql_console_home": "Standardspeicherort der SQL-Konsolennotizen", "sql_console_home": "Standardspeicherort der SQL-Konsolennotizen",
"bookmark_folder": "Notizen mit dieser Bezeichnung werden in den Lesezeichen als Ordner angezeigt (und ermöglichen den Zugriff auf ihre untergeordneten Ordner)", "bookmark_folder": "Notizen mit dieser Bezeichnung werden in den Lesezeichen als Ordner angezeigt (und ermöglichen den Zugriff auf ihre untergeordneten Ordner).",
"share_hidden_from_tree": "Diese Notiz ist im linken Navigationsbaum ausgeblendet, kann aber weiterhin über ihre URL aufgerufen werden", "share_hidden_from_tree": "Diese Notiz ist im linken Navigationsbaum ausgeblendet, kann aber weiterhin über ihre URL aufgerufen werden",
"share_external_link": "Die Notiz dient als Link zu einer externen Website im Freigabebaum", "share_external_link": "Die Notiz dient als Link zu einer externen Website im Freigabebaum",
"share_alias": "Lege einen Alias fest, mit dem die Notiz unter https://your_trilium_host/share/[dein_alias] verfügbar sein wird", "share_alias": "Lege einen Alias fest, unter dem die Notiz unter https://your_trilium_host/share/[dein_alias] verfügbar sein wird.",
"share_omit_default_css": "Das Standard-CSS für die Freigabeseite wird weggelassen. Verwende es, wenn du umfangreiche Stylingänderungen vornimmst.", "share_omit_default_css": "Das Standard-CSS für die Freigabeseite wird weggelassen. Verwende es, wenn du umfangreiche Stylingänderungen vornimmst.",
"share_root": "Markiert eine Notiz, die im /share-Root bereitgestellt wird.", "share_root": "Markiert eine Notiz, die im /share-Root bereitgestellt wird.",
"share_description": "Definiere Text, der dem HTML-Meta-Tag zur Beschreibung hinzugefügt werden soll", "share_description": "Definiere Text, der dem HTML-Meta-Tag zur Beschreibung hinzugefügt werden soll",
@@ -403,7 +390,7 @@
"color": "Definiert die Farbe der Notiz im Notizbaum, in Links usw. Verwende einen beliebigen gültigen CSS-Farbwert wie „rot“ oder #a13d5f", "color": "Definiert die Farbe der Notiz im Notizbaum, in Links usw. Verwende einen beliebigen gültigen CSS-Farbwert wie „rot“ oder #a13d5f",
"keyboard_shortcut": "Definiert eine Tastenkombination, die sofort zu dieser Notiz springt. Beispiel: „Strg+Alt+E“. Erfordert ein Neuladen des Frontends, damit die Änderung wirksam wird.", "keyboard_shortcut": "Definiert eine Tastenkombination, die sofort zu dieser Notiz springt. Beispiel: „Strg+Alt+E“. Erfordert ein Neuladen des Frontends, damit die Änderung wirksam wird.",
"keep_current_hoisting": "Das Öffnen dieses Links ändert das Hochziehen nicht, selbst wenn die Notiz im aktuell hochgezogenen Unterbaum nicht angezeigt werden kann.", "keep_current_hoisting": "Das Öffnen dieses Links ändert das Hochziehen nicht, selbst wenn die Notiz im aktuell hochgezogenen Unterbaum nicht angezeigt werden kann.",
"execute_button": "Titel der Schaltfläche, welche die aktuelle Codenotiz ausführt", "execute_button": "Titel der Schaltfläche, die die aktuelle Codenotiz ausführt",
"execute_description": "Längere Beschreibung der aktuellen Codenotiz, die zusammen mit der Schaltfläche „Ausführen“ angezeigt wird", "execute_description": "Längere Beschreibung der aktuellen Codenotiz, die zusammen mit der Schaltfläche „Ausführen“ angezeigt wird",
"exclude_from_note_map": "Notizen mit dieser Bezeichnung werden in der Notizenkarte ausgeblendet", "exclude_from_note_map": "Notizen mit dieser Bezeichnung werden in der Notizenkarte ausgeblendet",
"new_notes_on_top": "Neue Notizen werden oben in der übergeordneten Notiz erstellt, nicht unten.", "new_notes_on_top": "Neue Notizen werden oben in der übergeordneten Notiz erstellt, nicht unten.",
@@ -418,10 +405,10 @@
"run_on_branch_change": "wird ausgeführt, wenn ein Zweig aktualisiert wird.", "run_on_branch_change": "wird ausgeführt, wenn ein Zweig aktualisiert wird.",
"run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. gelöscht. beim Verschieben der Notiz (alter Zweig/Link wird gelöscht).", "run_on_branch_deletion": "wird ausgeführt, wenn ein Zweig gelöscht wird. Der Zweig ist eine Verknüpfung zwischen der übergeordneten Notiz und der untergeordneten Notiz und wird z. B. gelöscht. beim Verschieben der Notiz (alter Zweig/Link wird gelöscht).",
"run_on_attribute_creation": "wird ausgeführt, wenn für die Notiz ein neues Attribut erstellt wird, das diese Beziehung definiert", "run_on_attribute_creation": "wird ausgeführt, wenn für die Notiz ein neues Attribut erstellt wird, das diese Beziehung definiert",
"run_on_attribute_change": " wird ausgeführt, wenn das Attribut einer Notiz geändert wird, die diese Beziehung definiert. Dies wird auch ausgelöst, wenn das Attribut gelöscht wird", "run_on_attribute_change": "wird ausgeführt, wenn das Attribut einer Notiz geändert wird, die diese Beziehung definiert. Dies wird auch ausgelöst, wenn das Attribut gelöscht wird",
"relation_template": "Die Attribute der Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Der Inhalt und der Unterbaum der Notiz werden den Instanznotizen hinzugefügt, wenn sie leer sind. Einzelheiten findest du in der Dokumentation.", "relation_template": "Die Attribute der Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Der Inhalt und der Unterbaum der Notiz werden den Instanznotizen hinzugefügt, wenn sie leer sind. Einzelheiten findest du in der Dokumentation.",
"inherit": "Die Attribute einer Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Ein ähnliches Konzept findest du unter Vorlagenbeziehung. Siehe Attributvererbung in der Dokumentation.", "inherit": "Die Attribute einer Notiz werden auch ohne eine Eltern-Kind-Beziehung vererbt. Ein ähnliches Konzept findest du unter Vorlagenbeziehung. Siehe Attributvererbung in der Dokumentation.",
"render_note": "Notizen vom Typ \"HTML-Notiz rendern\" werden mit einer Code-Notiz (HTML oder Skript) gerendert, und es ist notwendig, über diese Beziehung anzugeben, welche Notiz gerendert werden soll", "render_note": "Notizen vom Typ \"HTML-Notiz rendern\" werden mit einer Code-Notiz (HTML oder Skript) gerendert, und es ist notwendig, über diese Beziehung anzugeben, welche Notiz gerendert werden soll.",
"widget_relation": "Das Ziel dieser Beziehung wird ausgeführt und als Widget in der Seitenleiste gerendert", "widget_relation": "Das Ziel dieser Beziehung wird ausgeführt und als Widget in der Seitenleiste gerendert",
"share_css": "CSS-Hinweis, der in die Freigabeseite eingefügt wird. Die CSS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge auch die Verwendung von „share_hidden_from_tree“ und „share_omit_default_css“.", "share_css": "CSS-Hinweis, der in die Freigabeseite eingefügt wird. Die CSS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge auch die Verwendung von „share_hidden_from_tree“ und „share_omit_default_css“.",
"share_js": "JavaScript-Hinweis, der in die Freigabeseite eingefügt wird. Die JS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge die Verwendung von „share_hidden_from_tree“.", "share_js": "JavaScript-Hinweis, der in die Freigabeseite eingefügt wird. Die JS-Notiz muss sich ebenfalls im gemeinsamen Unterbaum befinden. Erwäge die Verwendung von „share_hidden_from_tree“.",
@@ -431,8 +418,7 @@
"other_notes_with_name": "Other notes with {{attributeType}} name \"{{attributeName}}\"", "other_notes_with_name": "Other notes with {{attributeType}} name \"{{attributeName}}\"",
"and_more": "... und {{count}} mehr.", "and_more": "... und {{count}} mehr.",
"print_landscape": "Beim Export als PDF, wird die Seitenausrichtung Querformat anstatt Hochformat verwendet.", "print_landscape": "Beim Export als PDF, wird die Seitenausrichtung Querformat anstatt Hochformat verwendet.",
"print_page_size": "Beim Export als PDF, wird die Größe der Seite angepasst. Unterstützte Größen: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.", "print_page_size": "Beim Export als PDF, wird die Größe der Seite angepasst. Unterstützte Größen: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>."
"color_type": "Farbe"
}, },
"attribute_editor": { "attribute_editor": {
"help_text_body1": "Um ein Label hinzuzufügen, gebe einfach z.B. ein. <code>#rock</code> oder wenn du auch einen Wert hinzufügen möchten, dann z.B. <code>#year = 2024</code>", "help_text_body1": "Um ein Label hinzuzufügen, gebe einfach z.B. ein. <code>#rock</code> oder wenn du auch einen Wert hinzufügen möchten, dann z.B. <code>#year = 2024</code>",
@@ -504,9 +490,9 @@
"to": "nach", "to": "nach",
"target_parent_note": "Ziel-Übergeordnetenotiz", "target_parent_note": "Ziel-Übergeordnetenotiz",
"on_all_matched_notes": "Auf allen übereinstimmenden Notizen", "on_all_matched_notes": "Auf allen übereinstimmenden Notizen",
"move_note_new_parent": "Verschiebe die Notiz in die neue übergeordnete Notiz, wenn die Notiz nur eine übergeordnete Notiz hat (d. h. der alte Zweig wird entfernt und ein neuer Zweig in die neue übergeordnete Notiz erstellt)", "move_note_new_parent": "Verschiebe die Notiz in die neue übergeordnete Notiz, wenn die Notiz nur eine übergeordnete Notiz hat (d. h. der alte Zweig wird entfernt und ein neuer Zweig in die neue übergeordnete Notiz erstellt).",
"clone_note_new_parent": "Notiz auf die neue übergeordnete Notiz klonen, wenn die Notiz mehrere Klone/Zweige hat (es ist nicht klar, welcher Zweig entfernt werden soll)", "clone_note_new_parent": "Notiz auf die neue übergeordnete Notiz klonen, wenn die Notiz mehrere Klone/Zweige hat (es ist nicht klar, welcher Zweig entfernt werden soll)",
"nothing_will_happen": "Es passiert nichts, wenn die Notiz nicht zur Zielnotiz verschoben werden kann (z.B. wenn dies einen Kreislauf in der Baumstruktur erzeugen würde)" "nothing_will_happen": "Es passiert nichts, wenn die Notiz nicht zur Zielnotiz verschoben werden kann (d. h. dies würde einen Baumzyklus erzeugen)."
}, },
"rename_note": { "rename_note": {
"rename_note": "Notiz umbenennen", "rename_note": "Notiz umbenennen",
@@ -514,10 +500,10 @@
"new_note_title": "neuer Notiztitel", "new_note_title": "neuer Notiztitel",
"click_help_icon": "Klicke rechts auf das Hilfesymbol, um alle Optionen anzuzeigen", "click_help_icon": "Klicke rechts auf das Hilfesymbol, um alle Optionen anzuzeigen",
"evaluated_as_js_string": "Der angegebene Wert wird als JavaScript-String ausgewertet und kann somit über die injizierte <code>note</code>-Variable mit dynamischem Inhalt angereichert werden (Notiz wird umbenannt). Beispiele:", "evaluated_as_js_string": "Der angegebene Wert wird als JavaScript-String ausgewertet und kann somit über die injizierte <code>note</code>-Variable mit dynamischem Inhalt angereichert werden (Notiz wird umbenannt). Beispiele:",
"example_note": "<code>Notiz</code> alle übereinstimmenden Notizen werden in „Notiz“ umbenannt", "example_note": "<code>Notiz</code> alle übereinstimmenden Notizen werden in „Notiz“ umbenannt.",
"example_new_title": "<code>NEU: ${note.title}</code> Übereinstimmende Notiztitel erhalten das Präfix „NEU:“", "example_new_title": "<code>NEU: ${note.title}</code> Übereinstimmende Notiztitel erhalten das Präfix „NEU:“",
"example_date_prefix": "<code>${note.dateCreatedObj.format('MM-DD:')}: ${note.title}</code> übereinstimmende Notizen werden mit dem Erstellungsmonat und -datum der Notiz vorangestellt", "example_date_prefix": "<code>${note.dateCreatedObj.format('MM-DD:')}: ${note.title}</code> übereinstimmende Notizen werden mit dem Erstellungsmonat und -datum der Notiz vorangestellt",
"api_docs": "Siehe API-Dokumente für <a href='https://zadam.github.io/trilium/backend_api/Note.html'>Notiz</a> und seinen <a href='https://day.js.org/ docs/en/display/format'>dateCreatedObj / utcDateCreatedObj properties</a> für Details." "api_docs": "Siehe API-Dokumente für <a hrefu003d'https://zadam.github.io/trilium/backend_api/Note.html'>Notiz</a> und seinen <a hrefu003d'https://day.js.org/ docs/en/display/format'>dateCreatedObj / utcDateCreatedObj-Eigenschaften</a> für Details."
}, },
"add_relation": { "add_relation": {
"add_relation": "Beziehung hinzufügen", "add_relation": "Beziehung hinzufügen",
@@ -581,7 +567,7 @@
"sun": "So", "sun": "So",
"cannot_find_day_note": "Tagesnotiz kann nicht gefunden werden", "cannot_find_day_note": "Tagesnotiz kann nicht gefunden werden",
"january": "Januar", "january": "Januar",
"february": "Februar", "febuary": "Februar",
"march": "März", "march": "März",
"april": "April", "april": "April",
"may": "Mai", "may": "Mai",
@@ -591,19 +577,7 @@
"september": "September", "september": "September",
"october": "Oktober", "october": "Oktober",
"november": "November", "november": "November",
"december": "Dezember", "december": "Dezember"
"cannot_find_week_note": "Wochennotiz kann nicht gefunden werden",
"week": "Woche",
"week_previous": "vorherige Woche",
"week_next": "nächste Woche",
"month": "Monat",
"month_previous": "vorheriger Monat",
"month_next": "nächster Monat",
"year": "Jahr",
"year_previous": "vorheriges Jahr",
"year_next": "nächstes Jahr",
"list": "Liste",
"today": "Heute"
}, },
"close_pane_button": { "close_pane_button": {
"close_this_pane": "Schließe diesen Bereich" "close_this_pane": "Schließe diesen Bereich"
@@ -725,14 +699,14 @@
"zoom_out_title": "Herauszoomen" "zoom_out_title": "Herauszoomen"
}, },
"zpetne_odkazy": { "zpetne_odkazy": {
"backlink": "{{count}} Rückverlinkung", "backlink": "{{count}} Backlink",
"backlinks": "{{count}} Rückverlinkungen", "backlinks": "{{count}} Backlinks",
"relation": "Beziehung" "relation": "Beziehung"
}, },
"mobile_detail_menu": { "mobile_detail_menu": {
"insert_child_note": "Untergeordnete Notiz einfügen", "insert_child_note": "Untergeordnete Notiz einfügen",
"delete_this_note": "Diese Notiz löschen", "delete_this_note": "Diese Notiz löschen",
"error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden", "error_cannot_get_branch_id": "BranchId für notePath „{{notePath}}“ kann nicht abgerufen werden.",
"error_unrecognized_command": "Unbekannter Befehl {{command}}" "error_unrecognized_command": "Unbekannter Befehl {{command}}"
}, },
"note_icon": { "note_icon": {
@@ -744,9 +718,7 @@
"basic_properties": { "basic_properties": {
"note_type": "Notiztyp", "note_type": "Notiztyp",
"editable": "Bearbeitbar", "editable": "Bearbeitbar",
"basic_properties": "Grundlegende Eigenschaften", "basic_properties": "Grundlegende Eigenschaften"
"language": "Sprache",
"configure_code_notes": "Code-Notizen konfigurieren..."
}, },
"book_properties": { "book_properties": {
"view_type": "Ansichtstyp", "view_type": "Ansichtstyp",
@@ -757,12 +729,7 @@
"collapse": "Einklappen", "collapse": "Einklappen",
"expand": "Ausklappen", "expand": "Ausklappen",
"invalid_view_type": "Ungültiger Ansichtstyp „{{type}}“", "invalid_view_type": "Ungültiger Ansichtstyp „{{type}}“",
"calendar": "Kalender", "calendar": "Kalender"
"book_properties": "Sammlungseigenschaften",
"table": "Tabelle",
"geo-map": "Weltkarte",
"board": "Tafel",
"include_archived_notes": "Zeige archivierte Notizen"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...", "no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -838,9 +805,7 @@
"unknown_label_type": "Unbekannter Labeltyp „{{type}}“", "unknown_label_type": "Unbekannter Labeltyp „{{type}}“",
"unknown_attribute_type": "Unbekannter Attributtyp „{{type}}“", "unknown_attribute_type": "Unbekannter Attributtyp „{{type}}“",
"add_new_attribute": "Neues Attribut hinzufügen", "add_new_attribute": "Neues Attribut hinzufügen",
"remove_this_attribute": "Entferne dieses Attribut", "remove_this_attribute": "Entferne dieses Attribut"
"unset-field-placeholder": "nicht gesetzt",
"remove_color": "Entferne Farblabel"
}, },
"script_executor": { "script_executor": {
"query": "Abfrage", "query": "Abfrage",
@@ -863,7 +828,7 @@
"debug": "debuggen", "debug": "debuggen",
"debug_description": "Debug gibt zusätzliche Debuginformationen in die Konsole aus, um das Debuggen komplexer Abfragen zu erleichtern", "debug_description": "Debug gibt zusätzliche Debuginformationen in die Konsole aus, um das Debuggen komplexer Abfragen zu erleichtern",
"action": "Aktion", "action": "Aktion",
"search_button": "Suchen", "search_button": "Suchen <kbd>Eingabetaste</kbd>",
"search_execute": "Aktionen suchen und ausführen", "search_execute": "Aktionen suchen und ausführen",
"save_to_note": "Als Notiz speichern", "save_to_note": "Als Notiz speichern",
"search_parameters": "Suchparameter", "search_parameters": "Suchparameter",
@@ -902,7 +867,7 @@
"include_archived_notes": "Füge archivierte Notizen hinzu" "include_archived_notes": "Füge archivierte Notizen hinzu"
}, },
"limit": { "limit": {
"limit": "Limitierung", "limit": "Limit",
"take_first_x_results": "Nehmen Sie nur die ersten X angegebenen Ergebnisse." "take_first_x_results": "Nehmen Sie nur die ersten X angegebenen Ergebnisse."
}, },
"order_by": { "order_by": {
@@ -952,7 +917,7 @@
"attachment_detail": { "attachment_detail": {
"open_help_page": "Hilfeseite zu Anhängen öffnen", "open_help_page": "Hilfeseite zu Anhängen öffnen",
"owning_note": "Eigentümernotiz: ", "owning_note": "Eigentümernotiz: ",
"you_can_also_open": ", Du kannst auch das öffnen ", "you_can_also_open": ", Du kannst auch das öffnen",
"list_of_all_attachments": "Liste aller Anhänge", "list_of_all_attachments": "Liste aller Anhänge",
"attachment_deleted": "Dieser Anhang wurde gelöscht." "attachment_deleted": "Dieser Anhang wurde gelöscht."
}, },
@@ -963,9 +928,7 @@
"no_attachments": "Diese Notiz enthält keine Anhänge." "no_attachments": "Diese Notiz enthält keine Anhänge."
}, },
"book": { "book": {
"no_children_help": "Diese Notiz mit dem Notiztyp Buch besitzt keine Unternotizen, deshalb ist nichts zum Anzeigen vorhanden. Siehe <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">Wiki</a> für mehr Details.", "no_children_help": "Diese Notiz mit dem Notiztyp Buch besitzt keine Unternotizen, deshalb ist nichts zum Anzeigen vorhanden. Siehe <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">Wiki</a> für mehr Details."
"drag_locked_title": "Für Bearbeitung gesperrt",
"drag_locked_message": "Das Ziehen ist nicht möglich, da die Sammlung für die Bearbeitung gesperrt ist."
}, },
"editable_code": { "editable_code": {
"placeholder": "Gebe hier den Inhalt deiner Codenotiz ein..." "placeholder": "Gebe hier den Inhalt deiner Codenotiz ein..."
@@ -979,8 +942,7 @@
"enter_workspace": "Betrete den Arbeitsbereich {{title}}" "enter_workspace": "Betrete den Arbeitsbereich {{title}}"
}, },
"file": { "file": {
"file_preview_not_available": "Für dieses Dateiformat ist keine Dateivorschau verfügbar.", "file_preview_not_available": "Für dieses Dateiformat ist keine Dateivorschau verfügbar."
"too_big": "Die Vorschau zeigt aus Effizienzgründen nur die ersten {{maxNumChars}} Zeichen der Datei an. Lade die Datei herunter und öffne sie extern um den gesamten Inhalt zu sehen."
}, },
"protected_session": { "protected_session": {
"enter_password_instruction": "Um die geschützte Notiz anzuzeigen, musst du dein Passwort eingeben:", "enter_password_instruction": "Um die geschützte Notiz anzuzeigen, musst du dein Passwort eingeben:",
@@ -1019,7 +981,7 @@
"web_view": { "web_view": {
"web_view": "Webansicht", "web_view": "Webansicht",
"embed_websites": "Notiz vom Typ Web View ermöglicht das Einbetten von Websites in Trilium.", "embed_websites": "Notiz vom Typ Web View ermöglicht das Einbetten von Websites in Trilium.",
"create_label": "Um zu beginnen, erstelle bitte ein Label mit einer URL-Adresse, die eingebettet werden soll, z. B. #webViewSrc=\"https://www.google.com\"" "create_label": "To start, please create a label with a URL address you want to embed, e.g. #webViewSrc=\"https://www.google.com\""
}, },
"backend_log": { "backend_log": {
"refresh": "Aktualisieren" "refresh": "Aktualisieren"
@@ -1045,7 +1007,7 @@
"error_creating_anonymized_database": "Die anonymisierte Datenbank konnte nicht erstellt werden. Überprüfe die Backend-Protokolle auf Details", "error_creating_anonymized_database": "Die anonymisierte Datenbank konnte nicht erstellt werden. Überprüfe die Backend-Protokolle auf Details",
"successfully_created_fully_anonymized_database": "Vollständig anonymisierte Datenbank in {{anonymizedFilePath}} erstellt", "successfully_created_fully_anonymized_database": "Vollständig anonymisierte Datenbank in {{anonymizedFilePath}} erstellt",
"successfully_created_lightly_anonymized_database": "Leicht anonymisierte Datenbank in {{anonymizedFilePath}} erstellt", "successfully_created_lightly_anonymized_database": "Leicht anonymisierte Datenbank in {{anonymizedFilePath}} erstellt",
"no_anonymized_database_yet": "Noch keine anonymisierte Datenbank." "no_anonymized_database_yet": "Noch keine anonymisierte Datenbank"
}, },
"database_integrity_check": { "database_integrity_check": {
"title": "Datenbankintegritätsprüfung", "title": "Datenbankintegritätsprüfung",
@@ -1066,7 +1028,7 @@
"failed": "Synchronisierung fehlgeschlagen: {{message}}" "failed": "Synchronisierung fehlgeschlagen: {{message}}"
}, },
"vacuum_database": { "vacuum_database": {
"title": "Datenbank aufräumen", "title": "Vakuumdatenbank",
"description": "Dadurch wird die Datenbank neu erstellt, was normalerweise zu einer kleineren Datenbankdatei führt. Es werden keine Daten tatsächlich geändert.", "description": "Dadurch wird die Datenbank neu erstellt, was normalerweise zu einer kleineren Datenbankdatei führt. Es werden keine Daten tatsächlich geändert.",
"button_text": "Vakuumdatenbank", "button_text": "Vakuumdatenbank",
"vacuuming_database": "Datenbank wird geleert...", "vacuuming_database": "Datenbank wird geleert...",
@@ -1101,8 +1063,7 @@
"max_width_label": "Maximale Inhaltsbreite in Pixel", "max_width_label": "Maximale Inhaltsbreite in Pixel",
"apply_changes_description": "Um Änderungen an der Inhaltsbreite anzuwenden, klicke auf", "apply_changes_description": "Um Änderungen an der Inhaltsbreite anzuwenden, klicke auf",
"reload_button": "Frontend neu laden", "reload_button": "Frontend neu laden",
"reload_description": "Änderungen an den Darstellungsoptionen", "reload_description": "Änderungen an den Darstellungsoptionen"
"max_width_unit": "Pixel"
}, },
"native_title_bar": { "native_title_bar": {
"title": "Native Titelleiste (App-Neustart erforderlich)", "title": "Native Titelleiste (App-Neustart erforderlich)",
@@ -1125,10 +1086,7 @@
"layout-vertical-title": "Vertikal", "layout-vertical-title": "Vertikal",
"layout-horizontal-title": "Horizontal", "layout-horizontal-title": "Horizontal",
"layout-vertical-description": "Startleiste ist auf der linken Seite (standard)", "layout-vertical-description": "Startleiste ist auf der linken Seite (standard)",
"layout-horizontal-description": "Startleiste ist unter der Tableiste. Die Tableiste wird dadurch auf die ganze Breite erweitert.", "layout-horizontal-description": "Startleiste ist unter der Tableiste. Die Tableiste wird dadurch auf die ganze Breite erweitert."
"auto_theme": "Alt (Folge dem Farbschema des Systems)",
"light_theme": "Alt (Hell)",
"dark_theme": "Alt (Dunkel)"
}, },
"zoom_factor": { "zoom_factor": {
"title": "Zoomfaktor (nur Desktop-Build)", "title": "Zoomfaktor (nur Desktop-Build)",
@@ -1137,8 +1095,7 @@
"code_auto_read_only_size": { "code_auto_read_only_size": {
"title": "Automatische schreibgeschützte Größe", "title": "Automatische schreibgeschützte Größe",
"description": "Die automatische schreibgeschützte Notizgröße ist die Größe, ab der Notizen im schreibgeschützten Modus angezeigt werden (aus Leistungsgründen).", "description": "Die automatische schreibgeschützte Notizgröße ist die Größe, ab der Notizen im schreibgeschützten Modus angezeigt werden (aus Leistungsgründen).",
"label": "Automatische schreibgeschützte Größe (Codenotizen)", "label": "Automatische schreibgeschützte Größe (Codenotizen)"
"unit": "Zeichen"
}, },
"code_mime_types": { "code_mime_types": {
"title": "Verfügbare MIME-Typen im Dropdown-Menü" "title": "Verfügbare MIME-Typen im Dropdown-Menü"
@@ -1157,13 +1114,12 @@
"download_images_description": "Eingefügter HTML-Code kann Verweise auf Online-Bilder enthalten. Trilium findet diese Verweise und lädt die Bilder herunter, sodass sie offline verfügbar sind.", "download_images_description": "Eingefügter HTML-Code kann Verweise auf Online-Bilder enthalten. Trilium findet diese Verweise und lädt die Bilder herunter, sodass sie offline verfügbar sind.",
"enable_image_compression": "Bildkomprimierung aktivieren", "enable_image_compression": "Bildkomprimierung aktivieren",
"max_image_dimensions": "Maximale Breite/Höhe eines Bildes in Pixel (die Größe des Bildes wird geändert, wenn es diese Einstellung überschreitet).", "max_image_dimensions": "Maximale Breite/Höhe eines Bildes in Pixel (die Größe des Bildes wird geändert, wenn es diese Einstellung überschreitet).",
"jpeg_quality_description": "JPEG-Qualität (10 schlechteste Qualität, 100 beste Qualität, 50 85 wird empfohlen)", "jpeg_quality_description": "JPEG-Qualität (10 schlechteste Qualität, 100 beste Qualität, 50 85 wird empfohlen)"
"max_image_dimensions_unit": "Pixel"
}, },
"attachment_erasure_timeout": { "attachment_erasure_timeout": {
"attachment_erasure_timeout": "Zeitüberschreitung beim Löschen von Anhängen", "attachment_erasure_timeout": "Zeitüberschreitung beim Löschen von Anhängen",
"attachment_auto_deletion_description": "Anhänge werden automatisch gelöscht (und gelöscht), wenn sie nach einer definierten Zeitspanne nicht mehr in ihrer Notiz referenziert werden.", "attachment_auto_deletion_description": "Anhänge werden automatisch gelöscht (und gelöscht), wenn sie nach einer definierten Zeitspanne nicht mehr in ihrer Notiz referenziert werden.",
"erase_attachments_after": "Nicht verwendete Anhänge löschen nach:", "erase_attachments_after": "Erase unused attachments after:",
"manual_erasing_description": "Du kannst das Löschen auch manuell auslösen (ohne Berücksichtigung des oben definierten Timeouts):", "manual_erasing_description": "Du kannst das Löschen auch manuell auslösen (ohne Berücksichtigung des oben definierten Timeouts):",
"erase_unused_attachments_now": "Lösche jetzt nicht verwendete Anhangnotizen", "erase_unused_attachments_now": "Lösche jetzt nicht verwendete Anhangnotizen",
"unused_attachments_erased": "Nicht verwendete Anhänge wurden gelöscht." "unused_attachments_erased": "Nicht verwendete Anhänge wurden gelöscht."
@@ -1174,7 +1130,7 @@
}, },
"note_erasure_timeout": { "note_erasure_timeout": {
"note_erasure_timeout_title": "Beachte das Zeitlimit für die Löschung", "note_erasure_timeout_title": "Beachte das Zeitlimit für die Löschung",
"note_erasure_description": "Gelöschte Notizen (und Attribute, Notizrevisionen...) werden zunächst nur als gelöscht markiert und können über den Dialog „Zuletzt verwendete Notizen” wiederhergestellt werden. Nach einer bestimmten Zeit werden gelöschte Notizen „gelöscht”, was bedeutet, dass ihr Inhalt nicht mehr wiederhergestellt werden kann. Mit dieser Einstellung können Sie die Zeitspanne zwischen dem Löschen und dem endgültigen Löschen der Notiz festlegen.", "note_erasure_description": "Deleted notes (and attributes, revisions...) are at first only marked as deleted and it is possible to recover them from Recent Notes dialog. After a period of time, deleted notes are \"erased\" which means their content is not recoverable anymore. This setting allows you to configure the length of the period between deleting and erasing the note.",
"erase_notes_after": "Notizen löschen nach:", "erase_notes_after": "Notizen löschen nach:",
"manual_erasing_description": "Du kannst das Löschen auch manuell auslösen (ohne Berücksichtigung des oben definierten Timeouts):", "manual_erasing_description": "Du kannst das Löschen auch manuell auslösen (ohne Berücksichtigung des oben definierten Timeouts):",
"erase_deleted_notes_now": "Jetzt gelöschte Notizen löschen", "erase_deleted_notes_now": "Jetzt gelöschte Notizen löschen",
@@ -1190,8 +1146,7 @@
"note_revisions_snapshot_limit_description": "Das Limit für Notizrevision-Snapshots bezieht sich auf die maximale Anzahl von Revisionen, die für jede Notiz gespeichert werden können. Dabei bedeutet -1, dass es kein Limit gibt, und 0 bedeutet, dass alle Revisionen gelöscht werden. Du kannst das maximale Limit für Revisionen einer einzelnen Notiz über das Label #versioningLimit festlegen.", "note_revisions_snapshot_limit_description": "Das Limit für Notizrevision-Snapshots bezieht sich auf die maximale Anzahl von Revisionen, die für jede Notiz gespeichert werden können. Dabei bedeutet -1, dass es kein Limit gibt, und 0 bedeutet, dass alle Revisionen gelöscht werden. Du kannst das maximale Limit für Revisionen einer einzelnen Notiz über das Label #versioningLimit festlegen.",
"snapshot_number_limit_label": "Limit der Notizrevision-Snapshots:", "snapshot_number_limit_label": "Limit der Notizrevision-Snapshots:",
"erase_excess_revision_snapshots": "Überschüssige Revision-Snapshots jetzt löschen", "erase_excess_revision_snapshots": "Überschüssige Revision-Snapshots jetzt löschen",
"erase_excess_revision_snapshots_prompt": "Überschüssige Revision-Snapshots wurden gelöscht.", "erase_excess_revision_snapshots_prompt": "Überschüssige Revision-Snapshots wurden gelöscht."
"snapshot_number_limit_unit": "Momentaufnahmen"
}, },
"search_engine": { "search_engine": {
"title": "Suchmaschine", "title": "Suchmaschine",
@@ -1233,29 +1188,19 @@
"title": "Inhaltsverzeichnis", "title": "Inhaltsverzeichnis",
"description": "Das Inhaltsverzeichnis wird in Textnotizen angezeigt, wenn die Notiz mehr als eine definierte Anzahl von Überschriften enthält. Du kannst diese Nummer anpassen:", "description": "Das Inhaltsverzeichnis wird in Textnotizen angezeigt, wenn die Notiz mehr als eine definierte Anzahl von Überschriften enthält. Du kannst diese Nummer anpassen:",
"disable_info": "Du kannst diese Option auch verwenden, um TOC effektiv zu deaktivieren, indem du eine sehr hohe Zahl festlegst.", "disable_info": "Du kannst diese Option auch verwenden, um TOC effektiv zu deaktivieren, indem du eine sehr hohe Zahl festlegst.",
"shortcut_info": "Du kannst eine Tastenkombination zum schnellen Umschalten des rechten Bereichs (einschließlich Inhaltsverzeichnis) unter Optionen -> Tastenkombinationen konfigurieren (Name „toggleRightPane“).", "shortcut_info": "Du kannst eine Tastenkombination zum schnellen Umschalten des rechten Bereichs (einschließlich Inhaltsverzeichnis) unter Optionen -> Tastenkombinationen konfigurieren (Name „toggleRightPane“)."
"unit": "Überschriften"
}, },
"text_auto_read_only_size": { "text_auto_read_only_size": {
"title": "Automatische schreibgeschützte Größe", "title": "Automatische schreibgeschützte Größe",
"description": "Die automatische schreibgeschützte Notizgröße ist die Größe, ab der Notizen im schreibgeschützten Modus angezeigt werden (aus Leistungsgründen).", "description": "Die automatische schreibgeschützte Notizgröße ist die Größe, ab der Notizen im schreibgeschützten Modus angezeigt werden (aus Leistungsgründen).",
"label": "Automatische schreibgeschützte Größe (Textnotizen)", "label": "Automatische schreibgeschützte Größe (Textnotizen)"
"unit": "Zeichen"
}, },
"i18n": { "i18n": {
"title": "Lokalisierung", "title": "Lokalisierung",
"language": "Sprache", "language": "Sprache",
"first-day-of-the-week": "Erster Tag der Woche", "first-day-of-the-week": "Erster Tag der Woche",
"sunday": "Sonntag", "sunday": "Sonntag",
"monday": "Montag", "monday": "Montag"
"first-week-of-the-year": "Erste Woche des Jahres",
"first-week-contains-first-day": "Erste Woche enthält den ersten Tag des Jahres",
"first-week-contains-first-thursday": "Erste Woche enthält den ersten Donnerstag des Jahres",
"first-week-has-minimum-days": "Erste Woche hat Mindestanzahl an Tagen",
"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"
}, },
"backup": { "backup": {
"automatic_backup": "Automatische Sicherung", "automatic_backup": "Automatische Sicherung",
@@ -1358,8 +1303,7 @@
"test_title": "Synchronisierungstest", "test_title": "Synchronisierungstest",
"test_description": "Dadurch werden die Verbindung und der Handshake zum Synchronisierungsserver getestet. Wenn der Synchronisierungsserver nicht initialisiert ist, wird er dadurch für die Synchronisierung mit dem lokalen Dokument eingerichtet.", "test_description": "Dadurch werden die Verbindung und der Handshake zum Synchronisierungsserver getestet. Wenn der Synchronisierungsserver nicht initialisiert ist, wird er dadurch für die Synchronisierung mit dem lokalen Dokument eingerichtet.",
"test_button": "Teste die Synchronisierung", "test_button": "Teste die Synchronisierung",
"handshake_failed": "Handshake des Synchronisierungsservers fehlgeschlagen, Fehler: {{message}}", "handshake_failed": "Handshake des Synchronisierungsservers fehlgeschlagen, Fehler: {{message}}"
"timeout_unit": "Millisekunden"
}, },
"api_log": { "api_log": {
"close": "Schließen" "close": "Schließen"
@@ -1390,7 +1334,7 @@
"button-tree-map": "Baumkarte" "button-tree-map": "Baumkarte"
}, },
"tree-context-menu": { "tree-context-menu": {
"open-in-a-new-tab": "In neuem Tab öffnen", "open-in-a-new-tab": "In neuem Tab öffnen <kbd>Strg+Klick</kbd>",
"open-in-a-new-split": "In neuem Split öffnen", "open-in-a-new-split": "In neuem Split öffnen",
"insert-note-after": "Notiz dahinter einfügen", "insert-note-after": "Notiz dahinter einfügen",
"insert-child-note": "Unternotiz einfügen", "insert-child-note": "Unternotiz einfügen",
@@ -1400,7 +1344,7 @@
"unhoist-note": "Notiz-Fokus aufheben", "unhoist-note": "Notiz-Fokus aufheben",
"edit-branch-prefix": "Zweig-Präfix bearbeiten", "edit-branch-prefix": "Zweig-Präfix bearbeiten",
"advanced": "Erweitert", "advanced": "Erweitert",
"expand-subtree": "Unterzweig aufklappen", "expand-subtree": "Notizbaum ausklappen",
"collapse-subtree": "Notizbaum einklappen", "collapse-subtree": "Notizbaum einklappen",
"sort-by": "Sortieren nach...", "sort-by": "Sortieren nach...",
"recent-changes-in-subtree": "Kürzliche Änderungen im Notizbaum", "recent-changes-in-subtree": "Kürzliche Änderungen im Notizbaum",
@@ -1417,16 +1361,13 @@
"duplicate": "Duplizieren", "duplicate": "Duplizieren",
"export": "Exportieren", "export": "Exportieren",
"import-into-note": "In Notiz importieren", "import-into-note": "In Notiz importieren",
"apply-bulk-actions": "Massenaktionen anwenden", "apply-bulk-actions": "Massenaktionen ausführen",
"converted-to-attachments": "{{count}} Notizen wurden als Anhang konvertiert.", "converted-to-attachments": "{{count}} Notizen wurden als Anhang konvertiert.",
"convert-to-attachment-confirm": "Bist du sicher, dass du die ausgewählten Notizen in Anhänge ihrer übergeordneten Notizen umwandeln möchtest?", "convert-to-attachment-confirm": "Bist du sicher, dass du die ausgewählten Notizen in Anhänge ihrer übergeordneten Notizen umwandeln möchtest?"
"open-in-popup": "Schnellbearbeitung",
"archive": "Archiviere",
"unarchive": "Entarchivieren"
}, },
"shared_info": { "shared_info": {
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}.", "shared_publicly": "Diese Notiz ist öffentlich geteilt auf",
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}.", "shared_locally": "Diese Notiz ist lokal geteilt auf",
"help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>." "help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
}, },
"note_types": { "note_types": {
@@ -1436,7 +1377,7 @@
"relation-map": "Beziehungskarte", "relation-map": "Beziehungskarte",
"note-map": "Notizkarte", "note-map": "Notizkarte",
"render-note": "Render Notiz", "render-note": "Render Notiz",
"mermaid-diagram": "Mermaid Diagramm", "mermaid-diagram": "Mermaid Diagram",
"canvas": "Canvas", "canvas": "Canvas",
"web-view": "Webansicht", "web-view": "Webansicht",
"mind-map": "Mind Map", "mind-map": "Mind Map",
@@ -1446,13 +1387,8 @@
"doc": "Dokument", "doc": "Dokument",
"widget": "Widget", "widget": "Widget",
"confirm-change": "Es is nicht empfehlenswert den Notiz-Typ zu ändern, wenn der Inhalt der Notiz nicht leer ist. Möchtest du dennoch fortfahren?", "confirm-change": "Es is nicht empfehlenswert den Notiz-Typ zu ändern, wenn der Inhalt der Notiz nicht leer ist. Möchtest du dennoch fortfahren?",
"geo-map": "Geo-Karte", "geo-map": "Geo Map",
"beta-feature": "Beta", "beta-feature": "Beta"
"book": "Sammlung",
"ai-chat": "KI Chat",
"task-list": "Aufgabenliste",
"new-feature": "Neu",
"collections": "Sammlungen"
}, },
"protect_note": { "protect_note": {
"toggle-on": "Notiz schützen", "toggle-on": "Notiz schützen",
@@ -1505,8 +1441,7 @@
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)", "hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren", "refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
"create-child-note": "Unternotiz anlegen", "create-child-note": "Unternotiz anlegen",
"unhoist": "Fokus verlassen", "unhoist": "Entfokussieren"
"toggle-sidebar": "Seitenleiste ein-/ausblenden"
}, },
"title_bar_buttons": { "title_bar_buttons": {
"window-on-top": "Dieses Fenster immer oben halten" "window-on-top": "Dieses Fenster immer oben halten"
@@ -1563,9 +1498,7 @@
}, },
"clipboard": { "clipboard": {
"cut": "Notiz(en) wurden in die Zwischenablage ausgeschnitten.", "cut": "Notiz(en) wurden in die Zwischenablage ausgeschnitten.",
"copied": "Notiz(en) wurden in die Zwischenablage kopiert.", "copied": "Notiz(en) wurden in die Zwischenablage kopiert."
"copy_failed": "Speichern in Zwischenablage aufgrund von Berechtigungsproblemen gescheitert.",
"copy_success": "In Zwischenablage kopiert."
}, },
"entrypoints": { "entrypoints": {
"note-revision-created": "Notizrevision wurde erstellt.", "note-revision-created": "Notizrevision wurde erstellt.",
@@ -1587,9 +1520,7 @@
"ws": { "ws": {
"sync-check-failed": "Synchronisationsprüfung fehlgeschlagen!", "sync-check-failed": "Synchronisationsprüfung fehlgeschlagen!",
"consistency-checks-failed": "Konsistenzprüfung fehlgeschlagen! Siehe Logs für Details.", "consistency-checks-failed": "Konsistenzprüfung fehlgeschlagen! Siehe Logs für Details.",
"encountered-error": "Fehler „{{message}}“ aufgetreten, siehe Konsole für Details.", "encountered-error": "Fehler „{{message}}“ aufgetreten, siehe Konsole für Details."
"lost-websocket-connection-title": "Verbindung zum Server verloren",
"lost-websocket-connection-message": "Überprüfe die Konfiguration des Reverse-Proxys (z. B. nginx oder Apache), um sicherzustellen, dass WebSocket-Verbindungen zugelassen und nicht blockiert werden."
}, },
"hoisted_note": { "hoisted_note": {
"confirm_unhoisting": "Die angeforderte Notiz {{requestedNote}} befindet sich außerhalb des hoisted Bereichs der Notiz {{hoistedNote}}. Du musst sie unhoisten, um auf die Notiz zuzugreifen. Möchtest du mit dem Unhoisting fortfahren?" "confirm_unhoisting": "Die angeforderte Notiz {{requestedNote}} befindet sich außerhalb des hoisted Bereichs der Notiz {{hoistedNote}}. Du musst sie unhoisten, um auf die Notiz zuzugreifen. Möchtest du mit dem Unhoisting fortfahren?"
@@ -1611,15 +1542,13 @@
}, },
"highlighting": { "highlighting": {
"description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.", "description": "Steuert die Syntaxhervorhebung für Codeblöcke in Textnotizen, Code-Notizen sind nicht betroffen.",
"color-scheme": "Farbschema", "color-scheme": "Farbschema"
"title": "Code-Blöcke"
}, },
"code_block": { "code_block": {
"word_wrapping": "Wortumbruch", "word_wrapping": "Wortumbruch",
"theme_none": "Keine Syntax-Hervorhebung", "theme_none": "Keine Syntax-Hervorhebung",
"theme_group_light": "Helle Themen", "theme_group_light": "Helle Themen",
"theme_group_dark": "Dunkle Themen", "theme_group_dark": "Dunkle Themen"
"copy_title": "Kopiere in Zwischenablage"
}, },
"classic_editor_toolbar": { "classic_editor_toolbar": {
"title": "Format" "title": "Format"
@@ -1632,11 +1561,11 @@
"label": "Format Toolbar", "label": "Format Toolbar",
"floating": { "floating": {
"title": "Schwebend", "title": "Schwebend",
"description": "Werkzeuge erscheinen in Cursornähe;" "description": "Werkzeuge erscheinen in Cursornähe"
}, },
"fixed": { "fixed": {
"title": "Fixiert", "title": "Fixiert",
"description": "Werkzeuge erscheinen im \"Format\" Tab." "description": "Werkzeuge erscheinen im \"Format\" Tab"
}, },
"multiline-toolbar": "Toolbar wenn nötig in mehreren Zeilen darstellen." "multiline-toolbar": "Toolbar wenn nötig in mehreren Zeilen darstellen."
} }
@@ -1657,15 +1586,14 @@
"link_context_menu": { "link_context_menu": {
"open_note_in_new_tab": "Notiz in neuen Tab öffnen", "open_note_in_new_tab": "Notiz in neuen Tab öffnen",
"open_note_in_new_split": "Notiz in neuen geteilten Tab öffnen", "open_note_in_new_split": "Notiz in neuen geteilten Tab öffnen",
"open_note_in_new_window": "Notiz in neuen Fenster öffnen", "open_note_in_new_window": "Notiz in neuen Fenster öffnen"
"open_note_in_popup": "Schnellbearbeitung"
}, },
"electron_integration": { "electron_integration": {
"desktop-application": "Desktop Anwendung", "desktop-application": "Desktop Anwendung",
"native-title-bar": "Native Anwendungsleiste", "native-title-bar": "Native Anwendungsleiste",
"native-title-bar-description": "In Windows und macOS, sorgt das Deaktivieren der nativen Anwendungsleiste für ein kompakteres Aussehen. Unter Linux, sorgt das Aktivieren der nativen Anwendungsleiste für eine bessere Integration mit anderen Teilen des Systems.", "native-title-bar-description": "In Windows und macOS, sorgt das Deaktivieren der nativen Anwendungsleiste für ein kompakteres Aussehen. Unter Linux, sorgt das Aktivieren der nativen Anwendungsleiste für eine bessere Integration mit anderen Teilen des Systems.",
"background-effects": "Hintergrundeffekte aktivieren (nur Windows 11)", "background-effects": "Hintergrundeffekte aktivieren (nur Windows 11)",
"background-effects-description": "Der Mica Effekt fügt einen unscharfen, stylischen Hintergrund in Anwendungsfenstern ein. Dieser erzeugt Tiefe und ein modernes Auftreten. \"Native Titelleiste\" muss deaktiviert sein.", "background-effects-description": "Der Mica Effekt fügt einen unscharfen, stylischen Hintergrund in Anwendungsfenstern ein. Dieser erzeugt Tiefe und ein modernes Auftreten.",
"restart-app-button": "Anwendung neustarten um Änderungen anzuwenden", "restart-app-button": "Anwendung neustarten um Änderungen anzuwenden",
"zoom-factor": "Zoomfaktor" "zoom-factor": "Zoomfaktor"
}, },
@@ -1678,8 +1606,7 @@
"full-text-search": "Volltextsuche" "full-text-search": "Volltextsuche"
}, },
"note_tooltip": { "note_tooltip": {
"note-has-been-deleted": "Notiz wurde gelöscht.", "note-has-been-deleted": "Notiz wurde gelöscht."
"quick-edit": "Schnellbearbeitung"
}, },
"geo-map": { "geo-map": {
"create-child-note-title": "Neue Unternotiz anlegen und zur Karte hinzufügen", "create-child-note-title": "Neue Unternotiz anlegen und zur Karte hinzufügen",
@@ -1688,8 +1615,7 @@
}, },
"geo-map-context": { "geo-map-context": {
"open-location": "Ort öffnen", "open-location": "Ort öffnen",
"remove-from-map": "Von Karte entfernen", "remove-from-map": "Von Karte entfernen"
"add-note": "Markierung an dieser Position erstellen"
}, },
"help-button": { "help-button": {
"title": "Relevante Hilfeseite öffnen" "title": "Relevante Hilfeseite öffnen"
@@ -1701,371 +1627,9 @@
"days": "Tage" "days": "Tage"
}, },
"time_selector": { "time_selector": {
"invalid_input": "Die eingegebene Zeit ist keine valide Zahl.", "invalid_input": "Die eingegebene Zeit ist keine valide Zahl."
"minimum_input": "Die eingegebene Zeit muss mindestens {{minimumSeconds}} Sekunden entsprechen."
}, },
"modal": { "modal": {
"close": "Schließen", "close": "Schließen"
"help_title": "Zeige mehr Informationen zu diesem Fenster"
},
"ai_llm": {
"n_notes_queued": "{{ count }} Notiz zur Indizierung vorgemerkt",
"n_notes_queued_plural": "{{ count }} Notizen zur Indizierung vorgemerkt",
"notes_indexed": "{{ count }} Notiz indiziert",
"notes_indexed_plural": "{{ count }} Notizen indiziert",
"not_started": "Nicht gestartet",
"title": "KI Einstellungen",
"processed_notes": "Verarbeitete Notizen",
"total_notes": "Gesamt Notizen",
"progress": "Fortschritt",
"queued_notes": "Eingereihte Notizen",
"failed_notes": "Fehlgeschlagenen Notizen",
"last_processed": "Zuletzt verarbeitet",
"refresh_stats": "Statistiken neu laden",
"enable_ai_features": "Aktiviere KI/LLM Funktionen",
"enable_ai_description": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Aktiviere KI/LLM Funktionen",
"enable_ai_desc": "Aktiviere KI-Funktionen wie Notizzusammenfassungen, Inhaltserzeugung und andere LLM-Funktionen",
"provider_configuration": "KI-Anbieterkonfiguration",
"provider_precedence": "Anbieter Priorität",
"provider_precedence_description": "Komma-getrennte Liste von Anbieter in der Reihenfolge ihrer Priorität (z.B. 'openai, anthropic,ollama')",
"temperature": "Temperatur",
"temperature_description": "Regelt die Zufälligkeit in Antworten (0 = deterministisch, 2 = maximale Zufälligkeit)",
"system_prompt": "Systemaufforderung",
"system_prompt_description": "Standard Systemaufforderung für alle KI-Interaktionen",
"openai_configuration": "OpenAI Konfiguration",
"openai_settings": "OpenAI Einstellungen",
"api_key": "API Schlüssel",
"url": "Basis-URL",
"model": "Modell",
"anthropic_settings": "Anthropic Einstellungen",
"partial": "{{ percentage }}% verarbeitet",
"anthropic_api_key_description": "Dein Anthropic API-Key für den Zugriff auf Claude Modelle",
"anthropic_model_description": "Anthropic Claude Modell für Chat-Vervollständigung",
"voyage_settings": "Einstellungen für Voyage AI",
"ollama_url_description": "URL für die Ollama API (Standard: http://localhost:11434)",
"ollama_model_description": "Ollama Modell für Chat-Vervollständigung",
"anthropic_configuration": "Anthropic Konfiguration",
"voyage_configuration": "Voyage AI Konfiguration",
"voyage_url_description": "Standard: https://api.voyageai.com/v1",
"ollama_configuration": "Ollama Konfiguration",
"enable_ollama": "Aktiviere Ollama",
"enable_ollama_description": "Aktiviere Ollama für lokale KI Modell Nutzung",
"ollama_url": "Ollama URL",
"ollama_model": "Ollama Modell",
"refresh_models": "Aktualisiere Modelle",
"refreshing_models": "Aktualisiere...",
"enable_automatic_indexing": "Aktiviere automatische Indizierung",
"rebuild_index": "Index neu aufbauen",
"rebuild_index_error": "Fehler beim Neuaufbau des Index. Prüfe Log für mehr Informationen.",
"retry_failed": "Fehler: Notiz konnte nicht erneut eingereiht werden",
"max_notes_per_llm_query": "Max. Notizen je Abfrage",
"max_notes_per_llm_query_description": "Maximale Anzahl ähnlicher Notizen zum Einbinden als KI Kontext",
"active_providers": "Aktive Anbieter",
"disabled_providers": "Inaktive Anbieter",
"remove_provider": "Entferne Anbieter von Suche",
"restore_provider": "Anbieter zur Suche wiederherstellen",
"similarity_threshold": "Ähnlichkeitsschwelle",
"similarity_threshold_description": "Mindestähnlichkeitswert (0-1) für Notizen, die im Kontext für LLM-Abfragen berücksichtigt werden sollen",
"reprocess_index": "Suchindex neu erstellen",
"reprocessing_index": "Neuerstellung...",
"reprocess_index_started": "Suchindex-Optimierung wurde im Hintergrund gestartet",
"reprocess_index_error": "Fehler beim Wiederaufbau des Suchindex",
"index_rebuild_progress": "Fortschritt der Index-Neuerstellung",
"index_rebuilding": "Optimierung Index ({{percentage}}%)",
"index_rebuild_complete": "Index Optimierung abgeschlossen",
"index_rebuild_status_error": "Fehler bei Überprüfung Status Index Neuerstellung",
"never": "Niemals",
"processing": "Verarbeitung ({{percentage}}%)",
"refreshing": "Aktualisiere...",
"incomplete": "Unvollständig ({{percentage}}%)",
"complete": "Abgeschlossen (100%)",
"auto_refresh_notice": "Auto-Aktualisierung alle {{seconds}} Sekunden",
"note_queued_for_retry": "Notiz in Warteschlange für erneuten Versuch hinzugefügt",
"failed_to_retry_note": "Wiederholungsversuch fehlgeschlagen für Notiz",
"ai_settings": "KI Einstellungen",
"agent": {
"processing": "Verarbeite...",
"thinking": "Nachdenken...",
"loading": "Lade...",
"generating": "Generiere..."
},
"name": "KI",
"openai": "OpenAI",
"use_enhanced_context": "Benutze verbesserten Kontext",
"openai_api_key_description": "Dein OpenAPI-Key für den Zugriff auf den KI-Dienst",
"default_model": "Standardmodell",
"openai_model_description": "Beispiele: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Basis URL",
"openai_url_description": "Standard: https://api.openai.com/v1",
"anthropic_url_description": "Basis URL für Anthropic API (Standard: https://api.anthropic.com)",
"ollama_settings": "Ollama Einstellungen",
"note_title": "Notiz Titel",
"error": "Fehler",
"last_attempt": "Letzter Versuch",
"actions": "Aktionen",
"retry": "Erneut versuchen",
"retry_queued": "Notiz für weiteren Versuch eingereiht",
"empty_key_warning": {
"anthropic": "Anthropic API-Key ist leer. Bitte gültigen API-Key eingeben.",
"openai": "OpenAI API-Key ist leer. Bitte gültigen API-Key eingeben.",
"voyage": "Voyage API-Key ist leer. Bitte gültigen API-Key eingeben.",
"ollama": "Ollama API-Key ist leer. Bitte gültigen API-Key eingeben."
},
"api_key_tooltip": "API-Key für den Zugriff auf den Dienst",
"failed_to_retry_all": "Wiederholungsversuch für Notizen fehlgeschlagen",
"all_notes_queued_for_retry": "Alle fehlgeschlagenen Notizen wurden zur Wiederholung in die Warteschlange gestellt",
"enhanced_context_description": "Versorgt die KI mit mehr Kontext aus der Notiz und den zugehörigen Notizen, um bessere Antworten zu ermöglichen",
"show_thinking": "Zeige Denkprozess",
"show_thinking_description": "Zeige den Denkprozess der KI",
"enter_message": "Geben Sie Ihre Nachricht ein...",
"error_contacting_provider": "Fehler beim Kontaktieren des KI-Anbieters. Bitte überprüfe die Einstellungen und die Internetverbindung.",
"error_generating_response": "Fehler beim Generieren der KI Antwort",
"index_all_notes": "Indiziere alle Notizen",
"index_status": "Indizierungsstatus",
"indexed_notes": "Indizierte Notizen",
"indexing_stopped": "Indizierung gestoppt",
"indexing_in_progress": "Indizierung in Bearbeitung...",
"last_indexed": "Zuletzt Indiziert",
"note_chat": "Notizen-Chat",
"sources": "Quellen",
"start_indexing": "Starte Indizierung",
"use_advanced_context": "Benutze erweiterten Kontext",
"ollama_no_url": "Ollama ist nicht konfiguriert. Bitte trage eine gültige URL ein.",
"chat": {
"root_note_title": "KI Chats",
"root_note_content": "Diese Notiz enthält gespeicherte KI-Chat-Unterhaltungen.",
"new_chat_title": "Neuer Chat",
"create_new_ai_chat": "Erstelle neuen KI Chat"
},
"create_new_ai_chat": "Erstelle neuen KI Chat",
"configuration_warnings": "Es wurden Probleme mit der KI Konfiguration festgestellt. Bitte überprüfe die Einstellungen.",
"experimental_warning": "Die LLM-Funktionen sind aktuell experimentell - sei an dieser Stelle gewarnt.",
"selected_provider": "Ausgewählter Anbieter",
"selected_provider_description": "Wähle einen KI-Anbieter für Chat- und Vervollständigungsfunktionen",
"select_model": "Wähle Modell...",
"select_provider": "Wähle Anbieter...",
"ai_enabled": "KI Funktionen aktiviert",
"ai_disabled": "KI Funktionen deaktiviert",
"no_models_found_online": "Keine Modelle gefunden. Bitte überprüfe den API-Key und die Einstellungen.",
"no_models_found_ollama": "Kein Ollama Modell gefunden. Bitte prüfe, ob Ollama gerade läuft.",
"error_fetching": "Fehler beim Abrufen der Modelle: {{error}}"
},
"zen_mode": {
"button_exit": "Verlasse Zen Modus"
},
"ui-performance": {
"title": "Leistung",
"enable-motion": "Aktiviere Übergänge und Animationen",
"enable-shadows": "Aktiviere Schatten",
"enable-backdrop-effects": "Aktiviere Hintergrundeffekte für Menüs, Pop-up Fenster und Panele",
"enable-smooth-scroll": "Aktiviere sanftes Scrollen",
"app-restart-required": "(Ein Neustart der Anwendung ist erforderlich, damit die Änderungen wirksam werden)"
},
"code-editor-options": {
"title": "Editor"
},
"custom_date_time_format": {
"title": "Benutzerdefiniertes Datums-/Zeitformat",
"description": "Passe das Format des Datums und der Uhrzeit an, die über <shortcut /> oder die Symbolleiste eingefügt werden. Die verfügbaren Format-Tokens sind unter <doc>Day.js docs</doc> zu finden.",
"format_string": "Format Zeichenfolge:",
"formatted_time": "Formatiertes Datum/Uhrzeit:"
},
"multi_factor_authentication": {
"title": "Multi-Faktor-Authentifizierung",
"description": "Die Multi-Faktor-Authentifizierung (MFA) bietet Ihrem Konto eine zusätzliche Sicherheitsebene. Anstatt sich lediglich mit einem Passwort anzumelden, müssen bei der MFA ein oder mehrere zusätzliche Nachweise erbracht werden, um die Identität zu bestätigen. Auf diese Weise kann selbst bei Bekanntwerden des Passworts, ohne die zweite Information nicht auf Ihr Konto zugegriffen werden. Das ist so, als würden Sie ein zusätzliches Schloss an einer Tür anbringen, wodurch es für andere viel schwieriger wird, einzubrechen.<br><br>Befolgen Sie bitte die nachstehenden Anweisungen, um MFA zu aktivieren. Wenn Sie die Konfiguration nicht korrekt vornehmen, erfolgt die Anmeldung weiterhin nur mit dem Passwort.",
"mfa_enabled": "Aktiviere Multi-Faktor-Authentifizierung",
"mfa_method": "MFA Methode",
"electron_disabled": "Multi-Faktor-Authentifizierung wird aktuell nicht in der Desktop-Version unterstützt.",
"totp_title": "Zeitbasiertes Einmalpasswort (TOTP)",
"totp_description": "TOTP (Zeitbasiertes Einmalpasswort) ist eine Sicherheitsfunktion, die einen einzigartigen, temporären Code generiert, der sich alle 30 Sekunden ändert. Sie verwenden diesen Code zusammen mit Ihrem Passwort, um sich bei Ihrem Konto anzumelden, wodurch es für andere Personen wesentlich schwieriger wird, darauf unbefugt zuzugreifen.",
"totp_secret_title": "Generiere TOTP Geheimnis",
"totp_secret_generate": "Generiere TOTP Geheimnis",
"totp_secret_regenerate": "TOTP-Geheimnis neu generieren",
"no_totp_secret_warning": "Um TOTP zu aktivieren, muss zunächst ein TOTP Geheimnis generiert werden.",
"totp_secret_description_warning": "Nach der Generierung des TOTP Geheimnisses ist eine Neuanmeldung mit dem TOTP Geheimnis erforderlich.",
"totp_secret_generated": "TOTP Geheimnis generiert",
"totp_secret_warning": "Bitte speichere das TOTP Geheimnis an einem sicheren Ort. Es wird nicht noch einmal angezeigt.",
"totp_secret_regenerate_confirm": "Möchten Sie das TOTP-Geheimnis wirklich neu generieren? Dadurch werden das bisherige TOTP-Geheimnis und alle vorhandenen Wiederherstellungscodes ungültig.",
"recovery_keys_title": "Einmalige Wiederherstellungsschlüssel",
"recovery_keys_description": "Einmalige Wiederherstellungsschlüssel werden verwendet, um sich anzumelden, falls Sie keinen Zugriff auf Ihre Authentifizierungscodes haben.",
"recovery_keys_description_warning": "Wiederherstellungsschlüssel werden nach dem Verlassen der Seite nicht erneut angezeigt. Bewahren Sie sie an einem sicheren Ort auf.<br>Wiederherstellungsschlüssel können nach ihrer Verwendung nicht erneut verwendet werden.",
"recovery_keys_error": "Fehler beim Generieren der Wiederherstellungscodes",
"recovery_keys_no_key_set": "Keine Wiederherstellungscodes eingerichtet",
"recovery_keys_generate": "Generiere Wiederherstellungscodes",
"recovery_keys_regenerate": "Wiederherstellungscodes erneut generieren",
"recovery_keys_used": "Verwendet: {{date}}",
"recovery_keys_unused": "Wiederherstellungscode {{index}} ist unbenutzt",
"oauth_title": "OAuth/OpenID",
"oauth_description": "OpenID ist ein standardisiertes Verfahren, mit dem Sie sich über ein Konto eines anderen Dienstes, beispielsweise Google, bei Websites anmelden können, um Ihre Identität zu bestätigen. Der Standardaussteller ist Google, Sie können jedoch jeden anderen OpenID-Anbieter auswählen. Weitere Informationen finden Sie <a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">hier</a>. Befolgen Sie diese <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">Anweisungen</a>, um einen OpenID-Dienst über Google einzurichten.",
"oauth_description_warning": "Um OAuth/OpenID zu aktivieren, müssen Sie die OAuth/OpenID-Basis-URL, die Client-ID und den Client-Secret in der Datei config.ini festlegen und die Anwendung neu starten. Wenn Sie die Einstellungen über Umgebungsvariablen vornehmen möchten, legen Sie bitte TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID und TRILIUM_OAUTH_CLIENT_SECRET fest.",
"oauth_missing_vars": "Fehlende Einstellung: {{-variables}}",
"oauth_user_account": "Benutzerkonto: ",
"oauth_user_email": "Benutzer E-Mail: ",
"oauth_user_not_logged_in": "Nicht eingeloggt!"
},
"share": {
"title": "Freigabeeinstellungen",
"redirect_bare_domain": "Hauptdomain zur Freigabeseite weiterleiten",
"redirect_bare_domain_description": "Anonyme Benutzer zur Freigabeseite weiterleiten, anstatt die Anmeldung anzuzeigen",
"show_login_link": "Zeige Anmeldelink im Design der Freigabeseite",
"show_login_link_description": "Füge einen Anmeldelink in der Fußzeile der Freigabeseite hinzu",
"check_share_root": "Status des Freigabe-Roots prüfen",
"share_root_found": "Freigabe-Root-Notiz '{{noteTitle}}' ist bereit",
"share_root_not_found": "Keine Notiz mit #shareRoot Label gefunden",
"share_root_not_shared": "Notiz '{{noteTitle}}' hat das #shareRoot Label, wurde jedoch noch nicht geteilt"
},
"tasks": {
"due": {
"today": "Heute",
"tomorrow": "Morgen",
"yesterday": "Gestern"
}
},
"content_widget": {
"unknown_widget": "Unbekanntes Widget für '{{id}}'."
},
"note_language": {
"not_set": "Nicht gesetzt",
"configure-languages": "Konfiguriere Sprachen..."
},
"content_language": {
"title": "Inhaltssprachen",
"description": "Wähle eine oder mehrere Sprachen aus, die in der Sprachauswahl im Abschnitt „Grundlegende Eigenschaften“ einer schreibgeschützten oder bearbeitbaren Textnotiz angezeigt werden sollen. Dadurch stehen Funktionen wie Rechtschreibprüfung oder Unterstützung für Rechts-nach-Links-Sprachen zur Verfügung."
},
"switch_layout_button": {
"title_vertical": "Bearbeitungsbereich nach unten verschieben",
"title_horizontal": "Bearbeitungsbereich nach links verschieben"
},
"toggle_read_only_button": {
"unlock-editing": "Bearbeitung freischalten",
"lock-editing": "Bearbeitung sperren"
},
"png_export_button": {
"button_title": "Exportiere Diagramm als PNG"
},
"svg": {
"export_to_png": "Das Diagramm konnte als PNG nicht exportiert werden."
},
"code_theme": {
"title": "Aussehen",
"word_wrapping": "Zeilenumbruch",
"color-scheme": "Farbschema"
},
"cpu_arch_warning": {
"title": "Bitte lade die ARM64-Version herunter",
"message_macos": "TriliumNext läuft aktuell über Rosetta 2. Nutzen Sie die Intel-Version (x64) auf einem Apple-Silicon-Mac, wird dadurch die Leistung und Akkulaufzeit deutlich beeinträchtigt.",
"message_windows": "TriliumNext läuft momentan in einer Emulation. Verwenden Sie eine Intel-Version (x64) auf einem Windows ARM Gerät, kann dadurch die Leistung und Akkulaufzeit deutlich beeinträchtigt werden.",
"recommendation": "Für ein optimales Erlebnis lade bitte die native ARM64-Version von TriliumNext von unserer Release-Seite herunter.",
"download_link": "Lade native Version herunter",
"continue_anyway": "Trotzdem fortfahren",
"dont_show_again": "Zeige diese Warnung nicht erneut"
},
"editorfeatures": {
"title": "Funktionen",
"emoji_completion_enabled": "Emoji-Autovervollständigung aktivieren",
"note_completion_enabled": "Automatisches Vervollständigen von Notizen aktivieren",
"emoji_completion_description": "Wenn aktiviert, können Emojis ganz einfach in den Text eingefügt werden, indem man \":\" gefolgt vom Namen eines Emojis eingibt.",
"note_completion_description": "Wenn aktiviert, können Links zu Notizen erstellt werden, indem man \"@\" gefolgt vom Titel einer Notiz eingibt.",
"slash_commands_enabled": "Aktiviere Slash-Befehle",
"slash_commands_description": "Wenn aktiviert, können Bearbeitungsbefehle wie das Einfügen von Zeilenumbrüchen oder Überschriften durch Eingabe von \"/\" aktiviert werden."
},
"table_view": {
"new-row": "Neue Zeile",
"new-column": "Neue Spalte",
"sort-column-by": "Sortiere nach '{{title}}'",
"sort-column-ascending": "Aufsteigend",
"sort-column-descending": "Absteigend",
"sort-column-clear": "Sortierung zurücksetzen",
"hide-column": "Spalte '{{title}}' ausblenden",
"show-hide-columns": "Zeige/verberge Spalten",
"row-insert-above": "Zeile oberhalb einfügen",
"row-insert-below": "Zeile unterhalb einfügen",
"row-insert-child": "Unternotiz einfügen",
"add-column-to-the-left": "Spalte links einfügen",
"add-column-to-the-right": "Spalte rechts einfügen",
"edit-column": "Spalte editieren",
"delete_column_confirmation": "Soll diese Spalte wirklich gelöscht werden? Das entsprechende Attribut wird aus allen Notizen entfernt.",
"delete-column": "Spalte entfernen",
"new-column-label": "Label",
"new-column-relation": "Beziehung"
},
"book_properties_config": {
"hide-weekends": "Wochenenden ausblenden",
"display-week-numbers": "Zeige Kalenderwoche",
"map-style": "Kartenstil:",
"max-nesting-depth": "Maximale Verschachtelungstiefe:",
"raster": "Raster",
"vector_light": "Vektor (Hell)",
"vector_dark": "Vektor (Dunkel)",
"show-scale": "Zeige Skalierung"
},
"table_context_menu": {
"delete_row": "Zeile entfernen"
},
"board_view": {
"delete-note": "Lösche Notiz...",
"move-to": "Verschiebe zu",
"insert-above": "Oberhalb einfügen",
"insert-below": "Unterhalb einfügen",
"delete-column": "Spalte entfernen",
"delete-column-confirmation": "Soll die Spalte wirklich gelöscht werden? Abhängige Attribute werden auch in den Notizen unter dieser Spalte gelöscht.",
"new-item": "Neuer Artikel",
"add-column": "Spalte hinzufügen",
"remove-from-board": "Entferne von Tafel",
"archive-note": "archiviere Notiz",
"unarchive-note": "entarchiviere Notiz",
"new-item-placeholder": "Notiz Titel eingeben...",
"add-column-placeholder": "Spaltenname eingeben...",
"edit-note-title": "Klicke zum Editieren des Notiz-Titels",
"edit-column-title": "Klicke zum Editieren des Spalten-Titels"
},
"command_palette": {
"tree-action-name": "Struktur: {{name}}",
"export_note_title": "Notiz exportieren",
"export_note_description": "aktuelle Notiz exportieren",
"show_attachments_title": "Zeige Anhänge",
"show_attachments_description": "Notizanhänge anzeigen",
"search_notes_title": "Suche Notiz",
"search_notes_description": "Öffne erweiterte Suche",
"search_subtree_title": "Im Unterzweig suchen",
"search_subtree_description": "Im aktuellen Unterzweig suchen",
"search_history_title": "Zeige Suchhistorie",
"search_history_description": "Zeige vorherige Suchen",
"configure_launch_bar_title": "Startleiste anpassen",
"configure_launch_bar_description": "Öffnen Sie die Einstellungen der Startleiste, um Elemente hinzuzufügen oder zu entfernen."
},
"content_renderer": {
"open_externally": "Öffne extern"
},
"call_to_action": {
"next_theme_title": "Teste das neue Trilium Design",
"next_theme_message": "Es wird aktuell das alte Design verwendet. Möchten Sie das neue Design ausprobieren?",
"next_theme_button": "Teste das neue Design",
"background_effects_title": "Hintergrundeffekte sind jetzt zuverlässig nutzbar",
"background_effects_message": "Auf Windows-Geräten sind die Hintergrundeffekte nun vollständig stabil. Die Hintergrundeffekte verleihen der Benutzeroberfläche einen Farbakzent, indem der Hintergrund dahinter weichgezeichnet wird. Diese Technik wird auch in anderen Anwendungen wie dem Windows-Explorer eingesetzt.",
"background_effects_button": "Aktiviere Hintergrundeffekte",
"dismiss": "Ablehnen"
},
"settings": {
"related_settings": "Ähnliche Einstellungen"
},
"settings_appearance": {
"related_code_blocks": "Farbschema für Code-Blöcke in Textnotizen",
"related_code_notes": "Farbschema für Code-Notizen"
},
"units": {
"percentage": "%"
},
"pagination": {
"page_title": "Seite {{startIndex}} von {{endIndex}}",
"total_notes": "{{count}} Notizen"
},
"collections": {
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
} }
} }

View File

@@ -263,11 +263,6 @@
"confirm_delete_all": "Do you want to delete all revisions of this note?", "confirm_delete_all": "Do you want to delete all revisions of this note?",
"no_revisions": "No revisions for this note yet...", "no_revisions": "No revisions for this note yet...",
"restore_button": "Restore", "restore_button": "Restore",
"diff_on": "Show diff",
"diff_off": "Show content",
"diff_on_hint": "Click to show note source diff",
"diff_off_hint": "Click to show note content",
"diff_not_available": "Diff isn't available.",
"confirm_restore": "Do you want to restore this revision? This will overwrite the current title and content of the note with this revision.", "confirm_restore": "Do you want to restore this revision? This will overwrite the current title and content of the note with this revision.",
"delete_button": "Delete", "delete_button": "Delete",
"confirm_delete": "Do you want to delete this revision?", "confirm_delete": "Do you want to delete this revision?",
@@ -582,7 +577,7 @@
"cannot_find_day_note": "Cannot find day note", "cannot_find_day_note": "Cannot find day note",
"cannot_find_week_note": "Cannot find week note", "cannot_find_week_note": "Cannot find week note",
"january": "January", "january": "January",
"february": "February", "febuary": "February",
"march": "March", "march": "March",
"april": "April", "april": "April",
"may": "May", "may": "May",
@@ -592,18 +587,7 @@
"september": "September", "september": "September",
"october": "October", "october": "October",
"november": "November", "november": "November",
"december": "December", "december": "December"
"week": "Week",
"week_previous": "Previous week",
"week_next": "Next week",
"month": "Month",
"month_previous": "Previous month",
"month_next": "Next month",
"year": "Year",
"year_previous": "Previous year",
"year_next": "Next year",
"list": "List",
"today": "Today"
}, },
"close_pane_button": { "close_pane_button": {
"close_this_pane": "Close this pane" "close_this_pane": "Close this pane"
@@ -748,8 +732,7 @@
"note_type": "Note type", "note_type": "Note type",
"editable": "Editable", "editable": "Editable",
"basic_properties": "Basic Properties", "basic_properties": "Basic Properties",
"language": "Language", "language": "Language"
"configure_code_notes": "Configure code notes..."
}, },
"book_properties": { "book_properties": {
"view_type": "View type", "view_type": "View type",
@@ -764,8 +747,7 @@
"calendar": "Calendar", "calendar": "Calendar",
"table": "Table", "table": "Table",
"geo-map": "Geo Map", "geo-map": "Geo Map",
"board": "Board", "board": "Board"
"include_archived_notes": "Show archived notes"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "No edited notes on this day yet...", "no_edited_notes_found": "No edited notes on this day yet...",
@@ -866,7 +848,7 @@
"debug": "debug", "debug": "debug",
"debug_description": "Debug will print extra debugging information into the console to aid in debugging complex queries", "debug_description": "Debug will print extra debugging information into the console to aid in debugging complex queries",
"action": "action", "action": "action",
"search_button": "Search", "search_button": "Search <kbd>enter</kbd>",
"search_execute": "Search & Execute actions", "search_execute": "Search & Execute actions",
"save_to_note": "Save to note", "save_to_note": "Save to note",
"search_parameters": "Search Parameters", "search_parameters": "Search Parameters",
@@ -966,9 +948,7 @@
"no_attachments": "This note has no attachments." "no_attachments": "This note has no attachments."
}, },
"book": { "book": {
"no_children_help": "This collection doesn't have any child notes so there's nothing to display. See <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> for details.", "no_children_help": "This collection doesn't have any child notes so there's nothing to display. See <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> for details."
"drag_locked_title": "Locked for editing",
"drag_locked_message": "Dragging not allowed since the collection is locked for editing."
}, },
"editable_code": { "editable_code": {
"placeholder": "Type the content of your code note here..." "placeholder": "Type the content of your code note here..."
@@ -1133,14 +1113,6 @@
"layout-vertical-description": "launcher bar is on the left (default)", "layout-vertical-description": "launcher bar is on the left (default)",
"layout-horizontal-description": "launcher bar is underneath the tab bar, the tab bar is now full width." "layout-horizontal-description": "launcher bar is underneath the tab bar, the tab bar is now full width."
}, },
"ui-performance": {
"title": "Performance",
"enable-motion": "Enable transitions and animations",
"enable-shadows": "Enable shadows",
"enable-backdrop-effects": "Enable background effects for menus, popups and panels",
"enable-smooth-scroll": "Enable smooth scrolling",
"app-restart-required": "(a restart of the application is required for the change to take effect)"
},
"ai_llm": { "ai_llm": {
"not_started": "Not started", "not_started": "Not started",
"title": "AI Settings", "title": "AI Settings",
@@ -1517,7 +1489,7 @@
"oauth_title": "OAuth/OpenID", "oauth_title": "OAuth/OpenID",
"oauth_description": "OpenID is a standardized way to let you log into websites using an account from another service, like Google, to verify your identity. The default issuer is Google, but you can change it to any other OpenID provider. Check <a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">here</a> for more information. Follow these <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">instructions</a> to setup an OpenID service through Google.", "oauth_description": "OpenID is a standardized way to let you log into websites using an account from another service, like Google, to verify your identity. The default issuer is Google, but you can change it to any other OpenID provider. Check <a href=\"#root/_hidden/_help/_help_Otzi9La2YAUX/_help_WOcw2SLH6tbX/_help_7DAiwaf8Z7Rz\">here</a> for more information. Follow these <a href=\"https://developers.google.com/identity/openid-connect/openid-connect\">instructions</a> to setup an OpenID service through Google.",
"oauth_description_warning": "To enable OAuth/OpenID, you need to set the OAuth/OpenID base URL, client ID and client secret in the config.ini file and restart the application. If you want to set from environment variables, please set TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID and TRILIUM_OAUTH_CLIENT_SECRET.", "oauth_description_warning": "To enable OAuth/OpenID, you need to set the OAuth/OpenID base URL, client ID and client secret in the config.ini file and restart the application. If you want to set from environment variables, please set TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID and TRILIUM_OAUTH_CLIENT_SECRET.",
"oauth_missing_vars": "Missing settings: {{-variables}}", "oauth_missing_vars": "Missing settings: {{variables}}",
"oauth_user_account": "User Account: ", "oauth_user_account": "User Account: ",
"oauth_user_email": "User Email: ", "oauth_user_email": "User Email: ",
"oauth_user_not_logged_in": "Not logged in!" "oauth_user_not_logged_in": "Not logged in!"
@@ -1590,12 +1562,10 @@
"button-tree-map": "Tree map" "button-tree-map": "Tree map"
}, },
"tree-context-menu": { "tree-context-menu": {
"open-in-a-new-tab": "Open in a new tab", "open-in-a-new-tab": "Open in a new tab <kbd>Ctrl+Click</kbd>",
"open-in-a-new-split": "Open in a new split", "open-in-a-new-split": "Open in a new split",
"insert-note-after": "Insert note after", "insert-note-after": "Insert note after",
"insert-child-note": "Insert child note", "insert-child-note": "Insert child note",
"archive": "Archive",
"unarchive": "Unarchive",
"delete": "Delete", "delete": "Delete",
"search-in-subtree": "Search in subtree", "search-in-subtree": "Search in subtree",
"hoist-note": "Hoist note", "hoist-note": "Hoist note",
@@ -1625,8 +1595,8 @@
"open-in-popup": "Quick edit" "open-in-popup": "Quick edit"
}, },
"shared_info": { "shared_info": {
"shared_publicly": "This note is shared publicly on {{- link}}.", "shared_publicly": "This note is shared publicly on",
"shared_locally": "This note is shared locally on {{- link}}.", "shared_locally": "This note is shared locally on",
"help_link": "For help visit <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>." "help_link": "For help visit <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
}, },
"note_types": { "note_types": {
@@ -1705,8 +1675,7 @@
"hoist-this-note-workspace": "Hoist this note (workspace)", "hoist-this-note-workspace": "Hoist this note (workspace)",
"refresh-saved-search-results": "Refresh saved search results", "refresh-saved-search-results": "Refresh saved search results",
"create-child-note": "Create child note", "create-child-note": "Create child note",
"unhoist": "Unhoist", "unhoist": "Unhoist"
"toggle-sidebar": "Toggle sidebar"
}, },
"title_bar_buttons": { "title_bar_buttons": {
"window-on-top": "Keep Window on Top" "window-on-top": "Keep Window on Top"
@@ -1787,9 +1756,7 @@
"ws": { "ws": {
"sync-check-failed": "Sync check failed!", "sync-check-failed": "Sync check failed!",
"consistency-checks-failed": "Consistency checks failed! See logs for details.", "consistency-checks-failed": "Consistency checks failed! See logs for details.",
"encountered-error": "Encountered error \"{{message}}\", check out the console.", "encountered-error": "Encountered error \"{{message}}\", check out the console."
"lost-websocket-connection-title": "Lost connection to the server",
"lost-websocket-connection-message": "Check your reverse proxy (e.g. nginx or Apache) configuration to ensure WebSocket connections are properly allowed and not being blocked."
}, },
"hoisted_note": { "hoisted_note": {
"confirm_unhoisting": "Requested note '{{requestedNote}}' is outside of hoisted note '{{hoistedNote}}' subtree and you must unhoist to access the note. Do you want to proceed with unhoisting?" "confirm_unhoisting": "Requested note '{{requestedNote}}' is outside of hoisted note '{{hoistedNote}}' subtree and you must unhoist to access the note. Do you want to proceed with unhoisting?"
@@ -1865,7 +1832,7 @@
"native-title-bar": "Native title bar", "native-title-bar": "Native title bar",
"native-title-bar-description": "For Windows and macOS, keeping the native title bar off makes the application look more compact. On Linux, keeping the native title bar on integrates better with the rest of the system.", "native-title-bar-description": "For Windows and macOS, keeping the native title bar off makes the application look more compact. On Linux, keeping the native title bar on integrates better with the rest of the system.",
"background-effects": "Enable background effects (Windows 11 only)", "background-effects": "Enable background effects (Windows 11 only)",
"background-effects-description": "The Mica effect adds a blurred, stylish background to app windows, creating depth and a modern look. \"Native title bar\" must be disabled.", "background-effects-description": "The Mica effect adds a blurred, stylish background to app windows, creating depth and a modern look.",
"restart-app-button": "Restart the application to view the changes", "restart-app-button": "Restart the application to view the changes",
"zoom-factor": "Zoom factor" "zoom-factor": "Zoom factor"
}, },
@@ -1964,11 +1931,7 @@
"editorfeatures": { "editorfeatures": {
"title": "Features", "title": "Features",
"emoji_completion_enabled": "Enable Emoji auto-completion", "emoji_completion_enabled": "Enable Emoji auto-completion",
"emoji_completion_description": "If enabled, emojis can be easily inserted into text by typing `:`, followed by the name of an emoji.", "note_completion_enabled": "Enable note auto-completion"
"note_completion_enabled": "Enable note auto-completion",
"note_completion_description": "If enabled, links to notes can be created by typing `@` followed by the title of a note.",
"slash_commands_enabled": "Enable slash commands",
"slash_commands_description": "If enabled, editing commands such as inserting line breaks or headings can be toggled by typing `/`."
}, },
"table_view": { "table_view": {
"new-row": "New row", "new-row": "New row",
@@ -2004,21 +1967,14 @@
"delete_row": "Delete row" "delete_row": "Delete row"
}, },
"board_view": { "board_view": {
"delete-note": "Delete note...", "delete-note": "Delete Note",
"remove-from-board": "Remove from board",
"archive-note": "Archive note",
"unarchive-note": "Unarchive note",
"move-to": "Move to", "move-to": "Move to",
"insert-above": "Insert above", "insert-above": "Insert above",
"insert-below": "Insert below", "insert-below": "Insert below",
"delete-column": "Delete column", "delete-column": "Delete column",
"delete-column-confirmation": "Are you sure you want to delete this column? The corresponding attribute will be deleted in the notes under this column as well.", "delete-column-confirmation": "Are you sure you want to delete this column? The corresponding attribute will be deleted in the notes under this column as well.",
"new-item": "New item", "new-item": "New item",
"new-item-placeholder": "Enter note title...", "add-column": "Add Column"
"add-column": "Add Column",
"add-column-placeholder": "Enter column name...",
"edit-note-title": "Click to edit note title",
"edit-column-title": "Click to edit column title"
}, },
"command_palette": { "command_palette": {
"tree-action-name": "Tree: {{name}}", "tree-action-name": "Tree: {{name}}",
@@ -2060,12 +2016,5 @@
}, },
"units": { "units": {
"percentage": "%" "percentage": "%"
},
"pagination": {
"page_title": "Page of {{startIndex}} - {{endIndex}}",
"total_notes": "{{count}} notes"
},
"collections": {
"rendering_error": "Unable to show content due to an error."
} }
} }

View File

@@ -276,12 +276,7 @@
"mime": "MIME: ", "mime": "MIME: ",
"file_size": "Tamaño del archivo:", "file_size": "Tamaño del archivo:",
"preview": "Vista previa:", "preview": "Vista previa:",
"preview_not_available": "La vista previa no está disponible para este tipo de notas.", "preview_not_available": "La vista previa no está disponible para este tipo de notas."
"diff_off": "Mostrar contenido",
"diff_on": "Mostrar diferencia",
"diff_off_hint": "Haga clic para mostrar el contenido de la nota",
"diff_not_available": "Diferencias no disponibles.",
"diff_on_hint": "Haga clic para ver las diferencias"
}, },
"sort_child_notes": { "sort_child_notes": {
"sort_children_by": "Ordenar hijos por...", "sort_children_by": "Ordenar hijos por...",
@@ -582,7 +577,7 @@
"cannot_find_day_note": "No se puede encontrar la nota del día", "cannot_find_day_note": "No se puede encontrar la nota del día",
"cannot_find_week_note": "No se puede encontrar la nota de la semana", "cannot_find_week_note": "No se puede encontrar la nota de la semana",
"january": "Enero", "january": "Enero",
"february": "Febrero", "febuary": "Febrero",
"march": "Marzo", "march": "Marzo",
"april": "Abril", "april": "Abril",
"may": "Mayo", "may": "Mayo",
@@ -592,18 +587,7 @@
"september": "Septiembre", "september": "Septiembre",
"october": "Octubre", "october": "Octubre",
"november": "Noviembre", "november": "Noviembre",
"december": "Diciembre", "december": "Diciembre"
"week": "Semana",
"week_previous": "Semana anterior",
"week_next": "Semana siguiente",
"month": "Mes",
"month_previous": "Mes anterior",
"month_next": "Mes siguiente",
"year": "Año",
"year_previous": "Año anterior",
"year_next": "Año siguiente",
"list": "Lista",
"today": "Hoy"
}, },
"close_pane_button": { "close_pane_button": {
"close_this_pane": "Cerrar este panel" "close_this_pane": "Cerrar este panel"
@@ -748,8 +732,7 @@
"note_type": "Tipo de nota", "note_type": "Tipo de nota",
"editable": "Editable", "editable": "Editable",
"basic_properties": "Propiedades básicas", "basic_properties": "Propiedades básicas",
"language": "Idioma", "language": "Idioma"
"configure_code_notes": "Configurar notas de código..."
}, },
"book_properties": { "book_properties": {
"view_type": "Tipo de vista", "view_type": "Tipo de vista",
@@ -764,8 +747,7 @@
"book_properties": "Propiedades de colección", "book_properties": "Propiedades de colección",
"table": "Tabla", "table": "Tabla",
"geo-map": "Mapa Geo", "geo-map": "Mapa Geo",
"board": "Tablero", "board": "Tablero"
"include_archived_notes": "Mostrar notas archivadas"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "Aún no hay notas editadas en este día...", "no_edited_notes_found": "Aún no hay notas editadas en este día...",
@@ -866,7 +848,7 @@
"debug": "depurar", "debug": "depurar",
"debug_description": "La depuración imprimirá información de depuración adicional en la consola para ayudar a depurar consultas complejas", "debug_description": "La depuración imprimirá información de depuración adicional en la consola para ayudar a depurar consultas complejas",
"action": "acción", "action": "acción",
"search_button": "Buscar", "search_button": "Buscar <kbd>Enter</kbd>",
"search_execute": "Buscar y ejecutar acciones", "search_execute": "Buscar y ejecutar acciones",
"save_to_note": "Guardar en nota", "save_to_note": "Guardar en nota",
"search_parameters": "Parámetros de búsqueda", "search_parameters": "Parámetros de búsqueda",
@@ -966,9 +948,7 @@
"no_attachments": "Esta nota no tiene archivos adjuntos." "no_attachments": "Esta nota no tiene archivos adjuntos."
}, },
"book": { "book": {
"no_children_help": "Esta nota de tipo libro no tiene ninguna subnota así que no hay nada que mostrar. Véa la <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> para más detalles.", "no_children_help": "Esta nota de tipo libro no tiene ninguna subnota así que no hay nada que mostrar. Véa la <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> para más detalles."
"drag_locked_title": "Bloqueado para edición",
"drag_locked_message": "No se permite Arrastrar pues la colección está bloqueada para edición."
}, },
"editable_code": { "editable_code": {
"placeholder": "Escriba el contenido de su nota de código aquí..." "placeholder": "Escriba el contenido de su nota de código aquí..."
@@ -1273,12 +1253,7 @@
"selected_provider": "Proveedor seleccionado", "selected_provider": "Proveedor seleccionado",
"selected_provider_description": "Elija el proveedor de IA para el chat y características de completado", "selected_provider_description": "Elija el proveedor de IA para el chat y características de completado",
"select_model": "Seleccionar modelo...", "select_model": "Seleccionar modelo...",
"select_provider": "Seleccionar proveedor...", "select_provider": "Seleccionar proveedor..."
"ai_enabled": "Características de IA activadas",
"ai_disabled": "Características de IA desactivadas",
"no_models_found_online": "No se encontraron modelos. Por favor, comprueba tu clave de API y la configuración.",
"no_models_found_ollama": "No se encontraron modelos de Ollama. Por favor, comprueba si Ollama se está ejecutando.",
"error_fetching": "Error al obtener los modelos: {{error}}"
}, },
"zoom_factor": { "zoom_factor": {
"title": "Factor de zoom (solo versión de escritorio)", "title": "Factor de zoom (solo versión de escritorio)",
@@ -1509,7 +1484,7 @@
"oauth_title": "OAuth/OpenID", "oauth_title": "OAuth/OpenID",
"oauth_description": "OpenID es una forma estandarizada de permitirle iniciar sesión en sitios web utilizando una cuenta de otro servicio, como Google, para verificar su identidad. Siga estas <a href = \"https://developers.google.com/identity/openid-connect/openid-connect\">instrucciones</a> para configurar un servicio OpenID a través de Google.", "oauth_description": "OpenID es una forma estandarizada de permitirle iniciar sesión en sitios web utilizando una cuenta de otro servicio, como Google, para verificar su identidad. Siga estas <a href = \"https://developers.google.com/identity/openid-connect/openid-connect\">instrucciones</a> para configurar un servicio OpenID a través de Google.",
"oauth_description_warning": "Para habilitar OAuth/OpenID, necesita establecer la URL base de OAuth/OpenID, ID de cliente y secreto de cliente en el archivo config.ini y reiniciar la aplicación. Si desea establecerlas desde variables de ambiente, por favor establezca TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID y TRILIUM_OAUTH_CLIENT_SECRET.", "oauth_description_warning": "Para habilitar OAuth/OpenID, necesita establecer la URL base de OAuth/OpenID, ID de cliente y secreto de cliente en el archivo config.ini y reiniciar la aplicación. Si desea establecerlas desde variables de ambiente, por favor establezca TRILIUM_OAUTH_BASE_URL, TRILIUM_OAUTH_CLIENT_ID y TRILIUM_OAUTH_CLIENT_SECRET.",
"oauth_missing_vars": "Ajustes faltantes: {{-variables}}", "oauth_missing_vars": "Ajustes faltantes: {{variables}}",
"oauth_user_account": "Cuenta de usuario: ", "oauth_user_account": "Cuenta de usuario: ",
"oauth_user_email": "Correo electrónico de usuario: ", "oauth_user_email": "Correo electrónico de usuario: ",
"oauth_user_not_logged_in": "¡No ha iniciado sesión!" "oauth_user_not_logged_in": "¡No ha iniciado sesión!"
@@ -1582,7 +1557,7 @@
"button-tree-map": "Mapa de Árbol" "button-tree-map": "Mapa de Árbol"
}, },
"tree-context-menu": { "tree-context-menu": {
"open-in-a-new-tab": "Abrir en nueva pestaña", "open-in-a-new-tab": "Abrir en nueva pestaña <kbd>Ctrl+Click</kbd>",
"open-in-a-new-split": "Abrir en nueva división", "open-in-a-new-split": "Abrir en nueva división",
"insert-note-after": "Insertar nota después de", "insert-note-after": "Insertar nota después de",
"insert-child-note": "Insertar subnota", "insert-child-note": "Insertar subnota",
@@ -1612,13 +1587,11 @@
"apply-bulk-actions": "Aplicar acciones en lote", "apply-bulk-actions": "Aplicar acciones en lote",
"converted-to-attachments": "{{count}} notas han sido convertidas en archivos adjuntos.", "converted-to-attachments": "{{count}} notas han sido convertidas en archivos adjuntos.",
"convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?", "convert-to-attachment-confirm": "¿Está seguro que desea convertir las notas seleccionadas en archivos adjuntos de sus notas padres?",
"open-in-popup": "Edición rápida", "open-in-popup": "Edición rápida"
"archive": "Archivar",
"unarchive": "Desarchivar"
}, },
"shared_info": { "shared_info": {
"shared_publicly": "Esta nota está compartida públicamente en {{- link}}", "shared_publicly": "Esta nota está compartida públicamente en",
"shared_locally": "Esta nota está compartida localmente en {{- link}}", "shared_locally": "Esta nota está compartida localmente en",
"help_link": "Para obtener ayuda visite <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>." "help_link": "Para obtener ayuda visite <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
}, },
"note_types": { "note_types": {
@@ -1697,8 +1670,7 @@
"hoist-this-note-workspace": "Anclar esta nota (espacio de trabajo)", "hoist-this-note-workspace": "Anclar esta nota (espacio de trabajo)",
"refresh-saved-search-results": "Refrescar resultados de búsqueda guardados", "refresh-saved-search-results": "Refrescar resultados de búsqueda guardados",
"create-child-note": "Crear subnota", "create-child-note": "Crear subnota",
"unhoist": "Desanclar", "unhoist": "Desanclar"
"toggle-sidebar": "Alternar barra lateral"
}, },
"title_bar_buttons": { "title_bar_buttons": {
"window-on-top": "Mantener esta ventana en la parte superior" "window-on-top": "Mantener esta ventana en la parte superior"
@@ -1773,15 +1745,13 @@
"undeleting-notes-finished-successfully": "La recuperación de notas finalizó exitosamente." "undeleting-notes-finished-successfully": "La recuperación de notas finalizó exitosamente."
}, },
"frontend_script_api": { "frontend_script_api": {
"async_warning": "Está pasando una función asíncrona a `api.runOnBackend ()` que probablemente no funcionará como pretendía.\\nO haga la función sincrónica (removiendo la palabra `async`), o use `api.runAsyncOnBackendWithManualTransactionHandling()`.", "async_warning": "Está pasando una función asíncrona a `api.runOnBackend ()` que probablemente no funcionará como pretendía.",
"sync_warning": "Estás pasando una función sincrónica a `api.runasynconbackendwithmanualTransactionHandling ()`, \\n while debería usar `api.runonbackend ()` en su lugar." "sync_warning": "Estás pasando una función sincrónica a `api.runasynconbackendwithmanualTransactionHandling ()`, \\ n while debería usar `api.runonbackend ()` en su lugar."
}, },
"ws": { "ws": {
"sync-check-failed": "¡La comprobación de sincronización falló!", "sync-check-failed": "¡La comprobación de sincronización falló!",
"consistency-checks-failed": "¡Las comprobaciones de consistencia fallaron! Vea los registros para más detalles.", "consistency-checks-failed": "¡Las comprobaciones de consistencia fallaron! Vea los registros para más detalles.",
"encountered-error": "Error encontrado \"{{message}}\", compruebe la consola.", "encountered-error": "Error encontrado \"{{message}}\", compruebe la consola."
"lost-websocket-connection-title": "Se ha perdido la conexión con el servidor",
"lost-websocket-connection-message": "Compruebe la configuración de su proxy inverso (por ejemplo, nginx o Apache) para asegurarse de que las conexiones WebSocket están correctamente permitidas y no están bloqueadas."
}, },
"hoisted_note": { "hoisted_note": {
"confirm_unhoisting": "La nota requerida '{{requestedNote}}' está fuera del subárbol de la nota anclada '{{hoistedNote}}' y debe desanclarla para acceder a la nota. ¿Desea proceder con el desanclaje?" "confirm_unhoisting": "La nota requerida '{{requestedNote}}' está fuera del subárbol de la nota anclada '{{hoistedNote}}' y debe desanclarla para acceder a la nota. ¿Desea proceder con el desanclaje?"
@@ -1857,7 +1827,7 @@
"native-title-bar": "Barra de título nativa", "native-title-bar": "Barra de título nativa",
"native-title-bar-description": "Para Windows y macOS, quitar la barra de título nativa hace que la aplicación se vea más compacta. En Linux, mantener la barra de título nativa hace que se integre mejor con el resto del sistema.", "native-title-bar-description": "Para Windows y macOS, quitar la barra de título nativa hace que la aplicación se vea más compacta. En Linux, mantener la barra de título nativa hace que se integre mejor con el resto del sistema.",
"background-effects": "Habilitar efectos de fondo (sólo en Windows 11)", "background-effects": "Habilitar efectos de fondo (sólo en Windows 11)",
"background-effects-description": "El efecto Mica agrega un fondo borroso y elegante a las ventanas de la aplicación, creando profundidad y un aspecto moderno. \"Título nativo de la barra\" debe deshabilitarse.", "background-effects-description": "El efecto Mica agrega un fondo borroso y elegante a las ventanas de aplicaciones, creando profundidad y un aspecto moderno.",
"restart-app-button": "Reiniciar la aplicación para ver los cambios", "restart-app-button": "Reiniciar la aplicación para ver los cambios",
"zoom-factor": "Factor de zoom" "zoom-factor": "Factor de zoom"
}, },
@@ -1967,20 +1937,14 @@
"delete_row": "Eliminar fila" "delete_row": "Eliminar fila"
}, },
"board_view": { "board_view": {
"delete-note": "Eliminar nota...", "delete-note": "Eliminar nota",
"move-to": "Mover a", "move-to": "Mover a",
"insert-above": "Insertar arriba", "insert-above": "Insertar arriba",
"insert-below": "Insertar abajo", "insert-below": "Insertar abajo",
"delete-column": "Eliminar columna", "delete-column": "Eliminar columna",
"delete-column-confirmation": "¿Seguro que desea eliminar esta columna? El atributo correspondiente también se eliminará de las notas de esta columna.", "delete-column-confirmation": "¿Seguro que desea eliminar esta columna? El atributo correspondiente también se eliminará de las notas de esta columna.",
"add-column": "Añadir columna", "add-column": "Añadir columna",
"new-item": "Nuevo elemento", "new-item": "Nuevo elemento"
"archive-note": "Archivar nota",
"unarchive-note": "Desarchivar nota",
"new-item-placeholder": "Ingresar título de la nota...",
"add-column-placeholder": "Ingresar título de la columna...",
"edit-note-title": "Haga clic para editar el título de la nota",
"edit-column-title": "Haga clic para editar el título de la columna"
}, },
"content_renderer": { "content_renderer": {
"open_externally": "Abrir externamente" "open_externally": "Abrir externamente"
@@ -2008,11 +1972,7 @@
"editorfeatures": { "editorfeatures": {
"note_completion_enabled": "Activar autocompletado de notas", "note_completion_enabled": "Activar autocompletado de notas",
"emoji_completion_enabled": "Activar autocompletado de emojis", "emoji_completion_enabled": "Activar autocompletado de emojis",
"title": "Funciones", "title": "Funciones"
"emoji_completion_description": "Si está habilitado, los emojis pueden fácilmente insertarse en el texto escribiendo `:`, seguido del nombre de un emoji.",
"note_completion_description": "Si está habilitado, los vínculos a notas pueden crearse escribiendo `@` seguido del título de una nota.",
"slash_commands_enabled": "Habilitar comandos de barra",
"slash_commands_description": "Si está habilitado, editar comandos como insertar saltos de línea o títulos, puede alternarse escribiendo `/`."
}, },
"command_palette": { "command_palette": {
"tree-action-name": "Árbol:{{name}}", "tree-action-name": "Árbol:{{name}}",
@@ -2041,27 +2001,5 @@
"background_effects_message": "En los dispositivos Windows, los efectos de fondo ya son totalmente estables. Los efectos de fondo añaden un toque de color a la interfaz de usuario difuminando el fondo que hay detrás. Esta técnica también se utiliza en otras aplicaciones como el Explorador de Windows.", "background_effects_message": "En los dispositivos Windows, los efectos de fondo ya son totalmente estables. Los efectos de fondo añaden un toque de color a la interfaz de usuario difuminando el fondo que hay detrás. Esta técnica también se utiliza en otras aplicaciones como el Explorador de Windows.",
"background_effects_button": "Activar efectos de fondo", "background_effects_button": "Activar efectos de fondo",
"dismiss": "Desestimar" "dismiss": "Desestimar"
},
"ui-performance": {
"title": "Rendimiento",
"enable-motion": "Habilitar transiciones y animaciones",
"enable-shadows": "Activar sombras",
"enable-backdrop-effects": "Habilitar efectos de fondo para menús, ventanas emergentes y paneles",
"enable-smooth-scroll": "Habilitar desplazamiento suave",
"app-restart-required": "(es necesario reiniciar la aplicación para que el cambio surta efecto)"
},
"settings": {
"related_settings": "Configuración relacionada"
},
"settings_appearance": {
"related_code_blocks": "Esquema de colores para bloques de código en notas de texto",
"related_code_notes": "Esquema de colores para notas de código"
},
"units": {
"percentage": "%"
},
"pagination": {
"total_notes": "{{count}} notas",
"page_title": "Página de {{startIndex}} - {{endIndex}}"
} }
} }

View File

@@ -15,9 +15,6 @@
}, },
"widget-error": { "widget-error": {
"title": "Widgetin luonti epäonnistui" "title": "Widgetin luonti epäonnistui"
},
"bundle-error": {
"title": "Mukautetun skriptin lataus epäonnistui"
} }
}, },
"add_link": { "add_link": {

View File

@@ -576,7 +576,7 @@
"sun": "Dim", "sun": "Dim",
"cannot_find_day_note": "Note journalière introuvable", "cannot_find_day_note": "Note journalière introuvable",
"january": "Janvier", "january": "Janvier",
"february": "Février", "febuary": "Février",
"march": "Mars", "march": "Mars",
"april": "Avril", "april": "Avril",
"may": "Mai", "may": "Mai",
@@ -587,18 +587,7 @@
"october": "Octobre", "october": "Octobre",
"november": "Novembre", "november": "Novembre",
"december": "Décembre", "december": "Décembre",
"cannot_find_week_note": "Impossible de trouver la note de la semaine", "cannot_find_week_note": "Impossible de trouver la note de la semaine"
"week": "Semaine",
"week_previous": "Semaine précédente",
"week_next": "Semaine suivante",
"month": "Mois",
"month_previous": "Mois précédent",
"month_next": "Mois suivant",
"year": "Année",
"year_previous": "Année précédente",
"year_next": "Année suivante",
"list": "Liste",
"today": "Aujourd'hui"
}, },
"close_pane_button": { "close_pane_button": {
"close_this_pane": "Fermer ce volet" "close_this_pane": "Fermer ce volet"
@@ -743,8 +732,7 @@
"note_type": "Type de note", "note_type": "Type de note",
"editable": "Modifiable", "editable": "Modifiable",
"basic_properties": "Propriétés de base", "basic_properties": "Propriétés de base",
"language": "Langage", "language": "Langage"
"configure_code_notes": "Configurer les notes de code..."
}, },
"book_properties": { "book_properties": {
"view_type": "Type d'affichage", "view_type": "Type d'affichage",
@@ -759,8 +747,7 @@
"book_properties": "Propriétés de la collection", "book_properties": "Propriétés de la collection",
"table": "Tableau", "table": "Tableau",
"geo-map": "Carte géographique", "geo-map": "Carte géographique",
"board": "Tableau de bord", "board": "Tableau de bord"
"include_archived_notes": "Afficher les notes archivées"
}, },
"edited_notes": { "edited_notes": {
"no_edited_notes_found": "Aucune note modifiée ce jour-là...", "no_edited_notes_found": "Aucune note modifiée ce jour-là...",
@@ -861,7 +848,7 @@
"debug": "debug", "debug": "debug",
"debug_description": "Debug imprimera des informations supplémentaires dans la console pour faciliter le débogage des requêtes complexes", "debug_description": "Debug imprimera des informations supplémentaires dans la console pour faciliter le débogage des requêtes complexes",
"action": "action", "action": "action",
"search_button": "Recherche", "search_button": "Recherche <kbd>Entrée</kbd>",
"search_execute": "Rechercher et exécuter des actions", "search_execute": "Rechercher et exécuter des actions",
"save_to_note": "Enregistrer dans la note", "save_to_note": "Enregistrer dans la note",
"search_parameters": "Paramètres de recherche", "search_parameters": "Paramètres de recherche",
@@ -961,9 +948,7 @@
"no_attachments": "Cette note ne contient aucune pièce jointe." "no_attachments": "Cette note ne contient aucune pièce jointe."
}, },
"book": { "book": {
"no_children_help": "Cette note de type Livre n'a aucune note enfant, donc il n'y a rien à afficher. Consultez le <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> pour plus de détails.", "no_children_help": "Cette note de type Livre n'a aucune note enfant, donc il n'y a rien à afficher. Consultez le <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> pour plus de détails."
"drag_locked_title": "Edition verrouillée",
"drag_locked_message": "Le glisser-déposer n'est pas autorisé car l'édition de cette collection est verrouillé."
}, },
"editable_code": { "editable_code": {
"placeholder": "Saisir le contenu de votre note de code ici..." "placeholder": "Saisir le contenu de votre note de code ici..."
@@ -1372,7 +1357,7 @@
"button-tree-map": "Carte de l'arborescence" "button-tree-map": "Carte de l'arborescence"
}, },
"tree-context-menu": { "tree-context-menu": {
"open-in-a-new-tab": "Ouvrir dans un nouvel onglet", "open-in-a-new-tab": "Ouvrir dans un nouvel onglet <kbd>Ctrl+Clic</kbd>",
"open-in-a-new-split": "Ouvrir dans une nouvelle division", "open-in-a-new-split": "Ouvrir dans une nouvelle division",
"insert-note-after": "Insérer une note après", "insert-note-after": "Insérer une note après",
"insert-child-note": "Insérer une note enfant", "insert-child-note": "Insérer une note enfant",
@@ -1404,8 +1389,8 @@
"convert-to-attachment-confirm": "Êtes-vous sûr de vouloir convertir les notes sélectionnées en pièces jointes de leurs notes parentes ?" "convert-to-attachment-confirm": "Êtes-vous sûr de vouloir convertir les notes sélectionnées en pièces jointes de leurs notes parentes ?"
}, },
"shared_info": { "shared_info": {
"shared_publicly": "Cette note est partagée publiquement sur {{- link}}", "shared_publicly": "Cette note est partagée publiquement sur",
"shared_locally": "Cette note est partagée localement sur {{- link}}", "shared_locally": "Cette note est partagée localement sur",
"help_link": "Pour obtenir de l'aide, visitez le <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>." "help_link": "Pour obtenir de l'aide, visitez le <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
}, },
"note_types": { "note_types": {
@@ -1695,82 +1680,6 @@
"n_notes_queued_2": "", "n_notes_queued_2": "",
"notes_indexed_0": "{{ count }} note indexée", "notes_indexed_0": "{{ count }} note indexée",
"notes_indexed_1": "{{ count }} notes indexées", "notes_indexed_1": "{{ count }} notes indexées",
"notes_indexed_2": "", "notes_indexed_2": ""
"anthropic_url_description": "URL de base pour l'API Anthropic (par défaut : https ://api.anthropic.com)",
"anthropic_model_description": "Modèles Anthropic Claude pour la complétion",
"voyage_settings": "Réglages d'IA Voyage",
"ollama_settings": "Réglages Ollama",
"ollama_url_description": "URL pour l'API Ollama (par défaut: http://localhost:11434)",
"ollama_model_description": "Model Ollama utilisé pour la complétion",
"anthropic_configuration": "Configuration Anthropic",
"voyage_configuration": "Configuration IA Voyage",
"voyage_url_description": "Défaut: https://api.voyageai.com/v1",
"ollama_configuration": "Configuration Ollama",
"total_notes": "Notes totales",
"progress": "Progrès",
"queued_notes": "Notes dans la file d'attente",
"refresh_stats": "Rafraîchir les statistiques",
"enable_ai_features": "Activer les fonctionnalités IA/LLM",
"enable_ai_description": "Activer les fonctionnalités IA telles que le résumé des notes, la génération de contenu et autres fonctionnalités LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Activer les fonctionnalités IA/LLM",
"enable_ai_desc": "Activer les fonctionnalités IA telles que le résumé des notes, la génération de contenu et autres fonctionnalités LLM",
"provider_configuration": "Configuration du fournisseur IA",
"provider_precedence_description": "Liste de fournisseurs séparés par virgule, par ordre de préférence (ex. 'openai,anthopic,ollama')",
"temperature": "Température",
"temperature_description": "Contrôle de l'aléatoirité dans les réponses (0 = déterministe, 2 = hasard maximum)",
"system_prompt": "Prompt système",
"system_prompt_description": "Prompt système par défaut pour toutes les intéractions IA",
"openai_configuration": "Configuration OpenAI",
"openai_settings": "Options OpenAI",
"api_key": "Clef API",
"url": "URL de base",
"model": "Modèle",
"openai_api_key_description": "Votre clef API OpenAI pour accéder à leurs services IA",
"anthropic_api_key_description": "Votre clef API Anthropic pour accéder aux modèles Claude",
"default_model": "Modèle par défaut",
"openai_model_description": "Exemples : gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "URL de base",
"openai_url_description": "Défaut : https://api.openai.com/v1",
"anthropic_settings": "Réglages Anthropic",
"enable_ollama": "Activer Ollama",
"enable_ollama_description": "Activer Ollama comme modèle d'IA local",
"ollama_url": "URL Ollama",
"ollama_model": "Modèle Ollama",
"refresh_models": "Rafraîchir les modèles",
"refreshing_models": "Mise à jour...",
"enable_automatic_indexing": "Activer l'indexage automatique",
"rebuild_index": "Rafraîchir l'index",
"rebuild_index_error": "Erreur dans le démarrage du rafraichissement de l'index. Veuillez consulter les logs pour plus de détails.",
"note_title": "Titre de la note",
"error": "Erreur",
"last_attempt": "Dernier essai",
"actions": "Actions",
"retry": "Réessayer",
"partial": "Complété à {{ percentage }}%",
"retry_queued": "Note ajoutée à la file d'attente",
"retry_failed": "Echec de l'ajout de la note à la file d'attente",
"max_notes_per_llm_query": "Notes maximum par requête",
"max_notes_per_llm_query_description": "Nombre maximum de notes similaires à inclure dans le contexte IA",
"active_providers": "Fournisseurs actifs",
"disabled_providers": "Fournisseurs désactivés",
"remove_provider": "Retirer le fournisseur de la recherche",
"similarity_threshold": "Seuil de similarité",
"similarity_threshold_description": "Seuil de similarité minimum (0-1) pour que inclure les notes dans le contexte d'une requête IA",
"reprocess_index": "Rafraîchir l'index de recherche",
"reprocessing_index": "Mise à jour...",
"reprocess_index_started": "L'optimisation de l'indice de recherche à commencer en arrière-plan",
"reprocess_index_error": "Erreur dans le rafraichissement de l'indice de recherche"
},
"ui-performance": {
"title": "Performance",
"enable-motion": "Activer les transitions et animations",
"enable-shadows": "Activer les ombres",
"enable-backdrop-effects": "Activer les effets d'arrière plan pour les menus, popups et panneaux",
"enable-smooth-scroll": "Active le défilement fluide",
"app-restart-required": "(redémarrer l'application pour appliquer les changements)"
} }
} }

View File

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

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