Compare commits

..

2 Commits

Author SHA1 Message Date
Elian Doran
8f6912cd57 chore(electron-builder): add build settings in package.json 2025-08-14 17:04:47 +03:00
Elian Doran
d32dbf40f8 chore(electron-builder): install dep 2025-08-14 16:15:52 +03:00
784 changed files with 35930 additions and 47531 deletions

View File

@@ -1,6 +1,6 @@
root = true
[*.{js,ts,tsx}]
[*.{js,ts}]
charset = utf-8
end_of_line = lf
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
shell: ${{ inputs.shell }}
run: pnpm run chore:update-build-info
run: npm run chore:update-build-info
# Critical debugging configuration
- name: Run electron-forge build with enhanced logging
@@ -86,8 +86,7 @@ runs:
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
TARGET_ARCH: ${{ inputs.arch }}
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
run: pnpm nx --project=desktop electron-forge:make -- --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
# Add DMG signing step
- name: Sign DMG

View File

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

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

@@ -12,7 +12,6 @@ jobs:
steps:
- name: Check if PRs have conflicts
uses: eps1lon/actions-label-merge-conflict@v3
if: github.repository == ${{ vars.REPO_MAIN }}
with:
dirtyLabel: "merge-conflicts"
repoToken: "${{ secrets.MERGE_CONFLICT_LABEL_PAT }}"

View File

@@ -1,188 +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"
# Install wrangler globally to avoid workspace issues
- name: Install Wrangler
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: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site --project-name=trilium-docs --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: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site --project-name=trilium-docs --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
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.issue.number;
// Construct preview URL based on Cloudflare Pages pattern
const previewUrl = `https://pr-${prNumber}.trilium-docs.pages.dev`;
const mainUrl = 'https://docs.triliumnotes.org';
// Check if we already commented
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Documentation preview is ready')
);
const commentBody = `📚 Documentation preview is ready!\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
});
}

View File

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

View File

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

View File

@@ -27,7 +27,7 @@ permissions:
jobs:
nightly-electron:
if: github.repository == ${{ vars.REPO_MAIN }}
if: github.repository == 'TriliumNext/Trilium'
name: Deploy nightly
strategy:
fail-fast: false
@@ -51,12 +51,13 @@ jobs:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
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: Update nightly version
run: npm run chore:ci-update-nightly-version
- name: Run the build
@@ -78,7 +79,7 @@ jobs:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
- name: Publish release
uses: softprops/action-gh-release@v2.3.3
uses: softprops/action-gh-release@v2.3.2
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false
@@ -97,7 +98,7 @@ jobs:
path: apps/desktop/upload
nightly-server:
if: github.repository == ${{ vars.REPO_MAIN }}
if: github.repository == 'TriliumNext/Trilium'
name: Deploy server nightly
strategy:
fail-fast: false
@@ -119,7 +120,7 @@ jobs:
arch: ${{ matrix.arch }}
- name: Publish release
uses: softprops/action-gh-release@v2.3.3
uses: softprops/action-gh-release@v2.3.2
if: ${{ github.event_name != 'pull_request' }}
with:
make_latest: false

View File

@@ -19,8 +19,14 @@ jobs:
filter: tree: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: actions/setup-node@v5
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
@@ -28,12 +34,10 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps
- uses: nrwl/nx-set-shas@v4
- run: pnpm --filter server-e2e e2e
- name: Upload test report
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e report
path: apps/server-e2e/test-output
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
# - run: npx nx-cloud record -- echo Hello World
# Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected
# When you enable task distribution, run the e2e-ci task instead of e2e
- run: pnpm exec nx affected -t e2e --exclude desktop-e2e

View File

@@ -30,30 +30,18 @@ jobs:
image: win-signing
shell: cmd
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 }}
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- name: Set up node & dependencies
uses: actions/setup-node@v5
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: Run the build
uses: ./.github/actions/build-electron
with:
@@ -127,7 +115,7 @@ jobs:
path: upload
- name: Publish stable release
uses: softprops/action-gh-release@v2.3.3
uses: softprops/action-gh-release@v2.3.2
with:
draft: false
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md

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.
/.cache
# compiled output
dist
@@ -33,11 +32,14 @@ testem.log
.DS_Store
Thumbs.db
.nx/cache
.nx/workspace-data
vite.config.*.timestamp*
vitest.config.*.timestamp*
test-output
apps/*/data*
apps/*/data
apps/*/out
upload
@@ -45,7 +47,4 @@ upload
*.tsbuildinfo
/result
.svelte-kit
# docs
site/
.svelte-kit

2
.nvmrc
View File

@@ -1 +1 @@
22.19.0
22.18.0

View File

@@ -5,6 +5,7 @@
"lokalise.i18n-ally",
"ms-azuretools.vscode-docker",
"ms-playwright.playwright",
"nrwl.angular-console",
"redhat.vscode-yaml",
"tobermory.es6-string-html",
"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,
"apps/server/src/assets/doc_notes/**": true,
"apps/edit-docs/demo/**": true
}
},
"nxConsole.generateAiAgentRules": true
}

View File

@@ -20,10 +20,5 @@
"scope": "typescript",
"prefix": "jqf",
"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
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
@@ -14,9 +14,12 @@ Trilium Notes is a hierarchical note-taking application with advanced features l
### Running Applications
- `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
### Building
- `pnpm nx build <project>` - Build specific project (server, client, desktop, etc.)
- `pnpm run client:build` - Build client application
- `pnpm run server:build` - Build server 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:parallel` - Run tests that can run in parallel
- `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
### Linting & Type Checking
- `pnpm nx run <project>:lint` - Lint specific project
- `pnpm nx run <project>:typecheck` - Type check specific project
## Architecture Overview
### 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
4. **Configuration**:
- `nx.json` - NX workspace configuration
- `package.json` - Project dependencies and scripts
## Note Types and Features
@@ -145,7 +154,7 @@ Trilium provides powerful user scripting capabilities:
- Update schema in `apps/server/src/assets/db/schema.sql`
## Build System Notes
- Uses pnpm for monorepo management
- Uses NX for monorepo management with build caching
- Vite for fast development builds
- ESBuild for production optimization
- pnpm workspaces for dependency management

View File

@@ -1,8 +1,8 @@
# Trilium Notes
![GitHub Sponsors](https://img.shields.io/github/sponsors/eliandoran) ![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/trilium)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/notes)
![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/triliumnext/notes/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/)
[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)
@@ -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>
## 📚 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
* 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))
@@ -63,15 +46,28 @@ Our documentation is available in multiple formats:
- [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
- [TriliumRocks!](https://trilium.rocks/) for tutorials, guides, and much more.
## Why TriliumNext?
## ⚠️ Why TriliumNext?
The original Trilium developer ([Zadam](https://github.com/zadam)) has graciously given the Trilium repository to the community project which resides at https://github.com/TriliumNext
[The original Trilium project is in maintenance mode](https://github.com/zadam/trilium/issues/4620).
### ⬆️Migrating from Zadam/Trilium?
### Migrating from Trilium?
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/Notes instance. Simply [install TriliumNext/Notes](#-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/Notes/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 have their sync versions incremented.
## 📖 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
@@ -79,8 +75,8 @@ Feel free to join our official conversations. We would love to hear what feature
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions.)
- The `General` Matrix room is also bridged to [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
- [Github Discussions](https://github.com/TriliumNext/Trilium/discussions) (For asynchronous discussions.)
- [Github Issues](https://github.com/TriliumNext/Trilium/issues) (For bug reports and feature requests.)
- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For asynchronous discussions.)
- [Github Issues](https://github.com/TriliumNext/Notes/issues) (For bug reports and feature requests.)
## 🏗 Installation
@@ -108,11 +104,9 @@ Currently only the latest versions of Chrome & Firefox are supported (and tested
To use TriliumNext on a mobile device, you can use a mobile web browser to access the mobile interface of a server installation (see below).
See issue https://github.com/TriliumNext/Trilium/issues/4962 for more information on mobile app support.
If you prefer a native Android app, you can use [TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid). Report bugs and missing features at [their repository](https://github.com/FliegendeWurst/TriliumDroid).
If you prefer a native Android app, you can use [TriliumDroid](https://apt.izzysoft.de/fdroid/index/apk/eu.fliegendewurst.triliumdroid).
Report bugs and missing features at [their repository](https://github.com/FliegendeWurst/TriliumDroid).
Note: It is best to disable automatic updates on your server installation (see below) when using TriliumDroid since the sync version must match between Trilium and TriliumDroid.
See issue https://github.com/TriliumNext/Notes/issues/72 for more information on mobile app support.
### Server
@@ -146,7 +140,7 @@ Download the repository, install dependencies using `pnpm` and then run the envi
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
pnpm install
pnpm edit-docs:edit-docs
pnpm nx run edit-docs:edit-docs
```
### Building the Executable
@@ -155,14 +149,14 @@ Download the repository, install dependencies using `pnpm` and then build the de
git clone https://github.com/TriliumNext/Trilium.git
cd Trilium
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/Notes/blob/develop/docs/Developer%20Guide/Developer%20Guide/Building%20and%20deployment/Running%20a%20development%20build.md).
### Developer Documentation
Please view the [documentation guide](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md) for details. If you have more questions, feel free to reach out via the links described in the "Discuss with us" section above.
Please view the [documentation guide](./docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md) for details. If you have more questions, feel free to reach out via the links described in the "Discuss with us" section above.
## 👏 Shoutouts
@@ -174,7 +168,7 @@ Please view the [documentation guide](https://github.com/TriliumNext/Trilium/blo
## 🤝 Support
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)
- 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/Notes/graphs/contributors))) for a full list)
- 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).

View File

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

View File

@@ -1,4 +1,5 @@
# The development license key for premium CKEditor features.
# 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

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.99.0",
"version": "0.97.2",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -9,13 +9,8 @@
"email": "contact@eliandoran.me",
"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": {
"@eslint/js": "9.36.0",
"@eslint/js": "9.33.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -24,7 +19,7 @@
"@fullcalendar/multimonth": "6.1.19",
"@fullcalendar/timegrid": "6.1.19",
"@maplibre/maplibre-gl-leaflet": "0.1.3",
"@mermaid-js/layout-elk": "0.2.0",
"@mermaid-js/layout-elk": "0.1.8",
"@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8",
"@triliumnext/ckeditor5": "workspace:*",
@@ -33,15 +28,15 @@
"@triliumnext/highlightjs": "workspace:*",
"@triliumnext/share-theme": "workspace:*",
"autocomplete.js": "0.38.1",
"bootstrap": "5.3.8",
"bootstrap": "5.3.7",
"boxicons": "2.1.4",
"dayjs": "1.11.18",
"dayjs": "1.11.13",
"dayjs-plugin-utc": "0.1.2",
"debounce": "2.2.0",
"draggabilly": "3.0.0",
"force-graph": "1.51.0",
"globals": "16.4.0",
"i18next": "25.5.2",
"force-graph": "1.50.1",
"globals": "16.3.0",
"i18next": "25.3.4",
"i18next-http-backend": "3.0.2",
"jquery": "3.7.1",
"jquery.fancytree": "2.38.5",
@@ -51,13 +46,12 @@
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.3.0",
"mermaid": "11.12.0",
"mind-elixir": "5.2.0",
"marked": "16.1.2",
"mermaid": "11.9.0",
"mind-elixir": "5.0.5",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.2",
"react-i18next": "15.7.3",
"preact": "10.27.0",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
"tabulator-tables": "6.3.1",
@@ -67,14 +61,27 @@
"@ckeditor/ckeditor5-inspector": "5.0.0",
"@preact/preset-vite": "2.10.2",
"@types/bootstrap": "5.2.10",
"@types/jquery": "3.5.33",
"@types/jquery": "3.5.32",
"@types/leaflet": "1.9.20",
"@types/leaflet-gpx": "1.3.8",
"@types/leaflet-gpx": "1.3.7",
"@types/mark.js": "8.11.12",
"@types/tabulator-tables": "6.2.11",
"@types/tabulator-tables": "6.2.10",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "18.0.1",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.2"
"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",
"scope": "/",
"start_url": "/",
"display_override": [
"window-controls-overlay"
],
"icons": [
{
"src": "icon.png",

View File

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

View File

@@ -1,8 +1,6 @@
import utils from "../services/utils.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.
*
@@ -21,7 +19,6 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
initialized: Promise<void> | null;
parent?: TypedComponent<any>;
_position!: number;
private listeners: Record<string, EventHandler[]> | null = {};
constructor() {
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 {
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) {
const ret = child.handleEvent(name, data) as Promise<void>;
@@ -131,35 +120,6 @@ export class TypedComponent<ChildT extends TypedComponent<ChildT>> {
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> {}

View File

@@ -10,7 +10,22 @@ import bundleService from "../services/bundle.js";
import froca from "../services/froca.js";
import linkService from "../services/link.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 {
constructor() {
@@ -19,7 +34,7 @@ export default class Entrypoints extends Component {
openDevToolsCommand() {
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()) {
// standard JS version does not work completely correctly in electron
const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents();
const activeIndex = webContents.navigationHistory.getActiveIndex();
const activeIndex = parseInt(webContents.navigationHistory.getActiveIndex());
webContents.goToIndex(activeIndex - 1);
} else {
@@ -121,7 +136,7 @@ export default class Entrypoints extends Component {
if (utils.isElectron()) {
// standard JS version does not work completely correctly in electron
const webContents = utils.dynamicRequire("@electron/remote").getCurrentWebContents();
const activeIndex = webContents.navigationHistory.getActiveIndex();
const activeIndex = parseInt(webContents.navigationHistory.getActiveIndex());
webContents.goToIndex(activeIndex + 1);
} else {

View File

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

View File

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

View File

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

View File

@@ -8,9 +8,10 @@ import electronContextMenu from "./menus/electron_context_menu.js";
import glob from "./services/glob.js";
import { t } from "./services/i18n.js";
import options from "./services/options.js";
import server from "./services/server.js";
import type ElectronRemote from "@electron/remote";
import type Electron from "electron";
import "bootstrap/dist/css/bootstrap.min.css";
import "./stylesheets/bootstrap.scss";
import "boxicons/css/boxicons.min.css";
import "autocomplete.js/index_jquery.js";
@@ -45,10 +46,6 @@ if (utils.isElectron()) {
electronContextMenu.setupContextMenu();
}
if (utils.isPWA()) {
initPWATopbarColor();
}
function initOnElectron() {
const electron: typeof Electron = utils.dynamicRequire("electron");
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;
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.
*/
export default class FNote {
class FNote {
private froca: Froca;
noteId!: string;
@@ -256,20 +256,18 @@ export default class FNote {
return this.children;
}
async getSubtreeNoteIds(includeArchived = false) {
async getSubtreeNoteIds() {
let noteIds: (string | string[])[] = [];
for (const child of await this.getChildNotes()) {
if (child.isArchived && !includeArchived) continue;
noteIds.push(child.noteId);
noteIds.push(await child.getSubtreeNoteIds(includeArchived));
noteIds.push(await child.getSubtreeNoteIds());
}
return noteIds.flat();
}
async getSubtreeNotes() {
const noteIds = await this.getSubtreeNoteIds();
return (await this.froca.getNotes(noteIds));
return this.froca.getNotes(noteIds);
}
async getChildNotes() {
@@ -907,8 +905,8 @@ export default class FNote {
return this.getBlob();
}
getBlob() {
return this.froca.getBlob("notes", this.noteId);
async getBlob() {
return await this.froca.getBlob("notes", this.noteId);
}
toString() {
@@ -1022,14 +1020,6 @@ export default class FNote {
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.
*/
@@ -1037,3 +1027,5 @@ export default class FNote {
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 GlobalMenuWidget from "../widgets/buttons/global_menu.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 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 PromotedAttributesWidget from "../widgets/promoted_attributes.js";
import NoteIconWidget from "../widgets/note_icon.jsx";
import RibbonContainer from "../widgets/containers/ribbon_container.js";
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 RootContainer from "../widgets/containers/root_container.js";
import WatchedFileUpdateStatusWidget from "../widgets/watched_file_update_status.js";
import SpacerWidget from "../widgets/spacer.js";
import QuickSearchWidget from "../widgets/quick_search.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import LeftPaneToggleWidget from "../widgets/buttons/left_pane_toggle.js";
import CreatePaneButton from "../widgets/buttons/create_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 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 BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
import SharedInfoWidget from "../widgets/shared_info.js";
import FindWidget from "../widgets/find.js";
import TocWidget from "../widgets/toc.js";
import HighlightsListWidget from "../widgets/highlights_list.js";
import PasswordNoteSetDialog from "../widgets/dialogs/password_not_set.js";
import 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 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 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 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 { 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 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 {
@@ -76,9 +107,9 @@ export default class DesktopLayout {
new FlexContainer("row")
.class("tab-row-container")
.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"))
.optChild(customTitleBarButtons, <TitleBarButtons />)
.optChild(customTitleBarButtons, new TitleBarButtonsWidget())
.css("height", "40px")
.css("background-color", "var(--launcher-pane-background-color)")
.setParent(appContext)
@@ -99,7 +130,7 @@ export default class DesktopLayout {
new FlexContainer("column")
.id("rest-pane")
.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(
new FlexContainer("row")
.filling()
@@ -120,30 +151,69 @@ export default class DesktopLayout {
.css("min-height", "50px")
.css("align-items", "center")
.cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />)
.child(new NoteIconWidget())
.child(new NoteTitleWidget())
.child(new SpacerWidget(0, 1))
.child(<MovePaneButton direction="left" />)
.child(<MovePaneButton direction="right" />)
.child(<ClosePaneButton />)
.child(<CreatePaneButton />)
.child(new MovePaneButton(true))
.child(new MovePaneButton(false))
.child(new ClosePaneButton())
.child(new CreatePaneButton())
)
.child(<Ribbon />)
.child(<SharedInfo />)
.child(
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(<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(
new ScrollingContainer()
.filling()
.child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />)
.child(new SqlTableSchemasWidget())
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<SearchResult />)
.child(<SqlResults />)
.child(<ScrollPadding />)
.child(new NoteListWidget(false))
.child(new SearchResultWidget())
.child(new SqlResultWidget())
.child(new ScrollPaddingWidget())
)
.child(<ApiLog />)
.child(new ApiLogWidget())
.child(new FindWidget())
.child(
...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.
.child(<PasswordNoteSetDialog />)
.child(<UploadAttachmentsDialog />);
.child(new PasswordNoteSetDialog())
.child(new UploadAttachmentsDialog());
applyModals(rootContainer);
return rootContainer;
@@ -176,18 +246,14 @@ export default class DesktopLayout {
let launcherPane;
if (isHorizontal) {
launcherPane = new FlexContainer("row")
.css("height", "53px")
.class("horizontal")
.child(new LauncherContainer(true))
.child(<GlobalMenu isHorizontalLayout={true} />);
launcherPane = new FlexContainer("row").css("height", "53px").class("horizontal").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true));
} else {
launcherPane = new FlexContainer("column")
.css("width", "53px")
.class("vertical")
.child(<GlobalMenu isHorizontalLayout={false} />)
.child(new GlobalMenuWidget(false))
.child(new LauncherContainer(false))
.child(<LeftPaneToggle isHorizontalLayout={false} />);
.child(new LeftPaneToggleWidget(false));
}
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 PopupEditorDialog from "../widgets/dialogs/popup_editor.js";
import FlexContainer from "../widgets/containers/flex_container.js";
import NoteIconWidget from "../widgets/note_icon";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
import NoteIconWidget from "../widgets/note_icon.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 CallToActionDialog from "../widgets/dialogs/call_to_action.jsx";
import NoteTitleWidget from "../widgets/note_title.jsx";
import { PopupEditorFormattingToolbar } from "../widgets/ribbon/FormattingToolbar.js";
import NoteList from "../widgets/collections/NoteList.jsx";
import NoteListWidget from "../widgets/note_list.js";
import { CallToActionDialog } from "../widgets/dialogs/call_to_action.jsx";
export function applyModals(rootContainer: RootContainer) {
rootContainer
.child(<BulkActionsDialog />)
.child(<AboutDialog />)
.child(<HelpDialog />)
.child(<RecentChangesDialog />)
.child(<BranchPrefixDialog />)
.child(<SortChildNotesDialog />)
.child(<IncludeNoteDialog />)
.child(<NoteTypeChooserDialog />)
.child(<JumpToNoteDialog />)
.child(<AddLinkDialog />)
.child(<CloneToDialog />)
.child(<MoveToDialog />)
.child(<ImportDialog />)
.child(<ExportDialog />)
.child(<MarkdownImportDialog />)
.child(<ProtectedSessionPasswordDialog />)
.child(<RevisionsDialog />)
.child(<DeleteNotesDialog />)
.child(<InfoDialog />)
.child(<ConfirmDialog />)
.child(<PromptDialog />)
.child(<IncorrectCpuArchDialog />)
.child(new BulkActionsDialog())
.child(new AboutDialog())
.child(new HelpDialog())
.child(new RecentChangesDialog())
.child(new BranchPrefixDialog())
.child(new SortChildNotesDialog())
.child(new IncludeNoteDialog())
.child(new NoteTypeChooserDialog())
.child(new JumpToNoteDialog())
.child(new AddLinkDialog())
.child(new CloneToDialog())
.child(new MoveToDialog())
.child(new ImportDialog())
.child(new ExportDialog())
.child(new MarkdownImportDialog())
.child(new ProtectedSessionPasswordDialog())
.child(new RevisionsDialog())
.child(new DeleteNotesDialog())
.child(new InfoDialog())
.child(new ConfirmDialog())
.child(new PromptDialog())
.child(new IncorrectCpuArchDialog())
.child(new PopupEditorDialog()
.child(new FlexContainer("row")
.class("title-row")
.css("align-items", "center")
.cssBlock(".title-row > * { margin: 5px; }")
.child(<NoteIconWidget />)
.child(<NoteTitleWidget />))
.child(<PopupEditorFormattingToolbar />)
.child(new NoteIconWidget())
.child(new NoteTitleWidget()))
.child(new ClassicEditorToolbar())
.child(new PromotedAttributesWidget())
.child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />))
.child(<CallToActionDialog />);
.child(new NoteListWidget(true)))
.child(new CallToActionDialog());
}

View File

@@ -3,27 +3,30 @@ import NoteTitleWidget from "../widgets/note_title.js";
import NoteDetailWidget from "../widgets/note_detail.js";
import QuickSearchWidget from "../widgets/quick_search.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 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 LauncherContainer from "../widgets/containers/launcher_container.js";
import RootContainer from "../widgets/containers/root_container.js";
import SharedInfoWidget from "../widgets/shared_info.js";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
import type AppContext from "../components/app_context.js";
import TabRowWidget from "../widgets/tab_row.js";
import MobileEditorToolbar from "../widgets/type_widgets/ckeditor/mobile_editor_toolbar.js";
import 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 FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import { useNoteContext } from "../widgets/react/hooks.jsx";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
import CloseZenModeButton from "../widgets/close_zen_button.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
import NoteList from "../widgets/collections/NoteList.jsx";
import CloseZenButton from "../widgets/close_zen_button.js";
const MOBILE_CSS = `
<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 ScreenContainer("detail", "row")
new ScreenContainer("detail", "column")
.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")
.child(
new NoteWrapperWidget()
.child(
new FlexContainer("row")
.contentSized()
.css("font-size", "larger")
.css("align-items", "center")
.child(<ToggleSidebarButton />)
.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 />)
new FlexContainer("row")
.contentSized()
.css("font-size", "larger")
.css("align-items", "center")
.child(new ToggleSidebarButtonWidget().contentSized())
.child(new NoteTitleWidget().contentSized().css("position", "relative").css("padding-left", "0.5em"))
.child(new MobileDetailMenuWidget(true).contentSized())
)
.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(
@@ -166,25 +174,10 @@ export default class MobileLayout {
.contentSized()
.id("mobile-bottom-bar")
.child(new TabRowWidget().css("height", "40px"))
.child(new FlexContainer("row")
.class("horizontal")
.css("height", "53px")
.child(new LauncherContainer(true))
.child(<GlobalMenuWidget isHorizontalLayout />)
.id("launcher-pane"))
.child(new FlexContainer("row").class("horizontal").css("height", "53px").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true)).id("launcher-pane"))
)
.child(<CloseZenModeButton />);
.child(new CloseZenButton());
applyModals(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
// Required for correct loading of scripts in Electron

View File

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

View File

@@ -37,7 +37,7 @@ function setupContextMenu() {
handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
});
items.push({ kind: "separator" });
items.push({ title: `----` });
}
if (params.isEditable) {
@@ -112,7 +112,7 @@ function setupContextMenu() {
// Replace the placeholder with the real search keyword.
let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText));
items.push({ kind: "separator" });
items.push({ title: "----" });
items.push({
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-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 ? { 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,
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.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 }
];

View File

@@ -13,8 +13,6 @@ import type NoteTreeWidget from "../widgets/note_tree.js";
import type FAttachment from "../entities/fattachment.js";
import type { SelectMenuItemEventListener } from "../components/events.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.
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
// it's clear what the user meant to do.
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 notSearch = note?.type !== "search";
@@ -76,29 +69,27 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNotSearch;
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-popup"), command: "openNoteInPopup", uiIcon: "bx bx-edit", enabled: noSelectedNotes },
isHoisted
? null
: {
title: `${t("tree-context-menu.hoist-note")}`,
title: `${t("tree-context-menu.hoist-note")} <kbd data-command="toggleNoteHoisting"></kbd>`,
command: "toggleNoteHoisting",
keyboardShortcut: "toggleNoteHoisting",
uiIcon: "bx bxs-chevrons-up",
enabled: noSelectedNotes && notSearch
},
!isHoisted || !isNotRoot
? 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",
keyboardShortcut: "createNoteAfter",
uiIcon: "bx bx-plus",
items: insertNoteAfterEnabled ? await noteTypesService.getNoteTypeItems("insertNoteAfter") : null,
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",
keyboardShortcut: "createNoteInto",
uiIcon: "bx bx-plus",
items: notSearch ? await noteTypesService.getNoteTypeItems("insertChildNote") : null,
enabled: notSearch && noSelectedNotes && notOptionsOrHelp,
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.unprotect-subtree"), command: "unprotectSubtree", uiIcon: "bx bx-shield", enabled: noSelectedNotes },
{ kind: "separator" },
{ title: "----" },
{
title: t("tree-context-menu.advanced"),
@@ -130,52 +120,48 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
items: [
{ 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",
keyboardShortcut: "editBranchPrefix",
uiIcon: "bx bx-rename",
enabled: isNotRoot && parentNotSearch && noSelectedNotes && 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.collapse-subtree"), command: "collapseSubtree", keyboardShortcut: "collapseSubtree", uiIcon: "bx bx-collapse", 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")} <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",
keyboardShortcut: "sortChildNotes",
uiIcon: "bx bx-sort-down",
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.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",
keyboardShortcut: "cutNotesToClipboard",
uiIcon: "bx bx-cut",
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",
keyboardShortcut: "pasteNotesFromClipboard",
uiIcon: "bx bx-paste",
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",
keyboardShortcut: "moveNotesTo",
uiIcon: "bx bx-transfer",
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",
keyboardShortcut: "duplicateSubtree",
uiIcon: "bx bx-outline",
enabled: parentNotSearch && isNotRoot && !isHoisted && notOptionsOrHelp
},
{
title: !isArchived ? t("tree-context-menu.archive") : t("tree-context-menu.unarchive"),
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"),
title: `${t("tree-context-menu.delete")} <kbd data-command="deleteNotes"></kbd>`,
command: "deleteNotes",
keyboardShortcut: "deleteNotes",
uiIcon: "bx bx-trash destructive-action-icon",
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.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",
keyboardShortcut: "searchInSubtree",
uiIcon: "bx bx-search",
enabled: notSearch && noSelectedNotes
}

View File

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

View File

@@ -2,7 +2,6 @@ import server from "./server.js";
import froca from "./froca.js";
import type FNote from "../entities/fnote.js";
import type { AttributeRow } from "./load_results.js";
import { AttributeType } from "@triliumnext/commons";
async function addLabel(noteId: string, name: string, value: string = "", isInheritable = false) {
await server.put(`notes/${noteId}/attribute`, {
@@ -26,14 +25,6 @@ async function removeAttributeById(noteId: string, attributeId: string) {
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.
* 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.
*/
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.
await server.put(`notes/${note.noteId}/set-attribute`, { type, name, value });
} else {

View File

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

View File

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

View File

@@ -256,19 +256,8 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
</button>
`);
$downloadButton.on("click", (e) => {
e.stopPropagation();
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");
});
$downloadButton.on("click", () => openService.downloadFileNote(entity.noteId));
$openButton.on("click", () => openService.openNoteExternally(entity.noteId, entity.mime));
// open doesn't work for protected notes since it works through a browser which isn't in protected session
$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 }));
}
export async function prompt(props: PromptDialogOptions) {
async function prompt(props: PromptDialogOptions) {
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.
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`;
}

View File

@@ -1,8 +1,16 @@
import ws from "./ws.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: {},
attachments: {}
};
@@ -31,7 +39,7 @@ function ignoreModification(entityType: string, entityId: string) {
delete fileModificationStatus[entityType][entityId];
}
ws.subscribeToMessages(async message => {
ws.subscribeToMessages(async (message: Message) => {
if (message.type !== "openedFileUpdated") {
return;
}

View File

@@ -8,7 +8,6 @@ import FAttribute, { type FAttributeRow } from "../entities/fattribute.js";
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
import type { default as FNote, FNoteRow } from "../entities/fnote.js";
import type { EntityChange } from "../server_types.js";
import type { OptionNames } from "@triliumnext/commons";
async function processEntityChanges(entityChanges: EntityChange[]) {
const loadResults = new LoadResults(entityChanges);
@@ -31,14 +30,13 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
continue; // only noise
}
options.set(attributeEntity.name as OptionNames, attributeEntity.value);
loadResults.addOption(attributeEntity.name as OptionNames);
options.set(attributeEntity.name, attributeEntity.value);
loadResults.addOption(attributeEntity.name);
} else if (ec.entityName === "attachments") {
processAttachment(loadResults, ec);
} else if (ec.entityName === "blobs") {
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
// NOOP - these entities are handled at the backend level and don't require frontend processing
} else if (ec.entityName === "etapi_tokens") {
loadResults.hasEtapiTokenChanges = true;
} else {
throw new Error(`Unknown entityName '${ec.entityName}'`);
}
@@ -79,7 +77,9 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
noteAttributeCache.invalidate();
}
const appContext = (await import("../components/app_context.js")).default;
// TODO: Remove after porting the file
// @ts-ignore
const appContext = (await import("../components/app_context.js")).default as any;
await appContext.triggerEvent("entitiesReloaded", { loadResults });
}
}

View File

@@ -3,7 +3,6 @@ import i18next from "i18next";
import i18nextHttpBackend from "i18next-http-backend";
import server from "./server.js";
import type { Locale } from "@triliumnext/commons";
import { initReactI18next } from "react-i18next";
let locales: Locale[] | null;
@@ -17,7 +16,6 @@ export async function initLocale() {
locales = await server.get<Locale[]>("options/locales");
i18next.use(initReactI18next);
await i18next.use(i18nextHttpBackend).init({
lng: locale,
fallbackLng: "en",

View File

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

View File

@@ -4,7 +4,6 @@ import ws from "./ws.js";
import utils from "./utils.js";
import appContext from "../components/app_context.js";
import { t } from "./i18n.js";
import { WebSocketMessage } from "@triliumnext/commons";
type BooleanLike = boolean | "true" | "false";
@@ -67,7 +66,7 @@ function makeToast(id: string, message: string): ToastOptions {
}
ws.subscribeToMessages(async (message) => {
if (!("taskType" in message) || message.taskType !== "importNotes") {
if (message.taskType !== "importNotes") {
return;
}
@@ -88,8 +87,8 @@ ws.subscribeToMessages(async (message) => {
}
});
ws.subscribeToMessages(async (message: WebSocketMessage) => {
if (!("taskType" in message) || message.taskType !== "importAttachments") {
ws.subscribeToMessages(async (message) => {
if (message.taskType !== "importAttachments") {
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;
}
export function getActionSync(actionName: string) {
return keyboardActionRepo[actionName];
}
function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
//@ts-ignore
//TODO: each() does not support async callbacks.

View File

@@ -1,4 +1,4 @@
import type { AttachmentRow, EtapiTokenRow, OptionNames } from "@triliumnext/commons";
import type { AttachmentRow } from "@triliumnext/commons";
import type { AttributeType } from "../entities/fattribute.js";
import type { EntityChange } from "../server_types.js";
@@ -53,7 +53,6 @@ type EntityRowMappings = {
options: OptionRow;
revisions: RevisionRow;
note_reordering: NoteReorderingRow;
etapi_tokens: EtapiTokenRow;
};
export type EntityRowNames = keyof EntityRowMappings;
@@ -67,9 +66,8 @@ export default class LoadResults {
private revisionRows: RevisionRow[];
private noteReorderings: string[];
private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
private optionNames: OptionNames[];
private optionNames: string[];
private attachmentRows: AttachmentRow[];
public hasEtapiTokenChanges: boolean = false;
constructor(entityChanges: EntityChange[]) {
const entities: Record<string, Record<string, any>> = {};
@@ -180,11 +178,11 @@ export default class LoadResults {
return this.contentNoteIdToComponentId.find((l) => l.noteId === noteId && l.componentId !== componentId);
}
addOption(name: OptionNames) {
addOption(name: string) {
this.optionNames.push(name);
}
isOptionReloaded(name: OptionNames) {
isOptionReloaded(name: string) {
return this.optionNames.includes(name);
}
@@ -217,8 +215,7 @@ export default class LoadResults {
this.revisionRows.length === 0 &&
this.contentNoteIdToComponentId.length === 0 &&
this.optionNames.length === 0 &&
this.attachmentRows.length === 0 &&
!this.hasEtapiTokenChanges
this.attachmentRows.length === 0
);
}

View File

@@ -36,8 +36,6 @@ export interface Suggestion {
commandId?: string;
commandDescription?: string;
commandShortcut?: string;
attributeSnippet?: string;
highlightedAttributeSnippet?: string;
}
export interface Options {
@@ -325,33 +323,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
html += '</div>';
return html;
}
// Add special class for search-notes action
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;
return `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`;
}
},
// 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

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

View File

@@ -1,8 +1,7 @@
import { OptionNames } from "@triliumnext/commons";
import server from "./server.js";
import { isShare } from "./utils.js";
export type OptionValue = number | string;
type OptionValue = number | string;
class Options {
initializedPromise: Promise<void>;
@@ -20,7 +19,7 @@ class Options {
this.arr = arr;
}
get(key: OptionNames) {
get(key: string) {
return this.arr?.[key] as string;
}
@@ -40,7 +39,7 @@ class Options {
}
}
getInt(key: OptionNames) {
getInt(key: string) {
const value = this.arr?.[key];
if (typeof value === "number") {
return value;
@@ -52,7 +51,7 @@ class Options {
return null;
}
getFloat(key: OptionNames) {
getFloat(key: string) {
const value = this.arr?.[key];
if (typeof value !== "string") {
return null;
@@ -60,15 +59,15 @@ class Options {
return parseFloat(value);
}
is(key: OptionNames) {
is(key: string) {
return this.arr[key] === "true";
}
set(key: OptionNames, value: OptionValue) {
set(key: string, value: OptionValue) {
this.arr[key] = value;
}
async save(key: OptionNames, value: OptionValue) {
async save(key: string, value: OptionValue) {
this.set(key, value);
const payload: Record<string, OptionValue> = {};
@@ -77,15 +76,7 @@ class Options {
await server.put(`options`, payload);
}
/**
* Saves multiple options at once, by supplying a record where the keys are the option names and the values represent the stringified value to set.
* @param newValues the record of keys and values.
*/
async saveMany<T extends OptionNames>(newValues: Record<T, OptionValue>) {
await server.put<void>("options", newValues);
}
async toggle(key: OptionNames) {
async toggle(key: string) {
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) => {
if (!("taskType" in message) || message.taskType !== "protectNotes") {
if (message.taskType !== "protectNotes") {
return;
}
const isProtecting = message.data?.protect;
const isProtecting = message.data.protect;
const title = isProtecting ? t("protected_session.protecting-title") : t("protected_session.unprotecting-title");
if (message.type === "taskError") {

View File

@@ -10,10 +10,6 @@ let leftInstance: ReturnType<typeof Split> | null;
let rightPaneWidth: number;
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) {
if (leftInstance) {
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 {
setupLeftPaneResizer,
setupRightPaneResizer,
setupNoteSplitResizer,
delNoteSplitResizer,
moveNoteSplitResizer
setupRightPaneResizer
};

View File

@@ -218,7 +218,7 @@ function ajax(url: string, method: string, data: unknown, headers: Headers, sile
if (utils.isElectron()) {
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) {
handleSuccessfulResponse(arg);
} else {

View File

@@ -1,5 +1,5 @@
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
vi.mock("./utils.js", () => ({
@@ -320,36 +320,4 @@ describe("shortcuts", () => {
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

@@ -14,50 +14,6 @@ interface ShortcutBinding {
// Store all active shortcut bindings for management
const activeBindings: Map<string, ShortcutBinding[]> = new Map();
// Handle special key mappings and aliases
const keyMap: { [key: string]: string[] } = {
'return': ['Enter'],
'enter': ['Enter'], // alias for return
'del': ['Delete'],
'delete': ['Delete'], // alias for del
'esc': ['Escape'],
'escape': ['Escape'], // alias for esc
'space': [' ', 'Space'],
'tab': ['Tab'],
'backspace': ['Backspace'],
'home': ['Home'],
'end': ['End'],
'pageup': ['PageUp'],
'pagedown': ['PageDown'],
'up': ['ArrowUp'],
'down': ['ArrowDown'],
'left': ['ArrowLeft'],
'right': ['ArrowRight']
};
// Function keys
for (let i = 1; i <= 19; i++) {
keyMap[`f${i}`] = [`F${i}`];
}
/**
* 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) {
bindGlobalShortcut("", null, namespace);
}
@@ -86,13 +42,6 @@ function bindElShortcut($el: JQuery<ElementType | Element>, keyboardShortcut: st
}
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)) {
e.preventDefault();
e.stopPropagation();
@@ -175,6 +124,32 @@ export function keyMatches(e: KeyboardEvent, key: string): boolean {
return false;
}
// Handle special key mappings and aliases
const keyMap: { [key: string]: string[] } = {
'return': ['Enter'],
'enter': ['Enter'], // alias for return
'del': ['Delete'],
'delete': ['Delete'], // alias for del
'esc': ['Escape'],
'escape': ['Escape'], // alias for esc
'space': [' ', 'Space'],
'tab': ['Tab'],
'backspace': ['Backspace'],
'home': ['Home'],
'end': ['End'],
'pageup': ['PageUp'],
'pagedown': ['PageDown'],
'up': ['ArrowUp'],
'down': ['ArrowDown'],
'left': ['ArrowLeft'],
'right': ['ArrowRight']
};
// Function keys
for (let i = 1; i <= 19; i++) {
keyMap[`f${i}`] = [`F${i}`];
}
const mappedKeys = keyMap[key.toLowerCase()];
if (mappedKeys) {
return mappedKeys.includes(e.key) || mappedKeys.includes(e.code);
@@ -188,7 +163,7 @@ export function keyMatches(e: KeyboardEvent, key: string): boolean {
// For letter keys, use the physical key code for consistency
if (key.length === 1 && key >= 'a' && key <= 'z') {
return e.key.toLowerCase() === key.toLowerCase();
return e.code === `Key${key.toUpperCase()}`;
}
// For regular keys, check both key and code as fallback

View File

@@ -1,12 +1,11 @@
import dayjs from "dayjs";
import type { ViewScope } from "./link.js";
import FNote from "../entities/fnote";
const SVG_MIME = "image/svg+xml";
export const isShare = !window.glob;
export function reloadFrontendApp(reason?: string) {
function reloadFrontendApp(reason?: string) {
if (reason) {
logInfo(`Frontend app reload: ${reason}`);
}
@@ -14,7 +13,7 @@ export function reloadFrontendApp(reason?: string) {
window.location.reload();
}
export function restartDesktopApp() {
function restartDesktopApp() {
if (!isElectron()) {
reloadFrontendApp();
return;
@@ -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) {
return `${num <= 9 ? "0" : ""}${num}`;
}
@@ -105,7 +125,7 @@ function formatDateISO(date: Date) {
return `${date.getFullYear()}-${padNum(date.getMonth() + 1)}-${padNum(date.getDate())}`;
}
export function formatDateTime(date: Date, userSuppliedFormat?: string): string {
function formatDateTime(date: Date, userSuppliedFormat?: string): string {
if (userSuppliedFormat?.trim()) {
return dayjs(date).format(userSuppliedFormat);
} else {
@@ -124,23 +144,11 @@ function now() {
/**
* Returns `true` if the client is currently running under Electron, or `false` if running in a web browser.
*/
export function isElectron() {
function isElectron() {
return !!(window && window.process && window.process.type);
}
/**
* 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() {
function isMac() {
return navigator.platform.indexOf("Mac") > -1;
}
@@ -177,11 +185,7 @@ export function escapeQuotes(value: string) {
return value.replaceAll('"', "&quot;");
}
export function formatSize(size: number | null | undefined) {
if (size === null || size === undefined) {
return "";
}
function formatSize(size: number) {
size = Math.max(Math.round(size / 1024), 1);
if (size < 1024) {
@@ -214,7 +218,7 @@ function randomString(len: number) {
return text;
}
export function isMobile() {
function isMobile() {
return (
window.glob?.device === "mobile" ||
// window.glob.device is not available in setup
@@ -288,55 +292,7 @@ function isHtmlEmpty(html: string) {
);
}
function formatHtml(html: string) {
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() {
async function clearBrowserCache() {
if (isElectron()) {
const win = dynamicRequire("@electron/remote").getCurrentWindow();
await win.webContents.session.clearCache();
@@ -350,13 +306,7 @@ function copySelectionToClipboard() {
}
}
type dynamicRequireMappings = {
"@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]>{
function dynamicRequire(moduleName: string) {
if (typeof __non_webpack_require__ !== "undefined") {
return __non_webpack_require__(moduleName);
} else {
@@ -424,42 +374,33 @@ async function openInAppHelp($button: JQuery<HTMLElement>) {
const inAppHelpPage = $button.attr("data-in-app-help");
if (inAppHelpPage) {
openInAppHelpFromUrl(inAppHelpPage);
}
}
/**
* Opens the in-app help at the given page in a split note. If there already is a split note open with a help page, it will be replaced by this one.
*
* @param inAppHelpPage the ID of the help note (excluding the `_help_` prefix).
* @returns a promise that resolves once the help has been opened.
*/
export async function openInAppHelpFromUrl(inAppHelpPage: string) {
// Dynamic import to avoid import issues in tests.
const appContext = (await import("../components/app_context.js")).default;
const activeContext = appContext.tabManager.getActiveContext();
if (!activeContext) {
// Dynamic import to avoid import issues in tests.
const appContext = (await import("../components/app_context.js")).default;
const activeContext = appContext.tabManager.getActiveContext();
if (!activeContext) {
return;
}
const subContexts = activeContext.getSubContexts();
const targetNote = `_help_${inAppHelpPage}`;
const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help");
const viewScope: ViewScope = {
viewMode: "contextual-help",
};
if (!helpSubcontext) {
// The help is not already open, open a new split with it.
const { ntxId } = subContexts[subContexts.length - 1];
appContext.triggerCommand("openNewNoteSplit", {
ntxId,
notePath: targetNote,
hoistedNoteId: "_help",
viewScope
})
} else {
// There is already a help window open, make sure it opens on the right note.
helpSubcontext.setNote(targetNote, { viewScope });
}
return;
}
const subContexts = activeContext.getSubContexts();
const targetNote = `_help_${inAppHelpPage}`;
const helpSubcontext = subContexts.find((s) => s.viewScope?.viewMode === "contextual-help");
const viewScope: ViewScope = {
viewMode: "contextual-help",
};
if (!helpSubcontext) {
// The help is not already open, open a new split with it.
const { ntxId } = subContexts[subContexts.length - 1];
appContext.triggerCommand("openNewNoteSplit", {
ntxId,
notePath: targetNote,
hoistedNoteId: "_help",
viewScope
})
} else {
// There is already a help window open, make sure it opens on the right note.
helpSubcontext.setNote(targetNote, { viewScope });
}
}
function initHelpButtons($el: JQuery<HTMLElement> | JQuery<Window>) {
@@ -487,7 +428,7 @@ function sleep(time_ms: number) {
});
}
export function escapeRegExp(str: string) {
function escapeRegExp(str: string) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
@@ -620,7 +561,8 @@ function copyHtmlToClipboard(content: string) {
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()}`;
}
@@ -789,91 +731,16 @@ function isUpdateAvailable(latestVersion: string | null | undefined, currentVers
return compareVersions(latestVersion, currentVersion) > 0;
}
export function isLaunchBarConfig(noteId: string) {
function isLaunchBarConfig(noteId: string) {
return ["_lbRoot", "_lbAvailableLaunchers", "_lbVisibleLaunchers", "_lbMobileRoot", "_lbMobileAvailableLaunchers", "_lbMobileVisibleLaunchers"].includes(noteId);
}
/**
* Adds a class to the <body> of the page, where the class name is formed via a prefix and a value.
* Useful for configurable options such as `heading-style-markdown`, where `heading-style` is the prefix and `markdown` is the dynamic value.
* There is no separator between the prefix and the value, if needed it has to be supplied manually to the prefix.
*
* @param prefix the prefix.
* @param value the value to be appended to the prefix.
*/
export function toggleBodyClass(prefix: string, value: string) {
const $body = $("body");
for (const clazz of Array.from($body[0].classList)) {
// create copy to safely iterate over while removing classes
if (clazz.startsWith(prefix)) {
$body.removeClass(clazz);
}
}
$body.addClass(prefix + value);
}
/**
* Basic comparison for equality between the two arrays. The values are strictly checked via `===`.
*
* @param a the first array to compare.
* @param b the second array to compare.
* @returns `true` if both arrays are equals, `false` otherwise.
*/
export function arrayEqual<T>(a: T[], b: T[]) {
if (a === b) {
return true;
}
if (a.length !== b.length) {
return false;
}
for (let i=0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
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 {
reloadFrontendApp,
restartDesktopApp,
reloadTray,
parseDate,
getMonthsInDateRange,
formatDateISO,
formatDateTime,
formatTimeInterval,
@@ -881,7 +748,6 @@ export default {
localNowDateTime,
now,
isElectron,
isPWA,
isMac,
isCtrlKey,
assertArguments,
@@ -894,7 +760,6 @@ export default {
getNoteTypeClass,
getMimeTypeClass,
isHtmlEmpty,
formatHtml,
clearBrowserCache,
copySelectionToClipboard,
dynamicRequire,

View File

@@ -6,10 +6,9 @@ import frocaUpdater from "./froca_updater.js";
import appContext from "../components/app_context.js";
import { t } from "./i18n.js";
import type { EntityChange } from "../server_types.js";
import { WebSocketMessage } from "@triliumnext/commons";
type MessageHandler = (message: WebSocketMessage) => void;
let messageHandlers: MessageHandler[] = [];
type MessageHandler = (message: any) => void;
const messageHandlers: MessageHandler[] = [];
let ws: WebSocket;
let lastAcceptedEntityChangeId = window.glob.maxEntityChangeIdAtLoad;
@@ -48,14 +47,10 @@ function logInfo(message: string) {
window.logError = logError;
window.logInfo = logInfo;
export function subscribeToMessages(messageHandler: MessageHandler) {
function subscribeToMessages(messageHandler: MessageHandler) {
messageHandlers.push(messageHandler);
}
export function unsubscribeToMessage(messageHandler: MessageHandler) {
messageHandlers = messageHandlers.filter(handler => handler !== messageHandler);
}
// used to serialize frontend update operations
let consumeQueuePromise: Promise<void> | null = null;

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
import "normalize.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/scripts/index.js";

View File

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

View File

@@ -28,28 +28,6 @@
--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 {
--bs-table-bg: transparent !important;
}
@@ -161,27 +139,12 @@ textarea,
color: var(--muted-text-color);
}
.form-group.disabled,
.form-checkbox.disabled {
opacity: 0.5;
pointer-events: none;
}
.form-group {
margin-bottom: 15px;
}
/* Add a gap between consecutive radios / check boxes */
label.tn-radio + label.tn-radio,
label.tn-checkbox + label.tn-checkbox {
margin-left: 12px;
}
label.tn-radio input[type="radio"],
label.tn-checkbox input[type="checkbox"] {
margin-right: .5em;
}
#left-pane input,
#left-pane select,
#left-pane textarea {
@@ -252,6 +215,10 @@ button.close:hover {
color: var(--main-text-color) !important;
}
.note-title[readonly] {
background: inherit;
}
.tdialog {
display: none;
}
@@ -290,11 +257,6 @@ button.close:hover {
pointer-events: none;
}
.icon-action.btn {
padding: 0 8px;
min-width: unset !important;
}
.ui-widget-content a:not(.ui-tabs-anchor) {
color: #337ab7 !important;
}
@@ -363,24 +325,28 @@ button kbd {
.tabulator-popup-container {
color: var(--menu-text-color) !important;
font-size: inherit;
background: var(--menu-background-color) !important;
background-color: var(--menu-background-color) !important;
user-select: none;
-webkit-user-select: none;
--bs-dropdown-zindex: 999;
--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 .tabulator-popup-container {
border: 1px solid var(--dropdown-border-color);
column-rule: 1px solid var(--dropdown-border-color);
box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
animation: dropdown-menu-opening 100ms ease-in;
}
@supports (animation-fill-mode: forwards) {
/* Delay the opening of submenus */
body.desktop:not(.motion-disabled) .dropdown-submenu .dropdown-menu {
body.desktop .dropdown-submenu .dropdown-menu {
opacity: 0;
animation-fill-mode: forwards;
animation-delay: var(--submenu-opening-delay);
@@ -415,7 +381,7 @@ body.desktop .tabulator-popup-container {
}
.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 {
color: var(--hover-item-text-color) !important;
background-color: var(--hover-item-background-color) !important;
@@ -423,9 +389,9 @@ body.desktop .tabulator-popup-container {
cursor: pointer;
}
.dropdown-container-item,
.dropdown-item.dropdown-container-item:hover,
.dropdown-container-item:active {
.dropdown-item-container,
.dropdown-item-container:hover,
.dropdown-item-container:active {
background: transparent;
cursor: default;
}
@@ -440,20 +406,14 @@ body #context-menu-container .dropdown-item > span {
align-items: center;
}
.dropdown-item span.keyboard-shortcut,
.dropdown-item *:not(.keyboard-shortcut) > kbd {
.dropdown-menu kbd {
flex-grow: 1;
text-align: right;
padding-inline-start: 12px;
}
.dropdown-menu kbd {
color: var(--muted-text-color);
border: none;
background-color: transparent;
box-shadow: none;
padding-bottom: 0;
padding: 0;
}
.dropdown-item,
@@ -462,12 +422,6 @@ body #context-menu-container .dropdown-item > span {
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 kbd {
color: #aaa !important;
@@ -475,9 +429,9 @@ body #context-menu-container .dropdown-item > span {
.dropdown-item.active,
.dropdown-item:focus {
color: var(--active-item-text-color);
background-color: var(--active-item-background-color);
border-color: var(--active-item-border-color);
color: var(--active-item-text-color) !important;
background-color: var(--active-item-background-color) !important;
border-color: var(--active-item-border-color) !important;
outline: none;
}
@@ -877,34 +831,10 @@ table.promoted-attributes-in-tooltip th {
.aa-dropdown-menu .aa-suggestion {
cursor: pointer;
padding: 6px 16px;
padding: 5px;
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 {
padding: 0;
margin: 0;
@@ -992,11 +922,6 @@ div[data-notify="container"] {
font-family: var(--monospace-font-family);
}
svg.ck-icon .note-icon {
color: var(--main-text-color);
font-size: 20px;
}
.ck-content {
--ck-content-font-family: var(--detail-font-family);
--ck-content-font-size: 1.1em;
@@ -1138,7 +1063,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.toast-body {
white-space: preserve-breaks;
overflow: hidden;
}
.ck-mentions .ck-button {
@@ -1247,10 +1171,6 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
cursor: row-resize;
}
.hidden-ext.note-split + .gutter {
display: none;
}
#context-menu-cover.show {
position: fixed;
top: 0;
@@ -1472,7 +1392,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
cursor: pointer;
border: none;
color: var(--launcher-pane-text-color);
background: transparent;
background-color: var(--launcher-pane-background-color);
flex-shrink: 0;
}
@@ -1780,6 +1700,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
}
.note-split {
flex-basis: 0; /* so that each split has same width */
margin-left: auto;
margin-right: auto;
}
@@ -1817,12 +1738,16 @@ button.close:hover {
margin-bottom: 10px;
}
.options-section input[type="number"] {
.options-number-input {
/* overriding settings from .form-control */
width: 10em !important;
flex-grow: 0 !important;
}
.options-mime-types {
column-width: 250px;
}
textarea {
cursor: auto;
}
@@ -1843,37 +1768,20 @@ textarea {
font-size: 1em;
}
.jump-to-note-dialog .modal-dialog {
max-width: 900px;
width: 90%;
}
.jump-to-note-dialog .modal-header {
align-items: center;
}
.jump-to-note-dialog .modal-body {
padding: 0;
min-height: 200px;
}
.jump-to-note-results .aa-dropdown-menu {
max-height: calc(80vh - 200px);
width: 100%;
max-width: none;
overflow-y: auto;
overflow-x: hidden;
text-overflow: ellipsis;
box-shadow: none;
}
.jump-to-note-results {
width: 100%;
max-height: 40vh;
}
.jump-to-note-results .aa-suggestions {
padding: 0;
width: 100%;
padding: 1rem;
}
/* Command palette styling */
@@ -1891,24 +1799,8 @@ textarea {
.jump-to-note-dialog .aa-cursor .command-suggestion,
.jump-to-note-dialog .aa-suggestion:hover .command-suggestion {
background-color: transparent;
}
.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;
border-left-color: var(--link-color);
background-color: var(--hover-background-color);
}
.jump-to-note-dialog .command-icon {
@@ -2363,27 +2255,16 @@ footer.webview-footer button {
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 */
.bx-tn-toc::before {
content: "\ec24";
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 {
--theme-style: dark;
--main-font-family: Montserrat, sans-serif;
--main-font-family: Montserrat;
--main-font-size: normal;
--tree-font-family: Montserrat, sans-serif;
--tree-font-family: Montserrat;
--tree-font-size: normal;
--detail-font-family: Montserrat, sans-serif;
--detail-font-family: Montserrat;
--detail-font-size: normal;
--monospace-font-family: JetBrainsLight, monospace;
--monospace-font-family: JetBrainsLight;
--monospace-font-size: normal;
--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 */
--theme-style: light;
--main-font-family: Montserrat, sans-serif;
--main-font-family: Montserrat;
--main-font-size: normal;
--tree-font-family: Montserrat, sans-serif;
--tree-font-family: Montserrat;
--tree-font-size: normal;
--detail-font-family: Montserrat, sans-serif;
--detail-font-family: Montserrat;
--detail-font-size: normal;
--monospace-font-family: JetBrainsLight, monospace;
--monospace-font-family: JetBrainsLight;
--monospace-font-size: normal;
--main-background-color: white;

View File

@@ -13,13 +13,12 @@
--theme-style: dark;
--native-titlebar-background: #00000000;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: #272727;
--main-text-color: #ccc;
--main-border-color: #454545;
--subtle-border-color: #313131;
--dropdown-border-color: #404040;
--dropdown-border-color: #292929;
--dropdown-shadow-opacity: 0.6;
--dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef;
@@ -90,7 +89,6 @@
--menu-text-color: #e3e3e3;
--menu-background-color: #222222d9;
--menu-background-color-no-backdrop: #1b1b1b;
--menu-item-icon-color: #8c8c8c;
--menu-item-disabled-opacity: 0.5;
--menu-item-keyboard-shortcut-color: #ffffff8f;
@@ -122,8 +120,6 @@
--quick-search-focus-border: #80808095;
--quick-search-focus-background: #ffffff1f;
--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-background-color: #1f1f1f;
@@ -148,17 +144,14 @@
--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-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-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-background: #ffffff1c;
--launcher-pane-horiz-button-hover-shadow: unset;
--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;
--sync-status-error-pulse-color: #f47871;
@@ -172,10 +165,9 @@
--tab-close-button-hover-background: #a45353;
--tab-close-button-hover-color: white;
--active-tab-background-color: #ffffff1c;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-icon-color: #a9a9a9;
--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-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, 0.4);

View File

@@ -13,7 +13,6 @@
--theme-style: light;
--native-titlebar-background: #ffffff00;
--window-background-color-bgfx: transparent; /* When background effects enabled */
--main-background-color: white;
--main-text-color: black;
@@ -84,7 +83,6 @@
--menu-text-color: #272727;
--menu-background-color: #ffffffd9;
--menu-background-color-no-backdrop: #fdfdfd;
--menu-item-icon-color: #727272;
--menu-item-disabled-opacity: 0.6;
--menu-item-keyboard-shortcut-color: #666666a8;
@@ -116,17 +114,15 @@
--quick-search-focus-border: #00000029;
--quick-search-focus-background: #ffffff80;
--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-background-color: #f2f2f2;
--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-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
--left-pane-item-action-button-background: rgba(0, 0, 0, 0.11);
--left-pane-item-action-button-background: #d7d7d7;
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, 0.15);
@@ -142,7 +138,6 @@
--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-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-background-color: #fafafa;
@@ -150,8 +145,6 @@
--launcher-pane-horiz-button-hover-background: var(--icon-button-hover-background);
--launcher-pane-horiz-button-hover-shadow: unset;
--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;
--sync-status-error-pulse-color: #ff5528;
@@ -165,10 +158,9 @@
--tab-close-button-hover-background: #c95a5a;
--tab-close-button-hover-color: white;
--active-tab-background-color: white;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-icon-color: gray;
--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-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-size: normal;
--monospace-font-family: JetBrainsLight, monospace;
--monospace-font-family: JetBrainsLight;
--monospace-font-size: normal;
--left-pane-item-selected-shadow-size: 2px;
@@ -83,12 +83,6 @@
--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
*
@@ -102,6 +96,10 @@ body.backdrop-effects-disabled {
font-size: 0.9rem !important;
}
.dropdown-menu {
--scrollbar-background-color: var(--menu-background-color);
}
body.mobile .dropdown-menu {
backdrop-filter: var(--dropdown-backdrop-filter);
border-radius: var(--dropdown-border-radius);
@@ -150,22 +148,12 @@ body.desktop .dropdown-submenu .dropdown-menu {
.dropdown-item,
body.mobile .dropdown-submenu .dropdown-toggle {
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. */
border-radius: 6px;
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 {
padding: 0 !important;
}
@@ -203,17 +191,13 @@ html body .dropdown-item[disabled] {
/* Menu item keyboard shortcut */
.dropdown-item kbd {
margin-left: 16px;
font-family: unset !important;
font-size: unset !important;
color: var(--menu-item-keyboard-shortcut-color) !important;
padding-top: 0;
}
.dropdown-item span.keyboard-shortcut {
color: var(--menu-item-keyboard-shortcut-color) !important;
margin-left: 16px;
}
.dropdown-divider {
position: relative;
border-color: transparent !important;
@@ -295,20 +279,6 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
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
*/
@@ -349,8 +319,6 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
#toast-container .toast .toast-body {
flex-grow: 1;
overflow: hidden;
text-overflow: ellipsis;
}
/*
@@ -562,9 +530,10 @@ li.dropdown-item a.dropdown-item-button:focus-visible {
}
/* List item */
.jump-to-note-dialog .aa-suggestion,
.note-detail-empty .aa-suggestion {
.jump-to-note-dialog .aa-suggestions div,
.note-detail-empty .aa-suggestions div {
border-radius: 6px;
padding: 6px 12px;
color: var(--menu-text-color);
cursor: default;
}

View File

@@ -5,8 +5,7 @@
button.btn.btn-primary,
button.btn.btn-secondary,
button.btn.btn-sm:not(.select-button),
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 {
button.btn.btn-success {
display: inline-flex;
align-items: 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-secondary:hover,
button.btn.btn-sm:not(.select-button):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 {
button.btn.btn-success:hover {
background: var(--cmd-button-hover-background-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-secondary:active,
button.btn.btn-sm:not(.select-button):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 {
button.btn.btn-success:active {
opacity: 0.85;
box-shadow: unset;
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-secondary:disabled,
button.btn.btn-sm:not(.select-button):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 {
button.btn.btn-success:disabled {
opacity: var(--cmd-button-disabled-opacity);
}
button.btn.btn-primary:focus-visible,
button.btn.btn-secondary:focus-visible,
button.btn.btn-sm:not(.select-button):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 {
button.btn.btn-success:focus-visible {
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 .tn-tool-button,
:root .btn.tn-tool-button,
:root .btn-group .tn-tool-button:not(:last-child),
:root .btn-group .tn-tool-button:last-child {
width: var(--icon-button-size);
@@ -96,11 +91,6 @@ button.btn.btn-success kbd {
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 {
margin-left: 4px !important;
}
@@ -159,11 +149,8 @@ input[type="password"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
:root input.ck.ck-input-text,
:root input.ck.ck-input-number,
textarea.form-control,
textarea,
:root textarea.ck.ck-textarea,
.tn-input-field {
outline: 3px solid transparent;
outline-offset: 6px;
@@ -180,11 +167,8 @@ input[type="password"]:hover,
input[type="date"]:hover,
input[type="time"]: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:hover,
:root textarea.ck.ck-textarea:hover,
.tn-input-field:hover {
background: var(--input-hover-background);
color: var(--input-hover-color);
@@ -197,11 +181,8 @@ input[type="password"]:focus,
input[type="date"]:focus,
input[type="time"]: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:focus,
:root textarea.ck.ck-textarea:focus,
.tn-input-field:focus,
.tn-input-field:focus-within {
box-shadow: unset;
@@ -474,7 +455,6 @@ optgroup {
left: 0;
width: var(--box-size);
height: 100%;
margin: unset;
opacity: 0 !important;
}

View File

@@ -4,7 +4,6 @@
:root {
--ck-font-face: var(--main-font-family);
--ck-input-label-height: 1.5em;
}
/*
@@ -308,11 +307,6 @@
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 */
:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list {
@@ -369,86 +363,19 @@
color: var(--accent);
}
/* Text snippet dropdown */
/* Action buttons */
div.ck-template-form {
padding: 8px;
:root .ck-link-actions button.ck-button,
:root .ck-link-form button.ck-button {
--ck-border-radius: 6px;
background: transparent;
box-shadow: unset;
}
div.ck-template-form .ck-labeled-field-view {
margin-bottom: 8px;
}
/* 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);
:root .ck-link-actions button.ck-button:hover,
:root .ck-link-form button.ck-button:hover {
background: var(--hover-item-background-color);
}
/* 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;
}
/*
* 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
*/

View File

@@ -96,6 +96,7 @@
background: var(--background) !important;
color: var(--color) !important;
line-height: unset;
cursor: help;
}
.sql-table-schemas-widget .sql-table-schemas button:hover,
@@ -105,15 +106,22 @@
--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-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 {
color: var(--tab-close-button-hover-background);
}
@@ -173,7 +181,9 @@ div.note-detail-empty {
}
.options-section:not(.tn-no-card) {
margin: auto;
margin: auto;
min-width: var(--options-card-min-width);
max-width: var(--options-card-max-width);
border-radius: 12px;
border: 1px solid var(--card-border-color) !important;
box-shadow: var(--card-box-shadow);
@@ -182,11 +192,6 @@ div.note-detail-empty {
margin-bottom: calc(var(--options-title-offset) + 26px) !important;
}
body.desktop .option-section:not(.tn-no-card) {
min-width: var(--options-card-min-width);
max-width: var(--options-card-max-width);
}
.note-detail-content-widget-content.options {
--default-padding: 15px;
padding-top: calc(var(--default-padding) + var(--options-title-offset) + var(--options-title-font-size));
@@ -228,6 +233,11 @@ body.desktop .option-section:not(.tn-no-card) {
margin-bottom: 0;
}
.options-section .options-mime-types {
padding: 0;
margin: 0;
}
.options-section .form-group {
margin-bottom: 1em;
}

View File

@@ -94,17 +94,18 @@ div.promoted-attributes-container {
/* Note type dropdown */
ul.note-type-dropdown .check {
div.note-type-dropdown .check {
margin-right: 6px;
}
ul.note-type-dropdown li.dropdown-item {
--menu-item-icon-vert-offset: 0;
}
/* 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;
}

View File

@@ -36,23 +36,32 @@ body.mobile {
/* #region Mica */
body.background-effects.platform-win32 {
--background-material: tabbed;
--launcher-pane-horiz-border-color: var(--launcher-pane-horiz-border-color-bgfx);
--launcher-pane-horiz-background-color: var(--launcher-pane-horiz-background-color-bgfx);
--launcher-pane-vert-background-color: var(--launcher-pane-vert-background-color-bgfx);
--tab-background-color: var(--window-background-color-bgfx);
--new-tab-button-background: var(--window-background-color-bgfx);
--launcher-pane-horiz-border-color: rgba(0, 0, 0, 0.15);
--launcher-pane-horiz-background-color: rgba(255, 255, 255, 0.7);
--launcher-pane-vert-background-color: rgba(255, 255, 255, 0.055);
--tab-background-color: transparent;
--new-tab-button-background: transparent;
--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 {
--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;
}
body.background-effects.platform-win32,
body.background-effects.platform-win32 #root-widget {
background: var(--window-background-color-bgfx) !important;
body.background-effects.platform-win32 #root-widget,
body.background-effects.platform-win32 #launcher-pane .launcher-button {
background: transparent !important;
}
body.background-effects.platform-win32.layout-horizontal #horizontal-main-container,
@@ -81,7 +90,7 @@ body.background-effects.zen #root-widget {
* Gutter
*/
.gutter {
.gutter {
background: var(--gutter-color) !important;
transition: background 150ms ease-out;
}
@@ -223,7 +232,7 @@ body.layout-horizontal > .horizontal {
}
#launcher-pane .launcher-button:focus,
#launcher-pane .global-menu :focus {
#launcher-pane .global-menu button:focus {
outline: none;
}
@@ -304,11 +313,24 @@ body.layout-horizontal > .horizontal {
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-dropdown-widget {
width: unset !important;
padding: 12px;
color: var(--calendar-color);
user-select: none;
@@ -336,21 +358,6 @@ body.layout-horizontal > .horizontal {
--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) {
.calendar-dropdown-widget .calendar-header button {
margin: 0 !important;
@@ -565,28 +572,29 @@ div.quick-search .search-button.show {
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
* when background effects are enabled in Electron.
* As a temporary workaround, the backdrop and transparency are disabled for the
* vertical layout.
* Quick search results
*/
body.layout-vertical.background-effects div.quick-search .dropdown-menu {
--menu-background-color: var(--menu-background-color-no-backdrop) !important;
}
/* Item */
.quick-search .dropdown-menu *.dropdown-item {
padding: 8px 12px !important;
}
.quick-search .quick-search-item-icon {
vertical-align: text-bottom;
/* Note icon */
.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 */
@@ -597,24 +605,6 @@ body.layout-vertical.background-effects div.quick-search .dropdown-menu {
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
*/
@@ -875,10 +865,7 @@ body.mobile .fancytree-node > span {
}
.tab-row-container .toggle-button {
--icon-button-size: 30px;
--icon-button-icon-ratio: .6;
margin: 3px 6px auto 8px !important;
margin: 6px 10px !important;
}
.tab-row-container {
@@ -890,80 +877,6 @@ body.layout-horizontal .tab-row-container {
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 {
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);
}
: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 {
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 */
}
.split-note-container-widget > .gutter {
background: var(--root-background) !important;
transition: background 150ms ease-out;
}
/*
* 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;
}
.note-split:not(.hidden-ext) + .note-split:not(.hidden-ext) {
border-left: 4px solid var(--root-background);
}
@keyframes note-entrance {
from {
opacity: 0;
@@ -1471,7 +1375,7 @@ div.floating-buttons-children .floating-button:active {
}
/* 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);
}
@@ -1573,6 +1477,13 @@ div.floating-buttons-children .close-floating-buttons:has(.close-floating-button
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 */
.floating-buttons .code-buttons-widget,

View File

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

View File

@@ -276,12 +276,7 @@
"mime": "MIME 类型: ",
"file_size": "文件大小:",
"preview": "预览:",
"preview_not_available": "无法预览此类型的笔记。",
"diff_on": "显示差异",
"diff_off": "显示内容",
"diff_on_hint": "点击以显示笔记源代码差异",
"diff_off_hint": "点击以显示笔记内容",
"diff_not_available": "差异不可用。"
"preview_not_available": "无法预览此类型的笔记。"
},
"sort_child_notes": {
"sort_children_by": "按...排序子笔记",
@@ -592,18 +587,7 @@
"september": "九月",
"october": "十月",
"november": "十一月",
"december": "十二月",
"week_previous": "上周",
"week_next": "下周",
"month_previous": "上个月",
"month_next": "下个月",
"year": "年",
"year_previous": "上一年",
"year_next": "明年",
"today": "今天",
"week": "周",
"month": "月",
"list": "列表"
"december": "十二月"
},
"close_pane_button": {
"close_this_pane": "关闭此面板"
@@ -748,8 +732,7 @@
"note_type": "笔记类型",
"editable": "可编辑",
"basic_properties": "基本属性",
"language": "语言",
"configure_code_notes": "配置代码注释..."
"language": "语言"
},
"book_properties": {
"view_type": "视图类型",
@@ -764,8 +747,7 @@
"book_properties": "集合属性",
"table": "表格",
"geo-map": "地理地图",
"board": "看板",
"include_archived_notes": "展示归档笔记"
"board": "看板"
},
"edited_notes": {
"no_edited_notes_found": "今天还没有编辑过的笔记...",
@@ -866,7 +848,7 @@
"debug": "调试",
"debug_description": "调试将打印额外的调试信息到控制台,以帮助调试复杂查询",
"action": "操作",
"search_button": "搜索",
"search_button": "搜索 <kbd>回车</kbd>",
"search_execute": "搜索并执行操作",
"save_to_note": "保存到笔记",
"search_parameters": "搜索参数",
@@ -966,9 +948,7 @@
"no_attachments": "此笔记没有附件。"
},
"book": {
"no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> 了解详情。",
"drag_locked_title": "锁定编辑",
"drag_locked_message": "无法拖拽,因为集合已被锁定编辑。"
"no_children_help": "此类型为书籍的笔记没有任何子笔记,因此没有内容显示。请参阅 <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> 了解详情。"
},
"editable_code": {
"placeholder": "在这里输入您的代码笔记内容..."
@@ -1185,7 +1165,7 @@
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_interval_title": "笔记修订快照间隔",
"note_revisions_snapshot_description": "笔记修订快照间隔是创建新笔记修订的时间。有关更多信息,请参见 <doc>wiki</doc>。",
"note_revisions_snapshot_description": "笔记修订快照间隔是创建新笔记修订的时间。有关更多信息,请参见 <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki</a>。",
"snapshot_time_interval_label": "笔记修订快照时间间隔:"
},
"revisions_snapshot_limit": {
@@ -1426,7 +1406,7 @@
"button-tree-map": "树形地图"
},
"tree-context-menu": {
"open-in-a-new-tab": "在新标签页中打开",
"open-in-a-new-tab": "在新标签页中打开 <kbd>Ctrl+Click</kbd>",
"open-in-a-new-split": "在新分栏中打开",
"insert-note-after": "在后面插入笔记",
"insert-child-note": "插入子笔记",
@@ -1456,14 +1436,12 @@
"converted-to-attachments": "{{count}} 个笔记已被转换为附件。",
"convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?",
"duplicate": "复制",
"open-in-popup": "快速编辑",
"archive": "归档",
"unarchive": "解压"
"open-in-popup": "快速编辑"
},
"shared_info": {
"help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。",
"shared_publicly": "笔记已在 {{- link}} 上公开分享",
"shared_locally": "此笔记在本地通过 {{- link}} 进行共享。"
"shared_publicly": "此笔记已公开分享于",
"shared_locally": "笔记已在本地分享",
"help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。"
},
"note_types": {
"text": "文本",
@@ -1541,8 +1519,7 @@
"hoist-this-note-workspace": "聚焦此笔记(工作区)",
"refresh-saved-search-results": "刷新保存的搜索结果",
"create-child-note": "创建子笔记",
"unhoist": "取消聚焦",
"toggle-sidebar": "切换侧边栏"
"unhoist": "取消聚焦"
},
"title_bar_buttons": {
"window-on-top": "保持此窗口置顶"
@@ -1699,7 +1676,7 @@
"native-title-bar": "原生标题栏",
"native-title-bar-description": "对于 Windows 和 macOS关闭原生标题栏可使应用程序看起来更紧凑。在 Linux 上,保留原生标题栏可以更好地与系统集成。",
"background-effects": "启用背景效果(仅适用于 Windows 11",
"background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。「原生标题栏」必須被禁用。",
"background-effects-description": "Mica 效果为应用窗口添加模糊且时尚的背景,营造出深度感和现代外观。",
"restart-app-button": "重启应用程序以查看更改",
"zoom-factor": "缩放系数"
},
@@ -1894,19 +1871,14 @@
"selected_provider": "已选提供商",
"selected_provider_description": "选择用于聊天和补全功能的AI提供商",
"select_model": "选择模型...",
"select_provider": "选择提供商...",
"ai_enabled": "已启用 AI 功能",
"ai_disabled": "已禁用 AI 功能",
"no_models_found_online": "找不到模型。请检查您的 API 密钥及设置。",
"no_models_found_ollama": "找不到 Ollama 模型。请确认 Ollama 是否正在运行。",
"error_fetching": "获取模型失败:{{error}}"
"select_provider": "选择提供商..."
},
"code-editor-options": {
"title": "编辑器"
},
"custom_date_time_format": {
"title": "自定义日期/时间格式",
"description": "通过<shortcut />或工具栏的方式可自定义日期和时间格式,有关日期/时间格式字符串中各个字符的含义,请参阅<doc>Day.js docs</doc>。",
"description": "通过<kbd></kbd>或工具栏的方式可自定义日期和时间格式,有关日期/时间格式字符串中各个字符的含义,请参阅<a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Day.js docs</a>。",
"format_string": "日期/时间格式字符串:",
"formatted_time": "格式化后日期/时间:"
},
@@ -1988,21 +1960,14 @@
"delete_row": "删除行"
},
"board_view": {
"delete-note": "删除笔记...",
"delete-note": "删除笔记",
"move-to": "移动到",
"insert-above": "在上方插入",
"insert-below": "在下方插入",
"delete-column": "删除列",
"delete-column-confirmation": "确定要删除此列吗?此列下所有笔记中对应的属性也将被删除。",
"new-item": "新增项目",
"add-column": "添加列",
"archive-note": "存档笔记",
"unarchive-note": "解压笔记",
"new-item-placeholder": "输入笔记标题...",
"add-column-placeholder": "请输入列名...",
"edit-note-title": "点击编辑笔记标题",
"edit-column-title": "点击编辑列标题",
"remove-from-board": "从看板上移除"
"add-column": "添加列"
},
"command_palette": {
"tree-action-name": "树形:{{name}}",
@@ -2027,37 +1992,11 @@
"help_title": "显示关于此画面的更多信息"
},
"call_to_action": {
"next_theme_title": "新的 Trilium 主题已进入稳定版",
"next_theme_message": "有一段时间,我们一直在设计新的主题,为了让应用程序看起来更加现代。",
"next_theme_button": "切换至新的 Trilium 主题",
"background_effects_title": "背景效果现已推出稳定版本",
"background_effects_message": "在 Windows 装置上,背景效果现在已完全稳定。背景效果通过模糊背后的背景,为使用者界面增添一抹色彩。此技术也用于其他应用程序,例如 Windows 资源管理器。",
"background_effects_button": "启用背景效果",
"next_theme_title": "试用新 Trilium 主题",
"next_theme_message": "当前使用旧版主题,要试用新主题吗?",
"next_theme_button": "试用新主题",
"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": "出现错误无法显示内容。"
"background_effects_button": "启用背景效果"
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -263,11 +263,6 @@
"confirm_delete_all": "Do you want to delete all revisions of this note?",
"no_revisions": "No revisions for this note yet...",
"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.",
"delete_button": "Delete",
"confirm_delete": "Do you want to delete this revision?",
@@ -592,18 +587,7 @@
"september": "September",
"october": "October",
"november": "November",
"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"
"december": "December"
},
"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": "Configure code notes..."
"language": "Language"
},
"book_properties": {
"view_type": "View type",
@@ -764,8 +747,7 @@
"calendar": "Calendar",
"table": "Table",
"geo-map": "Geo Map",
"board": "Board",
"include_archived_notes": "Show archived notes"
"board": "Board"
},
"edited_notes": {
"no_edited_notes_found": "No edited notes on this day yet...",
@@ -866,7 +848,7 @@
"debug": "debug",
"debug_description": "Debug will print extra debugging information into the console to aid in debugging complex queries",
"action": "action",
"search_button": "Search",
"search_button": "Search <kbd>enter</kbd>",
"search_execute": "Search & Execute actions",
"save_to_note": "Save to note",
"search_parameters": "Search Parameters",
@@ -966,9 +948,7 @@
"no_attachments": "This note has no attachments."
},
"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.",
"drag_locked_title": "Locked for editing",
"drag_locked_message": "Dragging not allowed since the collection is locked for editing."
"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."
},
"editable_code": {
"placeholder": "Type the content of your code note here..."
@@ -1133,14 +1113,6 @@
"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."
},
"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": {
"not_started": "Not started",
"title": "AI Settings",
@@ -1281,12 +1253,7 @@
"selected_provider": "Selected Provider",
"selected_provider_description": "Choose the AI provider for chat and completion features",
"select_model": "Select model...",
"select_provider": "Select provider...",
"ai_enabled": "AI features enabled",
"ai_disabled": "AI features disabled",
"no_models_found_online": "No models found. Please check your API key and settings.",
"no_models_found_ollama": "No Ollama models found. Please check if Ollama is running.",
"error_fetching": "Error fetching models: {{error}}"
"select_provider": "Select provider..."
},
"zoom_factor": {
"title": "Zoom Factor (desktop build only)",
@@ -1343,7 +1310,7 @@
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_interval_title": "Note Revision Snapshot Interval",
"note_revisions_snapshot_description": "The Note revision snapshot interval is the time after which a new note revision will be created for the note. See <doc>wiki</doc> for more info.",
"note_revisions_snapshot_description": "The Note revision snapshot interval is the time after which a new note revision will be created for the note. See <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki</a> for more info.",
"snapshot_time_interval_label": "Note revision snapshot time interval:"
},
"revisions_snapshot_limit": {
@@ -1405,7 +1372,7 @@
},
"custom_date_time_format": {
"title": "Custom Date/Time Format",
"description": "Customize the format of the date and time inserted via <shortcut /> or the toolbar. See <doc>Day.js docs</doc> for available format tokens.",
"description": "Customize the format of the date and time inserted via <kbd></kbd> or the toolbar. See <a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Day.js docs</a> for available format tokens.",
"format_string": "Format string:",
"formatted_time": "Formatted date/time:"
},
@@ -1590,12 +1557,10 @@
"button-tree-map": "Tree map"
},
"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",
"insert-note-after": "Insert note after",
"insert-child-note": "Insert child note",
"archive": "Archive",
"unarchive": "Unarchive",
"delete": "Delete",
"search-in-subtree": "Search in subtree",
"hoist-note": "Hoist note",
@@ -1625,8 +1590,8 @@
"open-in-popup": "Quick edit"
},
"shared_info": {
"shared_publicly": "This note is shared publicly on {{- link}}.",
"shared_locally": "This note is shared locally on {{- link}}.",
"shared_publicly": "This note is shared publicly on",
"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>."
},
"note_types": {
@@ -1705,8 +1670,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": "Toggle sidebar"
"unhoist": "Unhoist"
},
"title_bar_buttons": {
"window-on-top": "Keep Window on Top"
@@ -1863,7 +1827,7 @@
"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.",
"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",
"zoom-factor": "Zoom factor"
},
@@ -1962,11 +1926,7 @@
"editorfeatures": {
"title": "Features",
"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_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 `/`."
"note_completion_enabled": "Enable note auto-completion"
},
"table_view": {
"new-row": "New row",
@@ -2002,21 +1962,14 @@
"delete_row": "Delete row"
},
"board_view": {
"delete-note": "Delete note...",
"remove-from-board": "Remove from board",
"archive-note": "Archive note",
"unarchive-note": "Unarchive note",
"delete-note": "Delete Note",
"move-to": "Move to",
"insert-above": "Insert above",
"insert-below": "Insert below",
"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.",
"new-item": "New item",
"new-item-placeholder": "Enter note title...",
"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"
"add-column": "Add Column"
},
"command_palette": {
"tree-action-name": "Tree: {{name}}",
@@ -2041,29 +1994,11 @@
"help_title": "Display more information about this screen"
},
"call_to_action": {
"next_theme_title": "Try the new Trilium theme",
"next_theme_message": "You are currently using the legacy theme, would you like to try the new theme?",
"next_theme_button": "Try the new theme",
"next_theme_title": "The new Trilium theme is now stable",
"next_theme_message": "For a while now, we've been working on a new theme to give the application a more modern look.",
"next_theme_button": "Switch to the new Trilium theme",
"background_effects_title": "Background effects are now stable",
"background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of color to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer.",
"background_effects_button": "Enable background effects",
"dismiss": "Dismiss"
},
"settings": {
"related_settings": "Related settings"
},
"settings_appearance": {
"related_code_blocks": "Color scheme for code blocks in text notes",
"related_code_notes": "Color scheme for code notes"
},
"units": {
"percentage": "%"
},
"pagination": {
"page_title": "Page of {{startIndex}} - {{endIndex}}",
"total_notes": "{{count}} notes"
},
"collections": {
"rendering_error": "Unable to show content due to an error."
"background_effects_button": "Enable background effects"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
{
"about": {
"title": "درباره Trilium Notes",
"homepage": "صفحه اصلی:",
"app_version": "نسخه برنامه:",
"db_version": "نسخه پایگاه داده:",
"sync_version": "نسخه منطبق:",
"build_date": "تاریخ ساخت:",
"build_revision": "نسخه بازنگری شده:",
"data_directory": "دایرکتوری داده:"
},
"toast": {
"critical-error": {
"title": "خطای بحرانی",
"message": "خطای بحرانی رخ داده که مانع از اجرای برنامه می شود\n\n {{message}}\n\nبه احتمال زیاد ناشی از خطای غیرمنتظره در اجرای ناموفق یک اسکریپت است. برنامه را در مد ایمن اجرا کنید و خطا را بررسی نمایید."
}
},
"add_link": {
"add_link": "افزودن لینک",
"note": "یادداشت"
}
}

View File

@@ -1,147 +0,0 @@
{
"about": {
"title": "Lisätietoja Trilium Notes:ista",
"homepage": "Kotisivu:",
"app_version": "Sovelluksen versio:",
"db_version": "Tietokannan versio:",
"build_date": "Koontipäivämäärä:",
"data_directory": "Datakansio:",
"sync_version": "Synkronoinnin versio:",
"build_revision": "Sovelluksen versio:"
},
"toast": {
"critical-error": {
"title": "Kriittinen virhe"
},
"widget-error": {
"title": "Widgetin luonti epäonnistui"
}
},
"add_link": {
"add_link": "Lisää linkki",
"link_title": "Linkin otsikko",
"button_add_link": "Lisää linkki",
"note": "Muistio",
"search_note": "etsi muistiota sen nimellä"
},
"branch_prefix": {
"prefix": "Etuliite: ",
"save": "Tallenna"
},
"bulk_actions": {
"bulk_actions": "Massatoiminnot",
"available_actions": "Saatavilla olevat toiminnot",
"chosen_actions": "Valitut toiminnot",
"execute_bulk_actions": "Toteuta massatoiminnot",
"bulk_actions_executed": "Massatoiminnot on toteutettu onnistuneesti.",
"none_yet": "Ei vielä... lisää toiminto klikkaamalla jotiain yllä saatavilla olevaa yltä.",
"labels": "Merkit",
"relations": "Suhteet",
"notes": "Muistiot",
"other": "Muut",
"affected_notes": "Vaikuttaa muistioihin"
},
"clone_to": {
"clone_notes_to": "Kopioi muistiot...",
"help_on_links": "Apua linkkeihin",
"notes_to_clone": "Kopioitavat muistiot",
"target_parent_note": "Kohteen päämuistio",
"search_for_note_by_its_name": "ensi muistiota sen nimellä",
"cloned_note_prefix_title": "Kopioitu muistia näytetään puussa annetulla etuliitteellä",
"prefix_optional": "Etuliite (valinnainen)",
"clone_to_selected_note": "Kopioi valittuun muistioon",
"note_cloned": "Muistio \"{{clonedTitle}}\" on kopioitu \"{{targetTitle}}\""
},
"confirm": {
"confirmation": "Vahvistus",
"cancel": "Peruuta",
"ok": "OK",
"also_delete_note": "Poista myös muistio"
},
"delete_notes": {
"delete_notes_preview": "Poista muistion esikatselu",
"close": "Sulje",
"notes_to_be_deleted": "Seuraavat muistiot tullaan poistamaan ({{notesCount}})",
"no_note_to_delete": "Muistioita ei poisteta (vain kopiot).",
"cancel": "Peruuta",
"ok": "OK"
},
"export": {
"export_note_title": "Vie muistio",
"close": "Sulje",
"format_html": "HTML - suositeltu, sillä se säilyttää kaikki formatoinnit",
"format_markdown": "Markdown - tämä säilyttää suurimman osan formatoinneista.",
"opml_version_1": "OPML v1.0 - pelkkä teksti",
"opml_version_2": "OPML v2.0 - sallii myös HTML:n",
"export": "Vie",
"choose_export_type": "Valitse ensin viennin tyyppi",
"export_status": "Viennin tila",
"export_in_progress": "Vienti käynnissä: {{progressCount}}",
"export_finished_successfully": "Vienti valmistui onnistuneesti.",
"format_pdf": "PDF - tulostukseen ja jakamiseen."
},
"help": {
"title": "Lunttilappu",
"noteNavigation": "Muistion navigointi",
"goUpDown": "mene ylös/alas muistioiden listassa",
"collapseExpand": "pienennä/suurenna solmu",
"notSet": "ei asetettu",
"goBackForwards": "mene taaksepäin/eteenpäin historiassa",
"jumpToParentNote": "Hyppää ylempään muistioon",
"collapseWholeTree": "pienennä koko muistio puu",
"onlyInDesktop": "Vain työpöytänäkymässä (Electron build)",
"openEmptyTab": "Avaa tyhjä välilehti",
"closeActiveTab": "sulje aktiivinen välilehti",
"activateNextTab": "aktivoi seuraava välilehti",
"activatePreviousTab": "aktivoi edellinen välilehti",
"creatingNotes": "Luo muistiota",
"movingCloningNotes": "Siirrä / kopioi muistioita",
"moveNoteUpHierarchy": "siirrä muistio ylöspäin listassa",
"selectNote": "valitse muistio",
"editingNotes": "Muokkaa solmua",
"createEditLink": "luo / muokkaa ulkoista linkkiä",
"createInternalLink": "luo sisäinen linkki",
"insertDateTime": "lisää nykyinen päivämäärä ja aika hiiren kohdalle",
"troubleshooting": "Vianmääritys",
"reloadFrontend": "lataa Trilium:in käyttöliittymä",
"showDevTools": "näytä kehittäjätyökalut",
"showSQLConsole": "näytä SQL konsoli",
"other": "Muut"
},
"import": {
"importIntoNote": "Tuo muistioon",
"chooseImportFile": "Valitse tuonnin tiedosto",
"options": "Valinnat",
"safeImport": "Turvallinen tuonti",
"shrinkImages": "Kutista kuvat",
"replaceUnderscoresWithSpaces": "Korvaa alaviivat väleillä tuotujen muistioiden tiedostonimissä",
"import": "Tuo",
"failed": "Tuonti epäonnistui: {{message}}.",
"html_import_tags": {
"title": "HTML Tuonnin Tunnisteet",
"placeholder": "Lisää HTML tunnisteet, yksi per rivi"
},
"import-status": "Tuonnin tila",
"in-progress": "Tuonti vaiheessa: {{progress}}",
"successful": "Tuonti valmistui onnistuneesti."
},
"include_note": {
"dialog_title": "Sisällytä muistio",
"label_note": "Muistio",
"placeholder_search": "etsi muistiota sen nimellä",
"box_size_small": "pieni (~ 10 riviä)",
"box_size_medium": "keskisuuri (~ 30 riviä)",
"button_include": "Sisällytä muistio"
},
"info": {
"modalTitle": "Info viesti",
"closeButton": "Sulje",
"okButton": "OK"
},
"jump_to_note": {
"search_button": "Etsi koko tekstistä"
},
"call_to_action": {
"dismiss": "Hylkää"
}
}

View File

@@ -202,8 +202,7 @@
"okButton": "OK"
},
"jump_to_note": {
"search_button": "Rechercher dans le texte intégral",
"search_placeholder": "Rechercher une note par son nom ou saisir > pour les commandes…"
"search_button": "Rechercher dans le texte intégral"
},
"markdown_import": {
"dialog_title": "Importation Markdown",
@@ -223,16 +222,11 @@
"note_type_chooser": {
"modal_title": "Choisissez le type de note",
"modal_body": "Choisissez le type de note/le modèle de la nouvelle note :",
"templates": "Modèles",
"change_path_prompt": "Modifier lemplacement de création de la nouvelle note :",
"search_placeholder": "Rechercher le chemin par nom (par défaut si vide)",
"builtin_templates": "Modèles intégrés"
"templates": "Modèles"
},
"password_not_set": {
"title": "Le mot de passe n'est pas défini",
"body1": "Les notes protégées sont cryptées à l'aide d'un mot de passe utilisateur, mais le mot de passe n'a pas encore été défini.",
"body2": "Pour pouvoir protéger les notes, cliquez sur le bouton ci-dessous pour ouvrir la boîte de dialogue Options et définir votre mot de passe.",
"go_to_password_options": "Accéder aux options de mot de passe"
"body1": "Les notes protégées sont cryptées à l'aide d'un mot de passe utilisateur, mais le mot de passe n'a pas encore été défini."
},
"prompt": {
"title": "Prompt",
@@ -274,9 +268,7 @@
"mime": "MIME : ",
"file_size": "Taille du fichier :",
"preview": "Aperçu :",
"preview_not_available": "L'aperçu n'est pas disponible pour ce type de note.",
"restore_button": "Restaurer",
"delete_button": "Supprimer"
"preview_not_available": "L'aperçu n'est pas disponible pour ce type de note."
},
"sort_child_notes": {
"sort_children_by": "Trier les enfants par...",
@@ -392,7 +384,7 @@
"share_index": "la note avec ce label listera toutes les racines des notes partagées",
"display_relations": "noms des relations délimités par des virgules qui doivent être affichés. Tous les autres seront masqués.",
"hide_relations": "noms de relations délimités par des virgules qui doivent être masqués. Tous les autres seront affichés.",
"title_template": "titre par défaut des notes créées en tant qu'enfants de cette note. La valeur est évaluée sous forme de chaîne JavaScript \n et peut ainsi être enrichi de contenu dynamique via les variables injectées <code>now</code> et <code>parentNote</code>. Exemples :\n \n <ul>\n <li><code>Œuvres littéraires de ${parentNote.getLabelValue('authorName')}</code></li>\n <li><code>Connectez-vous pour ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Consultez le <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki avec plus de détails</a>, la documentation sur l'API pour <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> et <a href=\"https://day.js.org/docs/en/display/format\">maintenant</a> pour plus de détails.",
"title_template": "titre par défaut des notes créées en tant qu'enfants de cette note. La valeur est évaluée sous forme de chaîne JavaScript \n et peut ainsi être enrichi de contenu dynamique via les variables injectées <code>now</code> et <code>parentNote</code>. Exemples :\n \n <ul>\n <li><code>Œuvres littéraires de ${parentNote.getLabelValue('authorName')}</code></li>\n <li><code>Connectez-vous pour ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n Consultez le <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki avec plus de détails</a>, la documentation sur l'API pour <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> et <a href=\"https://day.js.org/docs/en/display/format\">maintenant< /a> pour plus de détails.",
"template": "Cette note apparaîtra parmi les modèles disponibles lors de la création d'une nouvelle note",
"toc": "<code>#toc</code> ou <code>#toc=show</code> forcera l'affichage de la table des matières, <code>#toc=hide</code> force qu'elle soit masquée. Si le label n'existe pas, le paramètre global est utilisé",
"color": "définit la couleur de la note dans l'arborescence des notes, les liens, etc. Utilisez n'importe quelle valeur de couleur CSS valide comme « rouge » ou #a13d5f",
@@ -426,8 +418,7 @@
"other_notes_with_name": "Autres notes portant le nom {{attributeType}} \"{{attributeName}}\"",
"and_more": "... et {{count}} plus.",
"print_landscape": "Lors de l'exportation en PDF, change l'orientation de la page en paysage au lieu de portrait.",
"print_page_size": "Lors de l'exportation en PDF, change la taille de la page. Valeurs supportées : <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": "Couleur"
"print_page_size": "Lors de l'exportation en PDF, change la taille de la page. Valeurs supportées : <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>."
},
"attribute_editor": {
"help_text_body1": "Pour ajouter un label, tapez simplement par ex. <code>#rock</code>, ou si vous souhaitez également ajouter une valeur, tapez par ex. <code>#année = 2020</code>",
@@ -586,8 +577,7 @@
"september": "Septembre",
"october": "Octobre",
"november": "Novembre",
"december": "Décembre",
"cannot_find_week_note": "Impossible de trouver la note de la semaine"
"december": "Décembre"
},
"close_pane_button": {
"close_this_pane": "Fermer ce volet"
@@ -731,8 +721,7 @@
"basic_properties": {
"note_type": "Type de note",
"editable": "Modifiable",
"basic_properties": "Propriétés de base",
"language": "Langage"
"basic_properties": "Propriétés de base"
},
"book_properties": {
"view_type": "Type d'affichage",
@@ -743,11 +732,7 @@
"collapse": "Réduire",
"expand": "Développer",
"invalid_view_type": "Type de vue non valide '{{type}}'",
"calendar": "Calendrier",
"book_properties": "Propriétés de la collection",
"table": "Tableau",
"geo-map": "Carte géographique",
"board": "Tableau de bord"
"calendar": "Calendrier"
},
"edited_notes": {
"no_edited_notes_found": "Aucune note modifiée ce jour-là...",
@@ -824,8 +809,7 @@
"unknown_label_type": "Type de label inconnu '{{type}}'",
"unknown_attribute_type": "Type d'attribut inconnu '{{type}}'",
"add_new_attribute": "Ajouter un nouvel attribut",
"remove_this_attribute": "Supprimer cet attribut",
"remove_color": "Supprimer létiquette de couleur"
"remove_this_attribute": "Supprimer cet attribut"
},
"script_executor": {
"query": "Requête",
@@ -848,7 +832,7 @@
"debug": "debug",
"debug_description": "Debug imprimera des informations supplémentaires dans la console pour faciliter le débogage des requêtes complexes",
"action": "action",
"search_button": "Recherche",
"search_button": "Recherche <kbd>Entrée</kbd>",
"search_execute": "Rechercher et exécuter des actions",
"save_to_note": "Enregistrer dans la note",
"search_parameters": "Paramètres de recherche",
@@ -915,7 +899,7 @@
"description1": "Le script de recherche permet de définir les résultats de la recherche en exécutant un script. Cela offre une flexibilité maximale lorsque la recherche standard ne suffit pas.",
"description2": "Le script de recherche doit être de type \"code\" et sous-type \"backend JavaScript\". Le script doit retourner un tableau de noteIds ou de notes.",
"example_title": "Voir cet exemple :",
"example_code": "// 1. préfiltrage à l'aide de la recherche standard\nconst candidateNotes = api.searchForNotes(\"#journal\"); \n\n// 2. application de critères de recherche personnalisés\nconst matchedNotes = candidateNotes\n .filter(note => note.title.match(/[0-9]{1,2}\\.?[0-9]{1,2}\\.?[0-9]{4}/));\n\nreturn matchedNotes;",
"example_code": "// 1. préfiltrage à l'aide de la recherche standard\nconst candidateNotes = api.searchForNotes(\"#journal\"); \n\n// 2. application de critères de recherche personnalisés\nconst matchedNotes = candidateNotes\n .filter(note => note.title.match(/[0-9]{1,2}\\. ?[0-9]{1,2}\\. ?[0-9]{4}/));\n\nreturn matchedNotes;",
"note": "Notez que le script de recherche et la l'expression à rechercher standard ne peuvent pas être combinés."
},
"search_string": {
@@ -1084,8 +1068,7 @@
"max_width_label": "Largeur maximale du contenu en pixels",
"apply_changes_description": "Pour appliquer les modifications de largeur du contenu, cliquez sur",
"reload_button": "recharger l'interface",
"reload_description": "changements par rapport aux options d'apparence",
"max_width_unit": "Pixels"
"reload_description": "changements par rapport aux options d'apparence"
},
"native_title_bar": {
"title": "Barre de titre native (nécessite le redémarrage de l'application)",
@@ -1108,10 +1091,7 @@
"layout-vertical-title": "Vertical",
"layout-horizontal-title": "Horizontal",
"layout-vertical-description": "la barre de raccourcis est à gauche (défaut)",
"layout-horizontal-description": "la barre de raccourcis est sous la barre des onglets, cette-dernière est s'affiche en pleine largeur.",
"auto_theme": "Hérité (suivre le schéma de couleurs du système)",
"light_theme": "Hérité (clair)",
"dark_theme": "Hérité (foncé)"
"layout-horizontal-description": "la barre de raccourcis est sous la barre des onglets, cette-dernière est s'affiche en pleine largeur."
},
"zoom_factor": {
"title": "Facteur de zoom (version bureau uniquement)",
@@ -1156,14 +1136,14 @@
"note_erasure_timeout": {
"note_erasure_timeout_title": "Délai d'effacement des notes",
"note_erasure_description": "Les notes supprimées (et les attributs, versions...) sont seulement marquées comme supprimées et il est possible de les récupérer à partir de la boîte de dialogue Notes récentes. Après un certain temps, les notes supprimées sont « effacées », ce qui signifie que leur contenu n'est plus récupérable. Ce paramètre vous permet de configurer la durée entre la suppression et l'effacement de la note.",
"erase_notes_after": "Effacer les notes après :",
"erase_notes_after": "Effacer les notes après:",
"manual_erasing_description": "Vous pouvez également déclencher l'effacement manuellement (sans tenir compte de la durée définie ci-dessus) :",
"erase_deleted_notes_now": "Effacer les notes supprimées maintenant",
"deleted_notes_erased": "Les notes supprimées ont été effacées."
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_interval_title": "Délai d'enregistrement automatique d'une version de note",
"note_revisions_snapshot_description": "Le délai d'enregistrement automatique des versions de note définit le temps avant la création automatique d'une nouvelle version de note. Consultez le <doc>wiki</doc> pour plus d'informations.",
"note_revisions_snapshot_description": "Le délai d'enregistrement automatique des versions de note définit le temps avant la création automatique d'une nouvelle version de note. Consultez le <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki</a> pour plus d'informations.",
"snapshot_time_interval_label": "Délai d'enregistrement automatique de version de note :"
},
"revisions_snapshot_limit": {
@@ -1357,7 +1337,7 @@
"button-tree-map": "Carte de l'arborescence"
},
"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",
"insert-note-after": "Insérer une note après",
"insert-child-note": "Insérer une note enfant",
@@ -1389,8 +1369,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 ?"
},
"shared_info": {
"shared_publicly": "Cette note est partagée publiquement sur {{- link}}",
"shared_locally": "Cette note est partagée localement sur {{- link}}",
"shared_publicly": "Cette note est partagée publiquement sur",
"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>."
},
"note_types": {
@@ -1670,26 +1650,5 @@
},
"modal": {
"close": "Fermer"
},
"ai_llm": {
"not_started": "Non démarré",
"title": "Paramètres IA",
"processed_notes": "Notes traitées",
"n_notes_queued_0": "{{ count }} note en attente dindexation",
"n_notes_queued_1": "{{ count }} notes en attente dindexation",
"n_notes_queued_2": "",
"notes_indexed_0": "{{ count }} note indexée",
"notes_indexed_1": "{{ count }} notes indexées",
"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"
}
}

View File

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

View File

@@ -1,356 +1,345 @@
{
"about": {
"app_version": "Versione dell'app:",
"db_version": "Versione DB:",
"sync_version": "Versione Sync:",
"data_directory": "Cartella dati:",
"title": "Informazioni su Trilium Notes",
"build_date": "Data della build:",
"build_revision": "Revisione della build:",
"homepage": "Homepage:"
},
"toast": {
"critical-error": {
"title": "Errore critico",
"message": "Si è verificato un errore critico che impedisce l'avvio dell'applicazione client:\n\n{{message}}\n\nQuesto è probabilmente causato da un errore di script inaspettato. Prova a avviare l'applicazione in modo sicuro e controlla il problema."
"about": {
"app_version": "Versione dell'app:",
"db_version": "Versione DB:",
"sync_version": "Versione Sync:",
"data_directory": "Cartella dati:",
"title": "Informazioni su Trilium Notes",
"build_date": "Data della build:",
"build_revision": "Revisione della build:",
"homepage": "Homepage:"
},
"bundle-error": {
"title": "Non si è riusciti a caricare uno script personalizzato",
"message": "Lo script della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}"
"toast": {
"critical-error": {
"title": "Errore critico",
"message": "Si è verificato un errore critico che impedisce l'avvio dell'applicazione client:\n\n{{message}}\n\nQuesto è probabilmente causato da un errore di script inaspettato. Prova a avviare l'applicazione in modo sicuro e controlla il problema."
},
"bundle-error": {
"title": "Non si è riusciti a caricare uno script personalizzato",
"message": "Lo script della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}"
},
"widget-error": {
"title": "Impossibile inizializzare un widget",
"message-custom": "Il widget personalizzato della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}",
"message-unknown": "Un widget sconosciuto non è stato inizializzato a causa di:\n\n{{message}}"
}
},
"widget-error": {
"title": "Impossibile inizializzare un widget",
"message-custom": "Il widget personalizzato della nota con ID \"{{id}}\", dal titolo \"{{title}}\" non è stato inizializzato a causa di:\n\n{{message}}",
"message-unknown": "Un widget sconosciuto non è stato inizializzato a causa di:\n\n{{message}}"
"add_link": {
"add_link": "Aggiungi un collegamento",
"note": "Nota",
"search_note": "cerca una nota per nome",
"link_title_mirrors": "il titolo del collegamento rispecchia il titolo della nota corrente",
"link_title_arbitrary": "il titolo del collegamento può essere modificato arbitrariamente",
"link_title": "Titolo del collegamento",
"button_add_link": "Aggiungi il collegamento <kbd>invio</kbd>",
"help_on_links": "Aiuto sui collegamenti"
},
"branch_prefix": {
"edit_branch_prefix": "Modifica il prefisso del ramo",
"help_on_tree_prefix": "Aiuto sui prefissi dell'Albero",
"prefix": "Prefisso: ",
"save": "Salva",
"branch_prefix_saved": "Il prefisso del ramo è stato salvato."
},
"bulk_actions": {
"bulk_actions": "Azioni massive",
"affected_notes": "Note influenzate",
"include_descendants": "Includi i discendenti della nota selezionata",
"available_actions": "Azioni disponibili",
"chosen_actions": "Azioni scelte",
"execute_bulk_actions": "Esegui le azioni massive",
"bulk_actions_executed": "Le azioni massive sono state eseguite con successo.",
"none_yet": "Ancora nessuna... aggiungi una azione cliccando su una di quelle disponibili sopra.",
"labels": "Etichette",
"relations": "Relazioni",
"notes": "Note",
"other": "Altro"
},
"clone_to": {
"clone_notes_to": "Clona note in...",
"help_on_links": "Aiuto sui collegamenti",
"notes_to_clone": "Note da clonare",
"target_parent_note": "Nodo padre obiettivo",
"search_for_note_by_its_name": "cerca una nota per nome",
"cloned_note_prefix_title": "Le note clonate saranno mostrate nell'albero delle note con il dato prefisso",
"prefix_optional": "Prefisso (opzionale)",
"clone_to_selected_note": "Clona sotto la nota selezionata <kbd>invio</kbd>",
"no_path_to_clone_to": "Nessun percorso per clonare dentro.",
"note_cloned": "La nota \"{{clonedTitle}}\" è stata clonata in \"{{targetTitle}}\""
},
"confirm": {
"cancel": "Annulla",
"ok": "OK",
"confirmation": "Conferma",
"are_you_sure_remove_note": "Sei sicuro di voler rimuovere la nota \"{{title}}\" dalla mappa delle relazioni? ",
"if_you_dont_check": "Se non lo selezioni, la nota sarà rimossa solamente dalla mappa delle relazioni.",
"also_delete_note": "Rimuove anche la nota"
},
"delete_notes": {
"ok": "OK",
"close": "Chiudi",
"delete_notes_preview": "Anteprima di eliminazione delle note",
"delete_all_clones_description": "Elimina anche tutti i cloni (può essere disfatto tramite i cambiamenti recenti)",
"erase_notes_description": "L'eliminazione normale (soft) marca le note come eliminate e potranno essere recuperate entro un certo lasso di tempo (dalla finestra dei cambiamenti recenti). Selezionando questa opzione le note si elimineranno immediatamente e non sarà possibile recuperarle.",
"erase_notes_warning": "Elimina le note in modo permanente (non potrà essere disfatto), compresi tutti i cloni. Ciò forzerà un nuovo caricamento dell'applicazione.",
"cancel": "Annulla",
"notes_to_be_deleted": "Le seguenti note saranno eliminate ({{- noteCount}})",
"no_note_to_delete": "Nessuna nota sarà eliminata (solo i cloni).",
"broken_relations_to_be_deleted": "Le seguenti relazioni saranno interrotte ed eliminate ({{- relationCount}})",
"deleted_relation_text": "La nota {{- note}} (da eliminare) è referenziata dalla relazione {{- relation}} originata da {{- source}}."
},
"info": {
"okButton": "OK",
"closeButton": "Chiudi"
},
"export": {
"close": "Chiudi",
"export_note_title": "Esporta la nota",
"export_status": "Stato dell'esportazione",
"export": "Esporta",
"choose_export_type": "Scegli prima il tipo di esportazione, per favore",
"export_in_progress": "Esportazione in corso: {{progressCount}}",
"export_finished_successfully": "Esportazione terminata con successo.",
"format_pdf": "PDF- allo scopo di stampa o esportazione.",
"export_type_subtree": "Questa nota e tutti i suoi discendenti",
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione."
},
"password_not_set": {
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
"body2": "Per proteggere le note, fare clic su <a class=\"open-password-options-button\" href=\"javascript:\">qui</a> per aprire la finestra di dialogo Opzioni e impostare la password."
},
"protected_session_password": {
"close_label": "Chiudi"
},
"abstract_bulk_action": {
"remove_this_search_action": "Rimuovi questa azione di ricerca"
},
"etapi": {
"new_token_title": "Nuovo token ETAPI",
"new_token_message": "Inserire il nuovo nome del token"
},
"electron_integration": {
"zoom-factor": "Fattore di ingrandimento",
"desktop-application": "Applicazione Desktop"
},
"note_autocomplete": {
"search-for": "Cerca \"{{term}}\"",
"create-note": "Crea e collega la nota figlia \"{{term}}\"",
"insert-external-link": "Inserisci il collegamento esterno a \"{{term}}\"",
"clear-text-field": "Pulisci il campo di testo",
"show-recent-notes": "Mostra le note recenti",
"full-text-search": "Ricerca full text"
},
"note_tooltip": {
"note-has-been-deleted": "La nota è stata eliminata.",
"quick-edit": "Modifica veloce"
},
"geo-map": {
"create-child-note-title": "Crea una nota figlia e aggiungila alla mappa",
"create-child-note-instruction": "Clicca sulla mappa per creare una nuova nota qui o premi Escape per uscire.",
"unable-to-load-map": "Impossibile caricare la mappa."
},
"geo-map-context": {
"open-location": "Apri la posizione",
"remove-from-map": "Rimuovi dalla mappa",
"add-note": "Aggiungi un marcatore in questa posizione"
},
"debug": {
"debug": "Debug"
},
"database_anonymization": {
"light_anonymization": "Anonimizzazione parziale",
"title": "Anonimizzazione del Database",
"full_anonymization": "Anonimizzazione completa",
"full_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà (rimuove tutti i contenuti delle note, lasciando solo la struttura e qualche metadato non sensibile) per condividerlo online allo scopo di debugging, senza paura di far trapelare i tuoi dati personali.",
"save_fully_anonymized_database": "Salva il database completamente anonimizzato",
"light_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà in parzialmente — in particolare, solo il contenuto delle note sarà rimosso, ma i titoli e gli attributi rimarranno. Inoltre, note con script personalizzati JS di frontend/backend e widget personalizzati lasciando rimarranno. Ciò mette a disposizione più contesto per il debug dei problemi.",
"choose_anonymization": "Puoi decidere da solo se fornire un database completamente o parzialmente anonimizzato. Anche un database completamente anonimizzato è molto utile, sebbene in alcuni casi i database parzialmente anonimizzati possono accelerare il processo di identificazione dei bug e la loro correzione.",
"no_anonymized_database_yet": "Nessun database ancora anonimizzato.",
"save_lightly_anonymized_database": "Salva il database parzialmente anonimizzato",
"successfully_created_fully_anonymized_database": "Database completamente anonimizzato creato in {{anonymizedFilePath}}",
"successfully_created_lightly_anonymized_database": "Database parzialmente anonimizzato creato in {{anonymizedFilePath}}"
},
"cpu_arch_warning": {
"title": "Per favore scarica la versione ARM64",
"continue_anyway": "Continua Comunque",
"dont_show_again": "Non mostrare più questo avviso",
"download_link": "Scarica la Versione Nativa"
},
"editorfeatures": {
"title": "Caratteristiche",
"emoji_completion_enabled": "Abilita il completamento automatico delle Emoji",
"note_completion_enabled": "Abilita il completamento automatico delle note"
},
"table_view": {
"new-row": "Nuova riga",
"new-column": "Nuova colonna",
"sort-column-by": "Ordina per \"{{title}}\"",
"sort-column-ascending": "Ascendente",
"sort-column-descending": "Discendente",
"sort-column-clear": "Cancella l'ordinamento",
"hide-column": "Nascondi la colonna \"{{title}}\"",
"show-hide-columns": "Mostra/nascondi le colonne",
"row-insert-above": "Inserisci una riga sopra",
"row-insert-below": "Inserisci una riga sotto"
},
"abstract_search_option": {
"remove_this_search_option": "Rimuovi questa opzione di ricerca",
"failed_rendering": "Opzione di ricerca di rendering non riuscita: {{dto}} con errore: {{error}} {{stack}}"
},
"ancestor": {
"label": "Antenato"
},
"add_label": {
"add_label": "Aggiungi etichetta",
"label_name_placeholder": "nome dell'etichetta",
"new_value_placeholder": "nuovo valore",
"to_value": "al valore"
},
"update_label_value": {
"to_value": "al valore",
"label_name_placeholder": "nome dell'etichetta"
},
"delete_label": {
"delete_label": "Elimina etichetta",
"label_name_placeholder": "nome dell'etichetta",
"label_name_title": "Sono ammessi i caratteri alfanumerici, il carattere di sottolineato e i due punti."
},
"tree-context-menu": {
"move-to": "Muovi in...",
"cut": "Taglia"
},
"electron_context_menu": {
"cut": "Taglia",
"copy": "Copia",
"paste": "Incolla",
"copy-link": "Copia collegamento",
"paste-as-plain-text": "Incolla come testo semplice"
},
"editing": {
"editor_type": {
"multiline-toolbar": "Mostra la barra degli strumenti su più linee se non entra."
}
},
"edit_button": {
"edit_this_note": "Modifica questa nota"
},
"shortcuts": {
"shortcuts": "Scorciatoie"
},
"shared_switch": {
"toggle-on-title": "Condividi la nota",
"toggle-off-title": "Non condividere la nota"
},
"search_string": {
"search_prefix": "Cerca:"
},
"attachment_detail": {
"open_help_page": "Apri la pagina di aiuto sugli allegati"
},
"search_definition": {
"ancestor": "antenato",
"debug": "debug",
"action": "azione",
"add_search_option": "Aggiungi un opzione di ricerca:",
"search_string": "cerca la stringa",
"limit": "limite"
},
"modal": {
"close": "Chiudi"
},
"board_view": {
"insert-below": "Inserisci sotto",
"delete-column": "Elimina la colonna",
"delete-column-confirmation": "Sei sicuro di vole eliminare questa colonna? Il corrispondente attributo sarà eliminato anche nelle note sotto questa colonna."
},
"backup": {
"enable_weekly_backup": "Abilita le archiviazioni settimanali",
"enable_monthly_backup": "Abilita le archiviazioni mensili",
"backup_recommendation": "Si raccomanda di mantenere attive le archiviazioni, sebbene ciò possa rendere l'avvio dell'applicazione lento con database grandi e/o dispositivi di archiviazione lenti.",
"backup_now": "Archivia adesso",
"backup_database_now": "Archivia il database adesso",
"existing_backups": "Backup esistenti",
"date-and-time": "Data e ora",
"path": "Percorso",
"database_backed_up_to": "Il database è stato archiviato in {{backupFilePath}}",
"enable_daily_backup": "Abilita le archiviazioni giornaliere",
"no_backup_yet": "Ancora nessuna archiviazione"
},
"backend_log": {
"refresh": "Aggiorna"
},
"consistency_checks": {
"find_and_fix_button": "Trova e correggi i problemi di coerenza",
"finding_and_fixing_message": "In cerca e correzione dei problemi di coerenza...",
"issues_fixed_message": "Qualsiasi problema di coerenza che possa essere stato trovato ora è corretto."
},
"database_integrity_check": {
"check_button": "Controllo dell'integrità del database",
"checking_integrity": "Controllo dell'integrità del database in corso...",
"title": "Controllo di Integrità del database",
"description": "Controllerà che il database non sia corrotto a livello SQLite. Può durare un po' di tempo, a seconda della grandezza del DB.",
"integrity_check_failed": "Controllo di integrità fallito: {{results}}"
},
"sync": {
"title": "Sincronizza",
"force_full_sync_button": "Forza una sincronizzazione completa",
"failed": "Sincronizzazione fallita: {{message}}"
},
"sync_2": {
"config_title": "Configurazione per la Sincronizzazione",
"proxy_label": "Server Proxy per la sincronizzazione (opzionale)",
"test_title": "Test di sincronizzazione",
"timeout": "Timeout per la sincronizzazione",
"timeout_unit": "millisecondi",
"save": "Salva",
"help": "Aiuto"
},
"search_engine": {
"save_button": "Salva"
},
"sql_table_schemas": {
"tables": "Tabelle"
},
"tab_row": {
"close_tab": "Chiudi la scheda",
"add_new_tab": "Aggiungi una nuova scheda",
"close": "Chiudi",
"close_other_tabs": "Chiudi le altre schede",
"close_right_tabs": "Chiudi le schede a destra",
"close_all_tabs": "Chiudi tutte le schede",
"reopen_last_tab": "Riapri l'ultima scheda chiusa",
"move_tab_to_new_window": "Sposta questa scheda in una nuova finestra",
"copy_tab_to_new_window": "Copia questa scheda in una nuova finestra",
"new_tab": "Nuova scheda"
},
"toc": {
"table_of_contents": "Sommario"
},
"table_of_contents": {
"title": "Sommario"
},
"tray": {
"title": "Vassoio di Sistema",
"enable_tray": "Abilita il vassoio (Trilium necessita di essere riavviato affinché la modifica abbia effetto)"
},
"heading_style": {
"title": "Stile dell'Intestazione",
"plain": "Normale",
"underline": "Sottolineato",
"markdown": "Stile Markdown"
},
"highlights_list": {
"title": "Punti salienti"
},
"highlights_list_2": {
"title": "Punti salienti",
"options": "Opzioni"
},
"quick-search": {
"placeholder": "Ricerca rapida",
"searching": "Ricerca in corso..."
}
},
"add_link": {
"add_link": "Aggiungi un collegamento",
"note": "Nota",
"search_note": "cerca una nota per nome",
"link_title_mirrors": "il titolo del collegamento rispecchia il titolo della nota corrente",
"link_title_arbitrary": "il titolo del collegamento può essere modificato arbitrariamente",
"link_title": "Titolo del collegamento",
"button_add_link": "Aggiungi il collegamento <kbd>invio</kbd>",
"help_on_links": "Aiuto sui collegamenti"
},
"branch_prefix": {
"edit_branch_prefix": "Modifica il prefisso del ramo",
"help_on_tree_prefix": "Aiuto sui prefissi dell'Albero",
"prefix": "Prefisso: ",
"save": "Salva",
"branch_prefix_saved": "Il prefisso del ramo è stato salvato."
},
"bulk_actions": {
"bulk_actions": "Azioni massive",
"affected_notes": "Note influenzate",
"include_descendants": "Includi i discendenti della nota selezionata",
"available_actions": "Azioni disponibili",
"chosen_actions": "Azioni scelte",
"execute_bulk_actions": "Esegui le azioni massive",
"bulk_actions_executed": "Le azioni massive sono state eseguite con successo.",
"none_yet": "Ancora nessuna... aggiungi una azione cliccando su una di quelle disponibili sopra.",
"labels": "Etichette",
"relations": "Relazioni",
"notes": "Note",
"other": "Altro"
},
"clone_to": {
"clone_notes_to": "Clona note in...",
"help_on_links": "Aiuto sui collegamenti",
"notes_to_clone": "Note da clonare",
"target_parent_note": "Nodo padre obiettivo",
"search_for_note_by_its_name": "cerca una nota per nome",
"cloned_note_prefix_title": "Le note clonate saranno mostrate nell'albero delle note con il dato prefisso",
"prefix_optional": "Prefisso (opzionale)",
"clone_to_selected_note": "Clona verso la nota selezionata <kbd>invio</kbd>",
"no_path_to_clone_to": "Nessun percorso per clonare dentro.",
"note_cloned": "La nota \"{{clonedTitle}}\" è stata clonata in \"{{targetTitle}}\""
},
"confirm": {
"cancel": "Annulla",
"ok": "OK",
"confirmation": "Conferma",
"are_you_sure_remove_note": "Sei sicuro di voler rimuovere la nota \"{{title}}\" dalla mappa delle relazioni? ",
"if_you_dont_check": "Se non lo selezioni, la nota sarà rimossa solamente dalla mappa delle relazioni.",
"also_delete_note": "Rimuove anche la nota"
},
"delete_notes": {
"ok": "OK",
"close": "Chiudi",
"delete_notes_preview": "Anteprima di eliminazione delle note",
"delete_all_clones_description": "Elimina anche tutti i cloni (può essere ripristinato nella sezione cambiamenti recenti)",
"erase_notes_description": "L'eliminazione normale (soft) marca le note come eliminate e potranno essere recuperate entro un certo lasso di tempo (dalla finestra dei cambiamenti recenti). Selezionando questa opzione le note si elimineranno immediatamente e non sarà possibile recuperarle.",
"erase_notes_warning": "Elimina le note in modo permanente (non potrà essere disfatto), compresi tutti i cloni. Ciò forzerà un nuovo caricamento dell'applicazione.",
"cancel": "Annulla",
"notes_to_be_deleted": "Le seguenti note saranno eliminate ({{- noteCount}})",
"no_note_to_delete": "Nessuna nota sarà eliminata (solo i cloni).",
"broken_relations_to_be_deleted": "Le seguenti relazioni saranno interrotte ed eliminate ({{- relationCount}})",
"deleted_relation_text": "La nota {{- note}} (da eliminare) è referenziata dalla relazione {{- relation}} originata da {{- source}}."
},
"info": {
"okButton": "OK",
"closeButton": "Chiudi"
},
"export": {
"close": "Chiudi",
"export_note_title": "Esporta la nota",
"export_status": "Stato dell'esportazione",
"export": "Esporta",
"choose_export_type": "Scegli prima il tipo di esportazione, per favore",
"export_in_progress": "Esportazione in corso: {{progressCount}}",
"export_finished_successfully": "Esportazione terminata con successo.",
"format_pdf": "PDF- allo scopo di stampa o esportazione.",
"export_type_subtree": "Questa nota e tutti i suoi discendenti",
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione.",
"export_type_single": "Solo questa nota, senza le sottostanti",
"format_opml": "OPML - formato per scambio informazioni outline. Formattazione, immagini e files non sono inclusi.",
"opml_version_1": "OPML v.1.0 - solo testo semplice",
"opml_version_2": "OPML v2.0 - supporta anche HTML"
},
"password_not_set": {
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
"body2": "Per proteggere le note, fare clic su <a class=\"open-password-options-button\" href=\"javascript:\">qui</a> per aprire la finestra di dialogo Opzioni e impostare la password."
},
"protected_session_password": {
"close_label": "Chiudi"
},
"abstract_bulk_action": {
"remove_this_search_action": "Rimuovi questa azione di ricerca"
},
"etapi": {
"new_token_title": "Nuovo token ETAPI",
"new_token_message": "Inserire il nuovo nome del token"
},
"electron_integration": {
"zoom-factor": "Fattore di ingrandimento",
"desktop-application": "Applicazione Desktop"
},
"note_autocomplete": {
"search-for": "Cerca \"{{term}}\"",
"create-note": "Crea e collega la nota figlia \"{{term}}\"",
"insert-external-link": "Inserisci il collegamento esterno a \"{{term}}\"",
"clear-text-field": "Pulisci il campo di testo",
"show-recent-notes": "Mostra le note recenti",
"full-text-search": "Ricerca full text"
},
"note_tooltip": {
"note-has-been-deleted": "La nota è stata eliminata.",
"quick-edit": "Modifica veloce"
},
"geo-map": {
"create-child-note-title": "Crea una nota figlia e aggiungila alla mappa",
"create-child-note-instruction": "Clicca sulla mappa per creare una nuova nota qui o premi Escape per uscire.",
"unable-to-load-map": "Impossibile caricare la mappa."
},
"geo-map-context": {
"open-location": "Apri la posizione",
"remove-from-map": "Rimuovi dalla mappa",
"add-note": "Aggiungi un marcatore in questa posizione"
},
"debug": {
"debug": "Debug"
},
"database_anonymization": {
"light_anonymization": "Anonimizzazione parziale",
"title": "Anonimizzazione del Database",
"full_anonymization": "Anonimizzazione completa",
"full_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà (rimuove tutti i contenuti delle note, lasciando solo la struttura e qualche metadato non sensibile) per condividerlo online allo scopo di debugging, senza paura di far trapelare i tuoi dati personali.",
"save_fully_anonymized_database": "Salva il database completamente anonimizzato",
"light_anonymization_description": "Questa azione creerà una nuova copia del database e lo anonimizzerà in parzialmente — in particolare, solo il contenuto delle note sarà rimosso, ma i titoli e gli attributi rimarranno. Inoltre, note con script personalizzati JS di frontend/backend e widget personalizzati lasciando rimarranno. Ciò mette a disposizione più contesto per il debug dei problemi.",
"choose_anonymization": "Puoi decidere da solo se fornire un database completamente o parzialmente anonimizzato. Anche un database completamente anonimizzato è molto utile, sebbene in alcuni casi i database parzialmente anonimizzati possono accelerare il processo di identificazione dei bug e la loro correzione.",
"no_anonymized_database_yet": "Nessun database ancora anonimizzato.",
"save_lightly_anonymized_database": "Salva il database parzialmente anonimizzato",
"successfully_created_fully_anonymized_database": "Database completamente anonimizzato creato in {{anonymizedFilePath}}",
"successfully_created_lightly_anonymized_database": "Database parzialmente anonimizzato creato in {{anonymizedFilePath}}"
},
"cpu_arch_warning": {
"title": "Per favore scarica la versione ARM64",
"continue_anyway": "Continua Comunque",
"dont_show_again": "Non mostrare più questo avviso",
"download_link": "Scarica la Versione Nativa"
},
"editorfeatures": {
"title": "Caratteristiche",
"emoji_completion_enabled": "Abilita il completamento automatico delle Emoji",
"note_completion_enabled": "Abilita il completamento automatico delle note"
},
"table_view": {
"new-row": "Nuova riga",
"new-column": "Nuova colonna",
"sort-column-by": "Ordina per \"{{title}}\"",
"sort-column-ascending": "Ascendente",
"sort-column-descending": "Discendente",
"sort-column-clear": "Cancella l'ordinamento",
"hide-column": "Nascondi la colonna \"{{title}}\"",
"show-hide-columns": "Mostra/nascondi le colonne",
"row-insert-above": "Inserisci una riga sopra",
"row-insert-below": "Inserisci una riga sotto"
},
"abstract_search_option": {
"remove_this_search_option": "Rimuovi questa opzione di ricerca",
"failed_rendering": "Opzione di ricerca di rendering non riuscita: {{dto}} con errore: {{error}} {{stack}}"
},
"ancestor": {
"label": "Antenato"
},
"add_label": {
"add_label": "Aggiungi etichetta",
"label_name_placeholder": "nome dell'etichetta",
"new_value_placeholder": "nuovo valore",
"to_value": "al valore"
},
"update_label_value": {
"to_value": "al valore",
"label_name_placeholder": "nome dell'etichetta"
},
"delete_label": {
"delete_label": "Elimina etichetta",
"label_name_placeholder": "nome dell'etichetta",
"label_name_title": "Sono ammessi i caratteri alfanumerici, il carattere di sottolineato e i due punti."
},
"tree-context-menu": {
"move-to": "Muovi in...",
"cut": "Taglia"
},
"electron_context_menu": {
"cut": "Taglia",
"copy": "Copia",
"paste": "Incolla",
"copy-link": "Copia collegamento",
"paste-as-plain-text": "Incolla come testo semplice"
},
"editing": {
"editor_type": {
"multiline-toolbar": "Mostra la barra degli strumenti su più linee se non entra."
}
},
"edit_button": {
"edit_this_note": "Modifica questa nota"
},
"shortcuts": {
"shortcuts": "Scorciatoie"
},
"shared_switch": {
"toggle-on-title": "Condividi la nota",
"toggle-off-title": "Non condividere la nota"
},
"search_string": {
"search_prefix": "Cerca:"
},
"attachment_detail": {
"open_help_page": "Apri la pagina di aiuto sugli allegati"
},
"search_definition": {
"ancestor": "antenato",
"debug": "debug",
"action": "azione",
"add_search_option": "Aggiungi un opzione di ricerca:",
"search_string": "cerca la stringa",
"limit": "limite"
},
"modal": {
"close": "Chiudi"
},
"board_view": {
"insert-below": "Inserisci sotto",
"delete-column": "Elimina la colonna",
"delete-column-confirmation": "Sei sicuro di vole eliminare questa colonna? Il corrispondente attributo sarà eliminato anche nelle note sotto questa colonna."
},
"backup": {
"enable_weekly_backup": "Abilita le archiviazioni settimanali",
"enable_monthly_backup": "Abilita le archiviazioni mensili",
"backup_recommendation": "Si raccomanda di mantenere attive le archiviazioni, sebbene ciò possa rendere l'avvio dell'applicazione lento con database grandi e/o dispositivi di archiviazione lenti.",
"backup_now": "Archivia adesso",
"backup_database_now": "Archivia il database adesso",
"existing_backups": "Backup esistenti",
"date-and-time": "Data e ora",
"path": "Percorso",
"database_backed_up_to": "Il database è stato archiviato in {{backupFilePath}}",
"enable_daily_backup": "Abilita le archiviazioni giornaliere",
"no_backup_yet": "Ancora nessuna archiviazione"
},
"backend_log": {
"refresh": "Aggiorna"
},
"consistency_checks": {
"find_and_fix_button": "Trova e correggi i problemi di coerenza",
"finding_and_fixing_message": "In cerca e correzione dei problemi di coerenza...",
"issues_fixed_message": "Qualsiasi problema di coerenza che possa essere stato trovato ora è corretto."
},
"database_integrity_check": {
"check_button": "Controllo dell'integrità del database",
"checking_integrity": "Controllo dell'integrità del database in corso...",
"title": "Controllo di Integrità del database",
"description": "Controllerà che il database non sia corrotto a livello SQLite. Può durare un po' di tempo, a seconda della grandezza del DB.",
"integrity_check_failed": "Controllo di integrità fallito: {{results}}"
},
"sync": {
"title": "Sincronizza",
"force_full_sync_button": "Forza una sincronizzazione completa",
"failed": "Sincronizzazione fallita: {{message}}"
},
"sync_2": {
"config_title": "Configurazione per la Sincronizzazione",
"proxy_label": "Server Proxy per la sincronizzazione (opzionale)",
"test_title": "Test di sincronizzazione",
"timeout": "Timeout per la sincronizzazione",
"timeout_unit": "millisecondi",
"save": "Salva",
"help": "Aiuto"
},
"search_engine": {
"save_button": "Salva"
},
"sql_table_schemas": {
"tables": "Tabelle"
},
"tab_row": {
"close_tab": "Chiudi la scheda",
"add_new_tab": "Aggiungi una nuova scheda",
"close": "Chiudi",
"close_other_tabs": "Chiudi le altre schede",
"close_right_tabs": "Chiudi le schede a destra",
"close_all_tabs": "Chiudi tutte le schede",
"reopen_last_tab": "Riapri l'ultima scheda chiusa",
"move_tab_to_new_window": "Sposta questa scheda in una nuova finestra",
"copy_tab_to_new_window": "Copia questa scheda in una nuova finestra",
"new_tab": "Nuova scheda"
},
"toc": {
"table_of_contents": "Sommario"
},
"table_of_contents": {
"title": "Sommario"
},
"tray": {
"title": "Vassoio di Sistema",
"enable_tray": "Abilita il vassoio (Trilium necessita di essere riavviato affinché la modifica abbia effetto)"
},
"heading_style": {
"title": "Stile dell'Intestazione",
"plain": "Normale",
"underline": "Sottolineato",
"markdown": "Stile Markdown"
},
"highlights_list": {
"title": "Punti salienti"
},
"highlights_list_2": {
"title": "Punti salienti",
"options": "Opzioni"
},
"quick-search": {
"placeholder": "Ricerca rapida",
"searching": "Ricerca in corso..."
},
"help": {
"goUpDown": "su/giù nella lista delle note",
"collapseExpand": "collassa/espande il nodo",
"notSet": "non impostato",
"goBackForwards": "indietro/avanti nella cronologia",
"showJumpToNoteDialog": "mostra <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">la finestra di dialogo \"Salta alla nota\"<a>"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,37 +0,0 @@
{
"about": {
"title": "Trilium Notes에 대해서",
"homepage": "홈페이지:",
"app_version": "앱 버전:",
"db_version": "DB 버전:",
"sync_version": "동기화 버전:",
"build_date": "빌드 날짜:",
"build_revision": "빌드 리비전:",
"data_directory": "데이터 경로:"
},
"toast": {
"critical-error": {
"title": "심각한 오류",
"message": "클라이언트 애플리케이션 시작 도중 심각한 오류가 발생했습니다:\n\n{{message}}\n\n이는 스크립트가 예기치 않게 실패하면서 발생한 것일 수 있습니다. 애플리케이션을 안전 모드로 시작한 뒤 문제를 해결해 보세요."
},
"widget-error": {
"title": "위젯 초기화 실패",
"message-custom": "ID가 \"{{id}}\"고 ,제목이 \"{{title}}\" 인 노트에서 사용자 지정 위젯을 초기화 하는데 실패했습니다:\n\n{{message}}",
"message-unknown": "알 수 없는 위젯이 초기화 하는데 실패했습니다:\n\n{{message}}"
},
"bundle-error": {
"title": "사용자 정의 스크립트를 불러오는데 실패했습니다",
"message": "ID가 \"{{id}}\"고, 제목이 \"{{title}}\"인 노트에서 스크립트가 실행되지 못했습니다:\n\n{{message}}"
}
},
"add_link": {
"add_link": "링크 추가",
"note": "노트",
"search_note": "이름으로 노트 검색하기",
"help_on_links": "링크 관련 도움말",
"link_title_mirrors": "링크 제목은 노트의 현재 제목을 반영합니다"
},
"branch_prefix": {
"save": "저장"
}
}

View File

@@ -1,70 +0,0 @@
{
"about": {
"title": "Over Trilium Notes",
"homepage": "Homepagina:",
"app_version": "App versie:",
"db_version": "DB Versie:",
"sync_version": "Sync Versie:",
"build_date": "Build datum:",
"build_revision": "Build revisie:",
"data_directory": "Gegevensmap:"
},
"toast": {
"critical-error": {
"title": "Kritische Error",
"message": "Een kritieke fout heeft plaatsgevonden waardoor de cliënt zich aanmeldt vanaf het begin:\n\n84X\n\nDit is waarschijnlijk veroorzaakt door een script dat op een onverwachte manier faalt. Probeer de sollicitatie in veilige modus te starten en de kwestie aan te spreken."
}
},
"add_link": {
"add_link": "Voeg link toe",
"help_on_links": "Hulp bij links",
"note": "notitie",
"search_note": "zoek voor notitie op naam",
"link_title_mirrors": "De link titel is hetzelfde als de notitie's huidige titel",
"link_title": "Link titel",
"button_add_link": "Link toevoegen"
},
"branch_prefix": {
"edit_branch_prefix": "Bewerk branch prefix",
"save": "Opslaan",
"branch_prefix_saved": "Branch prefix is opgeslagen.",
"help_on_tree_prefix": "Help bij boomvoorvoegsel",
"prefix": "Voorvoegsel: "
},
"bulk_actions": {
"bulk_actions": "Bulk acties",
"affected_notes": "Getroffen notities",
"available_actions": "Beschikbare acties",
"chosen_actions": "Kies acties",
"execute_bulk_actions": "Bulk acties uitvoeren",
"bulk_actions_executed": "Bulk acties zijn succesvol uitgevoerd.",
"none_yet": "Nog niks... voeg een actie toe door een van de beschikbare bovenstaande opties te klikken.",
"labels": "Labels",
"relations": "Relaties",
"notes": "Notities",
"other": "Andere"
},
"calendar": {
"april": "April",
"may": "Mei",
"june": "Juni",
"july": "Juli",
"august": "Augustus",
"september": "September",
"october": "Oktober",
"november": "November",
"december": "December"
},
"close_pane_button": {
"close_this_pane": "Sluit dit paneel"
},
"create_pane_button": {
"create_new_split": "Maak nieuwe split"
},
"edit_button": {
"edit_this_note": "Notitie bewerken"
},
"show_toc_widget_button": {
"show_toc": "Laat Inhoudsopgave zien"
}
}

View File

@@ -1,634 +0,0 @@
{
"about": {
"title": "O notatkach Trilium",
"homepage": "Strona główna:",
"app_version": "Wersja aplikacji:",
"db_version": "Wersja bazy danych:",
"sync_version": "Wersja synchronizacji:",
"build_date": "Zbudowano:",
"build_revision": "Rewizja zbudowania:",
"data_directory": "Katalog z danymi:"
},
"toast": {
"critical-error": {
"title": "Błąd krytyczny",
"message": "Wystąpił krytyczny błąd uniemożliwiający uruchomienie aplikacji:\n\n{{message}}\n\nJest to spowodowane najprawdopodobniej niespodziewanym błędem skryptu. Spróbuj uruchomić aplikację ponownie w trybie bezpiecznym i zaadresuj problem."
},
"widget-error": {
"title": "Nie udało się zainicjować widżetu",
"message-custom": "Niestandardowy widżet z notatki o identyfikatorze \"{{id}}\", i tytule \"{{title}}\" nie mógł zostać zainicjowany z powodu:\n\n{{message}}",
"message-unknown": "Nieznany widżet nie mógł być zainicjowany z powodu:\n\n{{message}}"
},
"bundle-error": {
"title": "Nie udało się załadować niestandardowego skryptu",
"message": "Skrypt z notatki o identyfikatorze \"{{id}}\", tytule \"{{title}}: nie został uruchomiony z powodu:\n\n{{message}}"
}
},
"add_link": {
"add_link": "Dodaj link",
"note": "Notatka",
"search_note": "Wyszukaj notatkę po nazwie",
"link_title_arbitrary": "Tytuł linku można dowolnie zmieniać",
"link_title": "Tytuł linku",
"button_add_link": "Dodaj link",
"help_on_links": "Pomoc dotycząca linków",
"link_title_mirrors": "tytuł linku odzwierciedla tytuł obecnej notatki"
},
"branch_prefix": {
"save": "Zapisz",
"edit_branch_prefix": "Edytuj prefiks gałęzi",
"prefix": "Prefiks: ",
"branch_prefix_saved": "Zapisano prefiks gałęzi.",
"help_on_tree_prefix": "Pomoc dotycząca prefiksu drzewa"
},
"bulk_actions": {
"labels": "Etykiety",
"notes": "Notatki",
"other": "Inne",
"relations": "Powiązania",
"bulk_actions": "Działania zbiorcze",
"include_descendants": "Uwzględnia rozwinięcia wybranych notatek",
"available_actions": "Dostępne działania",
"chosen_actions": "Wybrane działania",
"execute_bulk_actions": "Wykonaj zbiór działań",
"bulk_actions_executed": "Zbiór działań został wykonany prawidłowo.",
"none_yet": "Brak zaznaczonych działań... dodaj działanie poprzez kliknięcie jednej z dostępnych opcji powyżej.",
"affected_notes": "Dotyczy notatek"
},
"confirm": {
"ok": "OK",
"cancel": "Anuluj",
"confirmation": "Potwierdzenie",
"are_you_sure_remove_note": "Czy napewno chcesz usunąć notatkę \"{{title}}\" z mapy powiązań? ",
"if_you_dont_check": "Jeśli nie zaznaczysz tej opcji, notatka zostanie usunięta jedynie z mapy powiązań.",
"also_delete_note": "Usuń dodatkowo notatkę"
},
"delete_notes": {
"cancel": "Anuluj",
"close": "Zamknij",
"delete_notes_preview": "Usuń podgląd notatek",
"delete_all_clones_description": "Usuń również wszystkie sklonowania (działanie może zostać cofnięte w ostatnich zmianach)",
"erase_notes_description": "Normalne (miękkie) usuwanie zaznacza jedynie notatki jako usunięte i można je przywrócić (w oknie dialogowym ostatnich zmian) przez wyznaczony okres czasu. Zaznaczenie tej opcji spowoduje natychmiastowe usunięcie notatek, bez możliwości ich przywrócenia.",
"erase_notes_warning": "Usuń notatki permanentnie (bez opcji ich przywrócenia), włączając wszystkie kopie. Działanie to wymaga ponownego uruchomienia aplikacji.",
"notes_to_be_deleted": "Następujące notatki zostaną usunięte ({{notesCount}})",
"no_note_to_delete": "Żadne notatki nie zostaną usunięte (jedynie kopie).",
"broken_relations_to_be_deleted": "Następujące powiązania zostaną uszkodzone i usunięte ({{ relationCount}})",
"ok": "OK",
"deleted_relation_text": "Notatka {{- note}} (do usunięcia) jest powiązana przez relację {{- relation}} pochodzącą z {{- source}}."
},
"export": {
"close": "Zamknij",
"export_note_title": "Eksportuj notatkę",
"export_type_subtree": "Ta notatka oraz wszystkie podrzędne",
"format_html": "HTML - rekomendowany jako zachowujący całość formatowania",
"format_html_zip": "HTML w archiwum ZIP - rekomendowany jako zachowujący całość formatowania.",
"format_markdown": "Markdown - zachowuje większość formatowania.",
"format_opml": "OPML - format wymiany danych dla outlinerów zawierający tylko tekst. Formatowanie, obrazy i pliki nie są uwzględnione.",
"opml_version_1": "OPML v1.0 - tylko zwykły tekst",
"opml_version_2": "OPML v2.0 - umożliwia również HTML",
"export_type_single": "Tylko ta notatka, bez elementów podrzędnych",
"export": "Eksportuj",
"choose_export_type": "Wybierz najpierw rodzaj pliku do eksportu",
"export_status": "Status eksportu",
"export_in_progress": "Postęp eksportowania: {{progressCount}}",
"export_finished_successfully": "Eksportowanie zakończone.",
"format_pdf": "PDF - w celu drukowania lub udostępniania."
},
"clone_to": {
"clone_notes_to": "Sklonuj notatki do...",
"notes_to_clone": "Notatki do sklonowania",
"search_for_note_by_its_name": "Wyszukaj notatkę po jej nazwie",
"cloned_note_prefix_title": "Sklonowana notatka zostanie wyświetlona w drzewie notatki z podanym prefiksem",
"prefix_optional": "Prefiks (opcjonalne)",
"clone_to_selected_note": "Sklonuj do wybranej notatki",
"no_path_to_clone_to": "Brak ścieżki do sklonowania.",
"note_cloned": "Notatka \"{{clonedTitle}}\" została sklonowana do \"{{targetTitle}}\"",
"help_on_links": "Pomoc dotycząca linków",
"target_parent_note": "Docelowa główna notatka"
},
"help": {
"title": "Ściągawka",
"noteNavigation": "Nawigacja po notatkach",
"goUpDown": "przewijanie w górę/w dół w liście notatek",
"collapseExpand": "zwiń/rozwiń zbiór",
"notSet": "niezdefiniowany",
"goBackForwards": "przewijaj do tyłu/do przodu w historii",
"showJumpToNoteDialog": "pokaż <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"przejdź do dialogu</a>",
"scrollToActiveNote": "przewiń do aktywnej notatki",
"jumpToParentNote": "przejdź do głównej notatki",
"collapseWholeTree": "zwiń całe drzewko notatki",
"collapseSubTree": "zwiń gałąź notatki",
"tabShortcuts": "Skóry kart",
"newTabNoteLink": "link notatki otwiera notatkę w nowej karcie",
"newTabWithActivationNoteLink": "link notatki otwiera i aktywuje notatkę w nowej karcie",
"onlyInDesktop": "Tylko na komputerze stacjonarnym (wersja Electron)",
"openEmptyTab": "Otwórz pustą kartę",
"closeActiveTab": "zamknij aktywną kartę",
"activateNextTab": "aktywuj następną kartę",
"activatePreviousTab": "aktywuj poprzednią kartę",
"creatingNotes": "Tworzenie notatek",
"createNoteAfter": "Utwórz nową notatkę obok obecnie aktywnej",
"createNoteInto": "Utwórz nową podnotatkę w obecnie otwartej",
"editBranchPrefix": "edytuj <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> aktywnej kopii notatki",
"movingCloningNotes": "Przenoszenie / kopiowanie notatek",
"moveNoteUpDown": "Przenieś notatkę w górę/w dół na liście notatek",
"moveNoteUpHierarchy": "Przenieś notatkę w górę w hierarchii",
"multiSelectNote": "Zaznacz wiele notatek powyżej/poniżej",
"selectAllNotes": "Wybierz wszystkie notatki na obecnym poziomie",
"selectNote": "Wybierz notatkę",
"copyNotes": "skopiuj obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">klonowania</a>)",
"cutNotes": "przytnij obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla przenoszenia notatek)",
"pasteNotes": "wklej notatkę jako podnotatka w obecnej notatce (rozumiane jako przenieś lub skopiuj, w zależności czy notatka była skopiowana czy wycięta)",
"deleteNotes": "usuń notatkę / gałąź",
"editingNotes": "Edytowanie notatek",
"other": "Inne",
"editNoteTitle": "W panelu drzewa nastąpi przejście z panelu drzewa do tytułu notatki. Naciśnięcie klawisza Enter w tytule notatki spowoduje przejście do edytora tekstu. <kbd>Ctrl+.</kbd> spowoduje powrót z edytora do panelu drzewa.",
"createEditLink": "stwórz / edytuj zewnętrzny link",
"createInternalLink": "stwórz wewnętrzny link",
"followLink": "kliknij link pod kursorem",
"insertDateTime": "wstaw aktualną datę i godzinę w pozycji kursora",
"markdownAutoformat": "Autoformatowanie w stylu Markdown",
"headings": "<code>##</code>, <code>###</code>, <code>####</code> itd., po których następuje miejsce na nagłówki",
"bulletList": "<code>*</code> lub <code>-</code>, a następnie spacja, aby utworzyć listę",
"jumpToTreePane": "przejdź do panelu drzewa i przewiń do aktywnej notatki",
"numberedList": "<code>1.</code> or <code>1)</code> po którym następuje miejsce na listę numerowaną",
"blockQuote": "zacznij linijkę od <code></code> aby po kliknięciu spacji dodać blok cytatu",
"troubleshooting": "Rozwiązywanie błędów",
"reloadFrontend": "Załaduj ponownie Frontend Trilium",
"showDevTools": "pokaż narzędzia deweloperskie",
"showSQLConsole": "pokaż konsolę SQL",
"quickSearch": "skup się na szybkim wyszukiwaniu",
"inPageSearch": "wyszukiwanie wewnątrz strony"
},
"book_properties": {
"list": "Lista"
},
"board_view": {
"move-to": "Przenieś do",
"insert-above": "Umieść nad",
"insert-below": "Umieść pod",
"delete-column": "Usuń kolumnę",
"delete-column-confirmation": "Czy na pewno chcesz usunąć tę kolumnę? Odpowiedni atrybut zostanie również usunięty w notatkach pod tą kolumną.",
"new-item": "Nowy element",
"new-item-placeholder": "Wpisz tytuł notatki...",
"add-column": "Dodaj kolumnę",
"add-column-placeholder": "Wpisz tytuł kolumny...",
"edit-note-title": "Naciśnij aby edytować tytuł notatki",
"edit-column-title": "Naciśnij aby edytować tytuł kolumny",
"delete-note": "Usuń notatkę...",
"remove-from-board": "Usuń z tablicy",
"archive-note": "Archiwalna notatka",
"unarchive-note": "Usuń notatkę z archiwum"
},
"command_palette": {
"tree-action-name": "Drzewo: {{name}}",
"export_note_title": "Wyeksportuj notatkę",
"export_note_description": "Wyeksportuj aktualną notatkę",
"show_attachments_title": "Pokaż załączniki",
"show_attachments_description": "Zobacz załączniki notatki",
"search_notes_title": "Szukaj notatek",
"search_notes_description": "Otwórz zaawansowane wyszukiwanie",
"search_subtree_title": "Poszukaj w poddrzewie",
"search_subtree_description": "poszukaj wewnątrz poddrzewa",
"search_history_title": "Pokaż historię wyszukiwania",
"search_history_description": "Pokaż poprzednie wyszukiwania",
"configure_launch_bar_title": "Ustaw Launch Bar",
"configure_launch_bar_description": "Otwórz konfigurację Launch Bar, aby dodać lub usunąć elementy."
},
"content_renderer": {
"open_externally": "Otwórz zewnętrznie"
},
"modal": {
"close": "Zamknij",
"help_title": "Pokaż więcej informacji na temat tego ekranu"
},
"call_to_action": {
"next_theme_title": "Spróbuj nowy motyw Trilium",
"next_theme_message": "Obecnie używasz starszego motywu. Czy chcesz wypróbować nowy motyw?",
"next_theme_button": "Spróbuj nowego motywu",
"background_effects_title": "Efekty w tle są już stabilne",
"dismiss": "Odrzuć",
"background_effects_button": "Włącz efekty w tle"
},
"settings": {
"related_settings": "Powiązane ustawienia"
},
"settings_appearance": {
"related_code_blocks": "Schemat kolorów dla bloków kodu w notatkach tekstowych",
"related_code_notes": "Schemat kolorów dla kodu"
},
"units": {
"percentage": "%"
},
"pagination": {
"page_title": "Strony:{{startIndex}}-{{endIndex}}",
"total_notes": "{{count}}notatek"
},
"collections": {
"rendering_error": "Błąd - Nie można pokazać treści."
},
"add_label": {
"add_label": "Dodaj etykietę",
"label_name_placeholder": "Nazwa etykiety",
"label_name_title": "Dozwolone są znaki alfanumeryczne, podkreślenie i dwukropek.",
"to_value": "do wartości",
"new_value_placeholder": "nowa wartość",
"help_text": "We wszystkich dopasowanych notatkach:",
"help_text_item2": "albo zmień wartość istniejącej etykiety"
},
"attribute_detail": {
"delete": "Usuń",
"related_notes_title": "Inne notatki z tą etykietą",
"more_notes": "Więcej notatek",
"label": "Szczegóły etykiety",
"label_definition": "Szczegóły definicji etykiety",
"relation": "Szczegóły powiązania",
"relation_definition": "Szczegóły definicji powiązania",
"disable_versioning": "Wyłącza automatyczne wersjonowanie. Przydatne np. w przypadku dużych, ale nieistotnych notatek np. dużych bibliotek JS używanych do skryptów",
"precision": "Prezycja",
"digits": "znaki",
"inverse_relation_title": "Opcjonalne ustawienie definiujące, do której relacji jest ta relacja przeciwna. Przykład: Główna - podnotatka są relacjami odwrotnymi do siebie.",
"inverse_relation": "Odwrócone powiązanie"
},
"import": {
"importIntoNote": "Importuj do notatki",
"chooseImportFile": "Wybierz plik do zaimportowania",
"importDescription": "Zawartość wybranego pliku(ów) zostanie zaimportowana jako notatka(i) podrzędna(e) do",
"options": "Opcje",
"shrinkImages": "Zmniejsz obrazy",
"safeImport": "Bezpieczny import",
"import-status": "Status importu",
"in-progress": "Import w trakcie: {{progress}}",
"successful": "Importowanie zakończone sukcesem.",
"safeImportTooltip": "Pliki eksportu Trilium <code>.zip</code> mogą zawierać skrypty wykonywalne, które mogą powodować szkodliwe zachowania. Bezpieczny import dezaktywuje automatyczne wykonywanie wszystkich importowanych skryptów. Odznacz opcję „Bezpieczny import” tylko wtedy, gdy importowane archiwum ma zawierać skrypty wykonywalne i masz pełne zaufanie do zawartości importowanego pliku.",
"import": "Import",
"failed": "Błąd importu: {{message}}.",
"html_import_tags": {
"title": "Tagi importu HTML",
"description": "Skonfiguruj, które tagi HTML mają zostać zachowane podczas importowania notatek. Tagi spoza tej listy zostaną usunięte podczas importu. Niektóre tagi (np. „script”) są zawsze usuwane ze względów bezpieczeństwa.",
"placeholder": "Wpisz tagi HTML, jedna na linijkę",
"reset_button": "Zresetuj do domyślnej listy"
}
},
"image_properties": {
"title": "Obraz",
"original_file_name": "Oryginalna nazwa pliku",
"file_type": "Typ pliku",
"file_size": "Rozmiar pliku",
"download": "Pobierz",
"open": "Otwórz",
"copy_reference_to_clipboard": "Kopiuj odniesienie do schowka",
"upload_new_revision": "Wgraj nową wersję",
"upload_success": "Nowa wersja obrazu została wysłana.",
"upload_failed": "Wysyłanie nowej wersji obrazu nie powiodło się: {{message}}"
},
"inherited_attribute_list": {
"title": "Odziedziczone atrybuty",
"no_inherited_attributes": "Brak odziedziczonych atrybutów."
},
"note_info_widget": {
"note_id": "ID notatki",
"created": "Stworzona",
"modified": "Zmodyfikowano",
"type": "Typ",
"note_size": "Rozmiar notatki",
"note_size_info": "Rozmiar notatki pozwala oszacować przybliżoną ilość miejsca potrzebnego na przechowanie jej. Uwzględnia ona jej treść oraz treść jej poprawek.",
"calculate": "oblicz",
"subtree_size": "(rozmiar poddrzewa: {{size}} w {{count}} notatkach)",
"title": "Informacje o notatce"
},
"note_map": {
"open_full": "Pełne rozszerzenie",
"collapse": "Zmniejsz do normalnego rozmiaru",
"title": "Mapa notatki",
"fix-nodes": "Napraw węzły",
"link-distance": "Odległość linku"
},
"note_paths": {
"title": "Ścieżki notatki",
"clone_button": "Sklonuj notatkę do nowej lokalizacji...",
"intro_placed": "Ta notatka jest umieszczona w następujących lokalizacjach:",
"intro_not_placed": "Ta notatka nie została jeszcze umieszczona w drzewie.",
"outside_hoisted": "Ta ścieżka znajduje się poza podniesioną notatką i trzeba ją odwiesić.",
"archived": "Zarchiwizowane",
"search": "Szukaj"
},
"note_properties": {
"this_note_was_originally_taken_from": "Ta notatka oryginalnie została wzięta z:",
"info": "Info"
},
"owned_attribute_list": {
"owned_attributes": "Posiadane atrybuty"
},
"promoted_attributes": {
"promoted_attributes": "Promowane atrybuty",
"unset-field-placeholder": "nie ustawione",
"url_placeholder": "http://strona...",
"open_external_link": "Otwórz link zewnętrzny",
"unknown_label_type": "Nieznany typ etykiety \"{{type}}\"",
"unknown_attribute_type": "Nieznany typ atrybutu \"{{type}}\"",
"add_new_attribute": "Dodaj nowy atrybut",
"remove_this_attribute": "Usuń ten atrybut",
"remove_color": "Usuń ten kolor etykiety"
},
"script_executor": {
"query": "Zapytanie",
"script": "Skrypt",
"execute_query": "Wykonaj zapytanie",
"execute_script": "Wykonaj skrypt"
},
"search_definition": {
"add_search_option": "Dodaj opcje wyszukiwania:",
"search_string": "ciąg wyszukiwania",
"search_script": "skrypt wyszukiwania",
"ancestor": "przodek",
"fast_search": "szybkie wyszukiwanie",
"fast_search_description": "Opcja szybkiego wyszukiwania wyłącza pełno tekstowe przeszukiwanie zawartości notatek, co może przyspieszyć przeszukiwanie dużych baz danych.",
"include_archived": "dodaj zarchiwizowane",
"include_archived_notes_description": "Domyślnie zarchiwizowane notatki są wyłączone z wyszukiwania, z tą opcją zostaną dodane do wyszukiwania.",
"order_by": "sortuj",
"limit": "limituj",
"limit_description": "Limituj liczbę wyników",
"save_to_note": "Zapisz do notatki",
"search_parameters": "Parametry wyszukiwania",
"unknown_search_option": "Nieznana opcja wyszukiwania {{searchOptionName}}",
"search_note_saved": "Wyszukiwana notatka została zapisana do {{- notePathTitle}}",
"actions_executed": "Akcja została wykonana."
},
"similar_notes": {
"title": "Podobne notatki",
"no_similar_notes_found": "Nie znaleziono podobnych notatek."
},
"abstract_search_option": {
"remove_this_search_option": "Usuń tą opcję wyszukiwania",
"failed_rendering": "Nieudana opcja wyszukiwania: {{dto}} z błędem: {{error}} {{stack}}"
},
"ancestor": {
"label": "Przodek",
"placeholder": "szukaj notatki po jej nazwie",
"depth_label": "glębokość",
"depth_doesnt_matter": "nie ważne",
"depth_eq": "jest dokładnie {{count}}",
"direct_children": "bezpośrednie podnotatki",
"depth_gt": "jest więcej niż {{count}}",
"depth_lt": "jest mniej niż {{count}}"
},
"debug": {
"debug": "Debuguj",
"debug_info": "Debugowanie wyświetli dodatkowe informacje debugowania w konsoli, aby ułatwić debugowanie złożonych zapytań."
},
"fast_search": {
"fast_search": "Szybkie wyszukiwanie"
},
"file_properties": {
"download": "Pobierz",
"open": "Otwórz",
"upload_new_revision": "Wgraj nową wersję",
"upload_success": "Nowa wersja pliku nie została wysłana.",
"upload_failed": "Wysyłanie nowej wersji pliku się nie udało.",
"title": "Plik"
},
"include_note": {
"label_note": "Notatka",
"placeholder_search": "szukaj notatki po jej nazwie",
"dialog_title": "Dołącz notatkę",
"button_include": "Dołącz notatkę"
},
"info": {
"closeButton": "Zamknij",
"okButton": "OK",
"modalTitle": "Wiadomość"
},
"jump_to_note": {
"search_placeholder": "Szukaj notatki po jej nazwie albo typie > komendy...",
"search_button": "Wyszukiwanie pełno tekstowe"
},
"markdown_import": {
"dialog_title": "Zaimportuj Markdown",
"import_button": "Import",
"import_success": "Treść Markdown została zaimportowana do dokumentu."
},
"limit": {
"limit": "Limit"
},
"link_context_menu": {
"open_note_in_popup": "Szybka edycja",
"open_note_in_new_tab": "Otwórz notatkę w nowej karcie",
"open_note_in_new_split": "Otwórz notatkę w nowym podziale ekranu",
"open_note_in_new_window": "Otwórz notatkę w nowym oknie"
},
"electron_integration": {
"desktop-application": "Aplikacja desktopowa"
},
"electron_context_menu": {
"cut": "Wytnij",
"copy": "Kopiuj",
"copy-link": "Kopiuj link",
"paste": "Wklej",
"paste-as-plain-text": "Wklej jako plain text",
"search_online": "Szukaj \"{{term}}\" za pomocą {{searchEngine}}"
},
"image_context_menu": {
"copy_reference_to_clipboard": "Skopiuj odnośnik do schowka",
"copy_image_to_clipboard": "Skopiuj obraz do schowka"
},
"note_autocomplete": {
"clear-text-field": "Wyczyść pole tekstowe",
"show-recent-notes": "Pokaż ostatnie notatki",
"full-text-search": "Wyszukiwanie pełnotekstowe"
},
"note_tooltip": {
"note-has-been-deleted": "Notatka została usunięta.",
"quick-edit": "Szybka edycja"
},
"duration": {
"seconds": "sekundy",
"minutes": "minuty",
"hours": "godziny",
"days": "dni"
},
"share": {
"title": "Ustawienia udostępniania"
},
"tasks": {
"due": {
"today": "Dziś",
"tomorrow": "Jutro",
"yesterday": "Wczoraj"
}
},
"content_widget": {
"unknown_widget": "Nieznany widget dla \"{{id}}\"."
},
"note_language": {
"not_set": "Nie ustawione",
"configure-languages": "Konfiguracja języków..."
},
"content_language": {
"title": "Język treści",
"description": "Wybierz jeden lub więcej języków, które mają być wyświetlane w sekcji Właściwości Podstawowe Notatki Tekstowej tylko do odczytu lub edytowalnej. Umożliwi to korzystanie z takich funkcji, jak sprawdzanie pisowni czy obsługa pisania od prawej do lewej."
},
"switch_layout_button": {
"title_vertical": "Przesuń panel edycji na dół",
"title_horizontal": "Przesuń panel edycji do lewej"
},
"toggle_read_only_button": {
"unlock-editing": "Odblokuj edycję",
"lock-editing": "Zablokuj edycję"
},
"png_export_button": {
"button_title": "Wyeksportuj diagram jako PNG"
},
"svg": {
"export_to_png": "Diagram nie może zostać wyeksportowany jako PNG."
},
"code_theme": {
"title": "Wygląd",
"word_wrapping": "Zawijanie słów",
"color-scheme": "Schemat kolorów"
},
"cpu_arch_warning": {
"title": "Proszę o pobranie wersji ARM64",
"message_macos": "TriliumNext działa obecnie w oparciu o technologię Rosetta 2, co oznacza, że używasz wersji Intel (x64) na komputerze Mac z procesorem Apple Silicon. Będzie to miało znaczący wpływ na wydajność i czas pracy baterii.",
"message_windows": "TriliumNext działa obecnie w trybie emulacji, co oznacza, że używasz wersji Intel (x64) na urządzeniu z systemem Windows na procesorze ARM. Będzie to miało znaczący wpływ na wydajność i czas pracy baterii.",
"recommendation": "Aby uzyskać najlepsze wrażenia, pobierz natywną wersję ARM64 aplikacji TriliumNext ze strony poświęconej wydaniom.",
"download_link": "Pobierz wersję natywną",
"continue_anyway": "Kontynuuj mimo wszystko",
"dont_show_again": "Nie pokazuj więcej tego ostrzeżenia"
},
"editorfeatures": {
"title": "Cechy",
"emoji_completion_enabled": "Włącz autouzupełnianie Emoji",
"note_completion_enabled": "Włącz autouzupełnianie notatki"
},
"table_view": {
"new-row": "Nowy wiersz",
"new-column": "Nowa kolumna",
"sort-column-by": "Sotuj po \"{{title}}\"",
"sort-column-ascending": "Rosnąco",
"sort-column-descending": "Malejąco",
"sort-column-clear": "Wyczyść sortowanie",
"hide-column": "Ukryj kolumnę \"{{title}}\"",
"show-hide-columns": "Pokaż/ukryj kolumny",
"row-insert-above": "Wstaw wiersz nad",
"row-insert-below": "Wstaw wiersz pod",
"row-insert-child": "Wstaw podnotatkę",
"add-column-to-the-left": "Dodaj kolumnę po lewej",
"add-column-to-the-right": "Dodaj kolumnę po prawej",
"edit-column": "Edytuj kolumnę",
"delete_column_confirmation": "Czy na pewno chcesz usunąć tę kolumnę? Odpowiedni atrybut zostanie usunięty ze wszystkich notatek.",
"delete-column": "Usuń kolumnę",
"new-column-label": "Etykieta",
"new-column-relation": "Relacje"
},
"book_properties_config": {
"hide-weekends": "Ukryj weekendy",
"display-week-numbers": "Pokaż numery tygodni",
"map-style": "Styl mapy:",
"max-nesting-depth": "Maksymalna głębokość zagnieżdżenia:",
"raster": "Raster",
"vector_light": "Wektor (jasny)",
"vector_dark": "Wektor (ciemny)",
"show-scale": "Pokaż skalę"
},
"table_context_menu": {
"delete_row": "Usuń wiersz"
},
"move_to": {
"dialog_title": "Przenieś notatki do ...",
"notes_to_move": "Notatki do przeniesienia"
},
"note_type_chooser": {
"modal_title": "Wybierz typ notatki",
"modal_body": "Wybierz typ / szablon notatki dla nowej notatki:",
"templates": "Szablony",
"builtin_templates": "Wbudowane szablony"
},
"password_not_set": {
"title": "Hasło nie zostało ustawione"
},
"add_relation": {
"add_relation": "Dodaj powiązanie",
"relation_name": "nazwa powiązania",
"allowed_characters": "Dozwolone są znaki alfanumeryczne, podkreślenie i dwukropek.",
"to": "do",
"target_note": "docelowa notatka"
},
"ai_llm": {
"actions": "Akcje",
"retry": "Spróbuj ponownie",
"partial": "{{ percentage }}% wykonania",
"retry_queued": "notatka dodana do kolejki",
"retry_failed": "Nieudana próba dodania notatki do kolejki",
"max_notes_per_llm_query": "Maksymalna ilość notatek w zapytaniu",
"index_all_notes": "Zindeksuj wszystkie notatki",
"index_status": "Status indeksowania",
"indexed_notes": "Zindeksowane notatki",
"indexing_stopped": "Indeksowanie zatrzymane",
"indexing_in_progress": "Indeksowanie w trakcie...",
"last_indexed": "Ostatnio zindeksowane",
"n_notes_queued_0": "{{ count }} notatka zakolejkowana do indeksowania",
"n_notes_queued_1": "{{ count }} notatek zakolejkowanych do indeksowania",
"n_notes_queued_2": "{{ count }} notatek zakolejkowanych do indeksowania",
"note_chat": "Czat notatki",
"note_title": "Tytuł notatki",
"error": "Błąd",
"last_attempt": "Ostatnia próba",
"queued_notes": "Zakolejkowane notatki",
"failed_notes": "Nieudane notatki",
"last_processed": "Ostatnio procesowane",
"refresh_stats": "Odśwież Statystyki",
"enable_ai_features": "Włącz funkcje AI/LLM",
"enable_ai_description": "Włącz funkcje AI, takie jak podsumowywanie notatek, generowanie treści i inne możliwości LLM",
"openai_tab": "OpenAI",
"anthropic_tab": "Anthropic",
"voyage_tab": "Voyage AI",
"ollama_tab": "Ollama",
"enable_ai": "Włącz funkcje AI/LLM",
"enable_ai_desc": "Włącz funkcje AI, takie jak podsumowywanie notatek, generowanie treści i inne możliwości LLM",
"provider_configuration": "Konfiguracja dostawcy AI",
"provider_precedence": "Pierwszeństwo dostawcy",
"provider_precedence_description": "Lista dostawców przedzielonych przecinkami w kolejności (np. „openai,anthropic,ollama”)",
"temperature": "Temperatura",
"temperature_description": "Kontroluje losowość odpowiedzi (0 = deterministyczna, 2 = maksymalna losowość)",
"system_prompt": "Monit systemowy",
"system_prompt_description": "Domyślny monit systemowy używany do wszystkich interakcji ze sztuczną inteligencją",
"openai_configuration": "Konfiguracja OpenAI",
"openai_settings": "Ustawienia OpenAI",
"api_key": "Klucz API",
"url": "Bazowy URL",
"model": "Model",
"openai_api_key_description": "Klucz API OpenAI umożliwiający dostęp do usług AI",
"anthropic_api_key_description": "Klucz API Anthropic umożliwiający dostęp do usług AI",
"default_model": "Domyślny Model",
"openai_model_description": "Przykłady: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"base_url": "Bazowy URL",
"openai_url_description": "Domyślny: https://api.openai.com/v1",
"anthropic_settings": "Ustawienia Anthropic",
"anthropic_url_description": "Bazowy URL dla Anthropic API (domyślny: https://api.anthropic.com)",
"anthropic_model_description": "Modele Anthropic Claude'a do uzupełniania czatów",
"voyage_settings": "Ustawienia Voyage AI",
"ollama_settings": "Ustawienia Ollama",
"ollama_url_description": "URL dla Ollama API (domyślny: http://localhost:11434)",
"ollama_model_description": "Model Ollama używany do uzupełniania czatów",
"anthropic_configuration": "Konfiguracja Anthropic",
"voyage_configuration": "Konfiguracja Voyage AI",
"voyage_url_description": "Domyślny: https://api.voyageai.com/v1",
"ollama_configuration": "Konfiguracja Ollama",
"enable_ollama": "Włącz Ollama",
"enable_ollama_description": "Włącz Ollama dla lokalnego modelu AI",
"ollama_url": "Ollama URL",
"ollama_model": "Model Ollama",
"refresh_models": "Odśwież modele",
"refreshing_models": "Odświeżanie...",
"enable_automatic_indexing": "Włącz automatyczne indeksowanie",
"rebuild_index": "Odbuduj indeks",
"rebuild_index_error": "Błąd uruchomienia odbudowy indeksu. Sprawdź logi.",
"max_notes_per_llm_query_description": "Maksymalna liczba podobnych notatek do uwzględnienia w kontekście sztucznej inteligencji",
"active_providers": "Aktywni dostawcy",
"disabled_providers": "Wyłączeni dostawcy",
"remove_provider": "Usuń dostawcę z wyszukiwania",
"restore_provider": "Przywróć dostawcę do wyszukiwania",
"similarity_threshold": "Próg podobieństwa"
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,7 @@
"add_relation": {
"add_relation": "Adaugă relație",
"allowed_characters": "Sunt permise doar caractere alfanumerice, underline și două puncte.",
"create_relation_on_all_matched_notes": "Creează relația pentru toate notițele găsite.",
"create_relation_on_all_matched_notes": "Crează relația pentru toate notițele găsite",
"relation_name": "denumirea relației",
"target_note": "notița destinație",
"to": "către"
@@ -76,9 +76,9 @@
"attachment_erasure_timeout": {
"attachment_auto_deletion_description": "Atașamentele se șterg automat (permanent) dacă nu sunt referențiate de către notița lor părinte după un timp prestabilit de timp.",
"attachment_erasure_timeout": "Perioadă de ștergere a atașamentelor",
"erase_attachments_after": "Șterge atașamentele neutilizate după:",
"erase_attachments_after": "Erase unused attachments after:",
"erase_unused_attachments_now": "Elimină atașamentele șterse acum",
"manual_erasing_description": "Puteți șterge atașamentele nefolosite manual (fără a lua în considerare timpul de mai sus):",
"manual_erasing_description": "Șterge acum toate atașamentele nefolosite din notițe",
"unused_attachments_erased": "Atașamentele nefolosite au fost șterse."
},
"attachment_list": {
@@ -141,7 +141,7 @@
"hide_promoted_attributes": "Ascunde lista atributelor promovate pentru această notiță",
"hide_relations": "lista denumirilor relațiilor ce trebuie ascunse, delimitate prin virgulă. Toate celelalte vor fi afișate.",
"icon_class": "valoarea acestei etichete este adăugată ca o clasă CSS la iconița notiței din ierarhia notițelor, fapt ce poate ajuta la identificarea vizuală mai rapidă a notițelor. Un exemplu ar fi „bx bx-home” pentru iconițe preluate din boxicons. Poate fi folosită în notițe de tip șablon.",
"inbox": "locația implicită în care vor apărea noile notițe atunci când se crează o noitiță utilizând butonul „Crează notiță” din bara laterală, notițele vor fi create în interiorul notiței marcată cu eticheta <code>#inbox</code>.",
"inbox": "locația implicită în care vor apărea noile notițe atunci când se crează o noitiță utilizând butonul „Crează notiță” din bara laterală, notițele vor fi create în interiorul notiței cu această etichetă.",
"inherit": "atributele acestei notițe vor fi moștenite chiar dacă nu există o relație părinte-copil între notițe. A se vedea relația de tip șablon pentru un concept similar. De asemenea, a se vedea moștenirea atributelor în documentație.",
"inheritable": "Moștenibilă",
"inheritable_title": "Atributele moștenibile vor fi moștenite de către toți descendenții acestei notițe.",
@@ -177,7 +177,7 @@
"render_note": "relație ce definește notița (de tip notiță de cod HTML sau script) ce trebuie randată pentru notițele de tip „Randare notiță HTML”",
"run": "definește evenimentele la care să ruleze scriptul. Valori acceptate:\n<ul>\n<li>frontendStartup - când pornește interfața Trilium (sau este reîncărcată), dar nu pe mobil.</li>\n<li>mobileStartup - când pornește interfața Trilium (sau este reîncărcată), doar pe mobil.</li>\n<li>backendStartup - când pornește serverul Trilium</li>\n<li>hourly - o dată pe oră. Se poate utiliza adițional eticheta <code>runAtHour</code> pentru a specifica ora.</li>\n<li>daily - o dată pe zi</li>\n</ul>",
"run_at_hour": "La ce oră ar trebui să ruleze. Trebuie folosit împreună cu <code>#run=hourly</code>. Poate fi definit de mai multe ori pentru a rula de mai multe ori în cadrul aceleași zile.",
"run_on_attribute_change": " se execută atunci când atributele unei notițe care definește această relație se schimbă. Se apelează și atunci când un atribut este șters",
"run_on_attribute_change": "se execută atunci când atributele unei notițe care definește această relație se schimbă. Se apelează și atunci când un atribut este șters",
"run_on_attribute_creation": "se execută atunci când un nou atribut este creat pentru notița care definește această relație",
"run_on_branch_change": "se execută atunci când o ramură este actualizată.",
"run_on_branch_creation": "se execută când o ramură este creată. O ramură este o legătură dintre o notiță părinte și o notiță copil și este creată, spre exemplu, la clonarea sau mutarea unei notițe.",
@@ -198,7 +198,7 @@
"share_disallow_robot_indexing": "împiedică indexarea conținutului de către roboți utilizând antetul <code>X-Robots-Tag: noindex</code>",
"share_external_link": "notița va funcționa drept o legătură către un site web extern în ierarhia de partajare",
"share_favicon": "Notiță ce conține pictograma favicon pentru a fi setată în paginile partajate. De obicei se poate seta în rădăcina ierarhiei de partajare și se poate face moștenibilă. Notița ce conține favicon-ul trebuie să fie și ea în ierarhia de partajare. Considerați și utilizarea „share_hidden_from_tree”.",
"share_hidden_from_tree": "notița este ascunsă din arborele de navigație din stânga, dar încă este accesibilă prin intermediul unui URL",
"share_hidden_from_tree": "notița este ascunsă din arborele de navigație din stânga, dar încă este accesibilă prin intermediul unui URL.",
"share_index": "notițele cu această etichetă vor afișa lista tuturor rădăcilor notițelor partajate",
"share_js": "Notiță JavaScript ce va fi injectată în pagina de partajare. Notița respectivă trebuie să fie și ea în ierarhia de partajare. Considerați utilizarea 'share_hidden_from_tree'.",
"share_omit_default_css": "CSS-ul implicit pentru pagina de partajare va fi omis. Se poate folosi atunci când se fac schimbări majore de stil la pagină.",
@@ -214,7 +214,7 @@
"target_note_title": "Relația este o conexiune numită dintre o notiță sursă și o notiță țintă.",
"template": "Șablon",
"text": "Text",
"title_template": "titlul implicit al notițelor create în interiorul acestei notițe. Valoarea este evaluată ca un șir de caractere JavaScript\n și poate fi astfel îmbogățită cu un conținut dinamic prin intermediul variabilelor <code>now</code> și <code>parentNote</code>. Exemple:\n \n <ul>\n <li><code>Lucrările lui ${parentNote.getLabelValue('autor')}</code></li>\n <li><code>Jurnal pentru ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n A se vedea <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki-ul pentru detalii</a>, documentația API pentru <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> și <a href=\"https://day.js.org/docs/en/display/format\">now</a> pentru mai multe informații.",
"title_template": "titlul implicit al notițelor create în interiorul acestei notițe. Valoarea este evaluată ca un șir de caractere JavaScript\n și poate fi astfel îmbogățită cu un conținut dinamic prin intermediul variabilelow <code>now</code> și <code>parentNote</code>. Exemple:\n \n <ul>\n <li><code>Lucrările lui ${parentNote.getLabelValue('autor')}</code></li>\n <li><code>Jurnal pentru ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n </ul>\n \n A se vedea <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki-ul pentru detalii</a>, documentația API pentru <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> și <a href=\"https://day.js.org/docs/en/display/format\">now</a> pentru mai multe informații",
"toc": "<code>#toc</code> sau <code>#toc=show</code> forțează afișarea tabelei de conținut, <code>#toc=hide</code> forțează ascunderea ei. Dacă eticheta nu există, se utilizează setările globale",
"top": "păstrează notița la începutul listei (se aplică doar pentru notițe sortate automat)",
"url": "URL",
@@ -267,13 +267,10 @@
"basic_properties": "Proprietăți de bază",
"editable": "Editabil",
"note_type": "Tipul notiței",
"language": "Limbă",
"configure_code_notes": "Configurează notițele de tip cod..."
"language": "Limbă"
},
"book": {
"no_children_help": "Această notiță de tip Carte nu are nicio subnotiță așadar nu este nimic de afișat. Vedeți <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> pentru detalii.",
"drag_locked_title": "Blocat pentru editare",
"drag_locked_message": "Glisarea notițelor nu este permisă deoarece colecția este blocată pentru editare."
"no_children_help": "Această notiță de tip Carte nu are nicio subnotiță așadar nu este nimic de afișat. Vedeți <a href=\"https://triliumnext.github.io/Docs/Wiki/book-note.html\">wiki</a> pentru detalii."
},
"book_properties": {
"collapse": "Minimizează",
@@ -288,8 +285,7 @@
"book_properties": "Proprietăți colecție",
"table": "Tabel",
"geo-map": "Hartă geografică",
"board": "Tablă Kanban",
"include_archived_notes": "Afișează notițele arhivate"
"board": "Tablă Kanban"
},
"bookmark_switch": {
"bookmark": "Semn de carte",
@@ -338,18 +334,7 @@
"thu": "Joi",
"tue": "Mar",
"wed": "Mie",
"cannot_find_week_note": "Nu s-a putut găsi notița săptămânală",
"week": "Săptămână",
"week_previous": "Săptămâna trecută",
"week_next": "Următoarea săptămână",
"month": "Lună",
"month_previous": "Luna anterioară",
"month_next": "Următoarea lună",
"year": "An",
"year_previous": "Anul trecut",
"year_next": "Anul următor",
"list": "Agendă",
"today": "Astăzi"
"cannot_find_week_note": "Nu s-a putut găsi notița săptămânală"
},
"clone_to": {
"clone_notes_to": "Clonează notițele către...",
@@ -384,7 +369,7 @@
},
"confirm": {
"also_delete_note": "Șterge și notița",
"are_you_sure_remove_note": "Doriți ștergerea notiței „{{title}}” din harta de relații? ",
"are_you_sure_remove_note": "Doriți ștergerea notiței „{{title}}” din harta de relații?",
"cancel": "Anulează",
"confirmation": "Confirm",
"if_you_dont_check": "Dacă această opțiune nu este bifată, notița va fi ștearsă doar din harta de relații.",
@@ -534,8 +519,8 @@
"export_status": "Starea exportului",
"export_type_single": "Doar această notiță fără descendenții ei",
"export_type_subtree": "Această notiță și toți descendenții ei",
"format_html_zip": "HTML în arhivă ZIP - recomandat deoarece păstrează toată formatarea.",
"format_markdown": "Markdown - păstrează majoritatea formatării.",
"format_html_zip": "HTML în arhivă ZIP - recomandat deoarece păstrează toată formatarea",
"format_markdown": "Markdown - păstrează majoritatea formatării",
"format_opml": "OPML - format de interschimbare pentru editoare cu structură ierarhică (outline). Formatarea, imaginile și fișierele nu vor fi incluse.",
"opml_version_1": "OPML v1.0 - text simplu",
"opml_version_2": "OPML v2.0 - permite și HTML",
@@ -655,7 +640,7 @@
"newTabNoteLink": "pe o legătură către o notiță va deschide notița într-un tab nou",
"notSet": "nesetat",
"noteNavigation": "Navigarea printre notițe",
"numberedList": "<code>1.</code> sau <code>1)</code> urmat de spațiu pentru o listă numerotată",
"numberedList": "<kbd>1.</code> sau <code>1)</code> urmat de spațiu pentru o listă numerotată",
"onlyInDesktop": "Doar pentru desktop (aplicația Electron)",
"openEmptyTab": "deschide un tab nou",
"other": "Altele",
@@ -670,8 +655,7 @@
"showSQLConsole": "afișează consola SQL",
"tabShortcuts": "Scurtături pentru tab-uri",
"troubleshooting": "Unelte pentru depanare",
"newTabWithActivationNoteLink": "pe o legătură către o notiță deschide și activează notița într-un tab nou",
"title": "Ghid rapid"
"newTabWithActivationNoteLink": "pe o legătură către o notiță deschide și activează notița într-un tab nou"
},
"hide_floating_buttons_button": {
"button_title": "Ascunde butoanele"
@@ -822,7 +806,7 @@
"dialog_title": "Mută notițele în...",
"error_no_path": "Nicio cale la care să poată fi mutate.",
"move_button": "Mută la notița selectată",
"move_success_message": "Notițele selectate au fost mutate în ",
"move_success_message": "Notițele selectate au fost mutate în",
"notes_to_move": "Notițe de mutat",
"search_placeholder": "căutați notița după denumirea ei",
"target_parent_note": "Notița părinte destinație"
@@ -902,8 +886,7 @@
"modal_title": "Selectați tipul notiței",
"templates": "Șabloane",
"change_path_prompt": "Selectați locul unde să se creeze noua notiță:",
"search_placeholder": "căutare cale notiță după nume (cea implicită dacă este necompletat)",
"builtin_templates": "Șabloane predefinite"
"search_placeholder": "căutare cale notiță după nume (cea implicită dacă este necompletat)"
},
"onclick_button": {
"no_click_handler": "Butonul „{{componentId}}” nu are nicio acțiune la clic definită"
@@ -957,9 +940,7 @@
},
"password_not_set": {
"body1": "Notițele protejate sunt criptate utilizând parola de utilizator, dar nu a fost setată nicio parolă.",
"title": "Parola nu este setată",
"body2": "Pentru a putea proteja notițe, clic pe butonul de mai jos pentru a deschide fereastra de opțiuni și pentru a seta parola.",
"go_to_password_options": "Mergi la setările de parolă"
"title": "Parola nu este setată"
},
"promoted_attributes": {
"add_new_attribute": "Adaugă un nou atribut",
@@ -1073,7 +1054,7 @@
"download_button": "Descarcă",
"file_size": "Dimensiune fișier:",
"help_title": "Informații despre reviziile notițelor",
"mime": "MIME: ",
"mime": "MIME:",
"no_revisions": "Nu există încă nicio revizie pentru această notiță...",
"note_revisions": "Revizii ale notiței",
"preview": "Previzualizare:",
@@ -1085,18 +1066,13 @@
"revisions_deleted": "Notița reviziei a fost ștearsă.",
"maximum_revisions": "Numărul maxim de revizii pentru notița curentă: {{number}}.",
"settings": "Setări revizii ale notițelor",
"snapshot_interval": "Intervalul de creare a reviziilor pentru notițe: {{seconds}}s.",
"diff_on": "Evidențiază diferențele",
"diff_off": "Afișează conținutul",
"diff_on_hint": "Clic pentru a afișa diferențele față de revizia anterioară, la nivel de cod sursă",
"diff_off_hint": "Clic pentru a afișa întregul conținut al reviziei",
"diff_not_available": "Diferențele nu pot fi evidențiate."
"snapshot_interval": "Intervalul de creare a reviziilor pentru notițe: {{seconds}}s."
},
"revisions_button": {
"note_revisions": "Revizii ale notiței"
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_description": "Intervalul de salvare a reviziilor este timpul după care se crează o nouă revizie a unei notițe. Vedeți <doc>wiki-ul</doc> pentru mai multe informații.",
"note_revisions_snapshot_description": "Intervalul de salvare a reviziilor este timpul după care se crează o nouă revizie a unei notițe. Vedeți <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">wiki-ul</a> pentru mai multe informații.",
"note_revisions_snapshot_interval_title": "Intervalul de salvare a reviziilor",
"snapshot_time_interval_label": "Intervalul de salvare a reviziilor:"
},
@@ -1126,7 +1102,7 @@
"limit_description": "Limitează numărul de rezultate",
"order_by": "ordonează după",
"save_to_note": "Salvează în notiță",
"search_button": "Căutare",
"search_button": "Căutare <kbd>Enter</kbd>",
"search_execute": "Caută și execută acțiunile",
"search_note_saved": "Notița de căutare a fost salvată în {{- notePathTitle}}",
"search_parameters": "Parametrii de căutare",
@@ -1213,7 +1189,7 @@
"enable": "Activează corectorul ortografic",
"language_code_label": "Codurile de limbă",
"language_code_placeholder": "de exemplu „en-US”, „de-AT”",
"multiple_languages_info": "Mai multe limbi pot fi separate prin virgulă, e.g. \"en-US, de-DE, cs\". ",
"multiple_languages_info": "Mai multe limbi pot fi separate prin virgulă, e.g. \"en-US, de-DE, cs\".",
"title": "Corector ortografic",
"restart-required": "Schimbările asupra setărilor corectorului ortografic vor fi aplicate după restartarea aplicației."
},
@@ -1267,10 +1243,7 @@
"layout-horizontal-description": "bara de lansare se află sub bara de taburi, bara de taburi este pe toată lungimea.",
"layout-horizontal-title": "Orizontal",
"layout-vertical-title": "Vertical",
"layout-vertical-description": "bara de lansare se află pe stânga (implicit)",
"auto_theme": "Tema clasică (se adaptează la schema de culori a sistemului)",
"light_theme": "Tema clasică (luminoasă)",
"dark_theme": "Tema clasică (întunecată)"
"layout-vertical-description": "bara de lansare se află pe stânga (implicit)"
},
"toast": {
"critical-error": {
@@ -1306,7 +1279,7 @@
"update_relation_target": {
"allowed_characters": "Sunt permise doar caractere alfanumerice, underline și două puncte.",
"change_target_note": "schimbă notița-țintă a unei relații existente",
"on_all_matched_notes": "Pentru toate notițele găsite",
"on_all_matched_notes": "Pentru toate notițele găsite:",
"relation_name": "denumirea relației",
"target_note": "notița destinație",
"to": "la",
@@ -1334,7 +1307,7 @@
"use_vim_keybindings_in_code_notes": "Combinații de taste Vim"
},
"web_view": {
"create_label": "Pentru a începe, creați o etichetă cu adresa URL de încorporat, e.g. #webViewSrc=\"https://www.google.com\"",
"create_label": "Pentru a începe, creați o etichetă cu adresa URL de încorporat, e.g. #webViewSrc=\"https://www.google.com\"",
"embed_websites": "Notițele de tip „Vizualizare web” permit încorporarea site-urilor web în Trilium.",
"web_view": "Vizualizare web"
},
@@ -1377,7 +1350,7 @@
"insert-note-after": "Inserează după notiță",
"move-to": "Mutare la...",
"open-in-a-new-split": "Deschide în lateral",
"open-in-a-new-tab": "Deschide în tab nou",
"open-in-a-new-tab": "Deschide în tab nou <kbd>Ctrl+Clic</kbd>",
"paste-after": "Lipește după notiță",
"paste-into": "Lipește în notiță",
"protect-subtree": "Protejează ierarhia",
@@ -1389,14 +1362,12 @@
"unhoist-note": "Defocalizează notița",
"converted-to-attachments": "{{count}} notițe au fost convertite în atașamente.",
"convert-to-attachment-confirm": "Doriți convertirea notițelor selectate în atașamente ale notiței părinte?",
"open-in-popup": "Editare rapidă",
"archive": "Arhivează",
"unarchive": "Dezarhivează"
"open-in-popup": "Editare rapidă"
},
"shared_info": {
"help_link": "Pentru informații vizitați <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki-ul</a>.",
"shared_locally": "Această notiță este partajată local la {{- link}}.",
"shared_publicly": "Această notiță este partajată public la {{- link}}."
"shared_locally": "Această notiță este partajată local la",
"shared_publicly": "Această notiță este partajată public la"
},
"note_types": {
"book": "Colecție",
@@ -1494,8 +1465,7 @@
"create-child-note": "Crează subnotiță",
"hoist-this-note-workspace": "Focalizează spațiul de lucru",
"refresh-saved-search-results": "Reîmprospătează căutarea salvată",
"unhoist": "Defocalizează notița",
"toggle-sidebar": "Comută bara laterală"
"unhoist": "Defocalizează notița"
},
"title_bar_buttons": {
"window-on-top": "Menține fereastra mereu vizibilă"
@@ -1886,20 +1856,15 @@
},
"create_new_ai_chat": "Crează o nouă discuție cu AI-ul",
"configuration_warnings": "Sunt câteva probleme la configurația AI-ului. Verificați setările.",
"experimental_warning": "Funcția LLM este experimentală.",
"experimental_warning": "Funcția LLM este experimentală!",
"selected_provider": "Furnizor selectat",
"selected_provider_description": "Selectați furnizorul de AI pentru funcțiile de discuție și completare",
"select_model": "Selectați modelul...",
"select_provider": "Selectați furnizorul...",
"ai_enabled": "Funcționalitățile AI au fost activate",
"ai_disabled": "Funcționalitățile AI au fost dezactivate",
"no_models_found_online": "Nu s-a găsit niciun model. Verificați cheia API și configurația.",
"no_models_found_ollama": "Nu s-a găsit niciun model Ollama. Verificați dacă Ollama rulează.",
"error_fetching": "Eroare la obținerea modelelor: {{error}}"
"select_provider": "Selectați furnizorul..."
},
"custom_date_time_format": {
"title": "Format dată/timp personalizat",
"description": "Personalizați formatul de dată și timp inserat prin <shortcut /> sau din bara de unelte. Vedeți <doc>Documentația Day.js</doc> pentru câmpurile de formatare disponibile.",
"description": "Personalizați formatul de dată și timp inserat prin <kbd></kbd> sau din bara de unelte. Vedeți <a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Documentația Day.js</a> pentru câmpurile de formatare disponibile.",
"format_string": "Șir de formatare:",
"formatted_time": "Data și ora formatate:"
},
@@ -1992,21 +1957,14 @@
"delete_row": "Șterge rândul"
},
"board_view": {
"delete-note": "Șterge notița...",
"delete-note": "Șterge notița",
"move-to": "Mută la",
"insert-above": "Inserează deasupra",
"insert-below": "Inserează dedesubt",
"delete-column": "Șterge coloana",
"delete-column-confirmation": "Doriți ștergerea acestei coloane? Atributul corespunzător va fi șters din notițele din acest tabel.",
"new-item": "Intrare nouă",
"add-column": "Adaugă coloană",
"remove-from-board": "Înlătură de pe tablă",
"archive-note": "Arhivează notița",
"unarchive-note": "Dezarhivează notița",
"new-item-placeholder": "Introduceți titlul notiței...",
"add-column-placeholder": "Introduceți denumirea coloanei...",
"edit-note-title": "Clic pentru a edita titlul notiței",
"edit-column-title": "Clic pentru a edita titlul coloanei"
"add-column": "Adaugă coloană"
},
"command_palette": {
"tree-action-name": "Listă de notițe: {{name}}",
@@ -2027,41 +1985,6 @@
"open_externally": "Deschide în afara programului"
},
"modal": {
"close": "Închide",
"help_title": "Afișează mai multe informații despre acest ecran"
},
"call_to_action": {
"background_effects_title": "Efectele de fundal sunt acum stabile",
"background_effects_message": "Pe dispozitive cu Windows, efectele de fundal sunt complet stabile. Acestea adaugă un strop de culoare interfeței grafice prin estomparea fundalului din spatele ferestrei. Această tehnică este folosită și în alte aplicații precum Windows Explorer.",
"background_effects_button": "Activează efectele de fundal",
"next_theme_title": "Încercați noua temă Trilium",
"next_theme_message": "Utilizați tema clasică, doriți să încercați noua temă?",
"next_theme_button": "Testează noua temă",
"dismiss": "Treci peste"
},
"ui-performance": {
"title": "Setări de performanță",
"enable-motion": "Activează tranzițiile și animațiile",
"enable-shadows": "Activează umbrirea elementelor",
"enable-backdrop-effects": "Activează efectele de fundal pentru meniuri, popup-uri și panouri",
"enable-smooth-scroll": "Activează derularea lină",
"app-restart-required": "(este necesară repornirea aplicației pentru ca modificarea să aibă efect)"
},
"settings": {
"related_settings": "Setări similare"
},
"settings_appearance": {
"related_code_blocks": "Tema de culori pentru blocuri de cod în notițe de tip text",
"related_code_notes": "Tema de culori pentru notițele de tip cod"
},
"units": {
"percentage": "%"
},
"pagination": {
"page_title": "Pagina pentru {{startIndex}} - {{endIndex}}",
"total_notes": "{{count}} notițe"
},
"collections": {
"rendering_error": "Nu a putut fi afișat conținutul din cauza unei erori."
"close": "Închide"
}
}

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