mirror of
https://github.com/zadam/trilium.git
synced 2025-11-06 13:26:01 +01:00
Merge branch 'main' into feat/clean-share-url
This commit is contained in:
@@ -8,6 +8,9 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
[{server,translation}.json]
|
[{server,translation}.json]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
|
|||||||
12
.gitattributes
vendored
12
.gitattributes
vendored
@@ -1,17 +1,21 @@
|
|||||||
|
# Mark files as auto-generated to simplify reviews.
|
||||||
package-lock.json linguist-generated=true
|
package-lock.json linguist-generated=true
|
||||||
**/package-lock.json linguist-generated=true
|
**/package-lock.json linguist-generated=true
|
||||||
|
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/** linguist-generated
|
||||||
|
|
||||||
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/** linguist-generated=true
|
# Ignore from GitHub language stats.
|
||||||
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/**/*.html eol=lf
|
apps/server/src/assets/doc_notes/en/User[[:space:]]Guide/**/*.html eol=lf
|
||||||
|
apps/server/src/assets/doc_notes/** linguist-vendored=true
|
||||||
|
apps/edit-docs/demo/** linguist-vendored=true
|
||||||
|
docs/** linguist-vendored=true
|
||||||
|
|
||||||
|
# Normalize line endings.
|
||||||
docs/**/*.md eol=lf
|
docs/**/*.md eol=lf
|
||||||
docs/**/*.json eol=lf
|
docs/**/*.json eol=lf
|
||||||
|
|
||||||
demo/**/*.html eol=lf
|
demo/**/*.html eol=lf
|
||||||
demo/**/*.json eol=lf
|
demo/**/*.json eol=lf
|
||||||
demo/**/*.svg eol=lf
|
demo/**/*.svg eol=lf
|
||||||
demo/**/*.txt eol=lf
|
demo/**/*.txt eol=lf
|
||||||
demo/**/*.js eol=lf
|
demo/**/*.js eol=lf
|
||||||
demo/**/*.css eol=lf
|
demo/**/*.css eol=lf
|
||||||
|
*.sh eol=lf
|
||||||
apps/client/src/libraries/** linguist-vendored
|
|
||||||
|
|||||||
2
.github/actions/build-electron/action.yml
vendored
2
.github/actions/build-electron/action.yml
vendored
@@ -85,7 +85,7 @@ runs:
|
|||||||
APPLE_ID: ${{ env.APPLE_ID }}
|
APPLE_ID: ${{ env.APPLE_ID }}
|
||||||
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
APPLE_ID_PASSWORD: ${{ env.APPLE_ID_PASSWORD }}
|
||||||
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
|
WINDOWS_SIGN_EXECUTABLE: ${{ env.WINDOWS_SIGN_EXECUTABLE }}
|
||||||
TRILIUM_ARTIFACT_NAME_HINT: TriliumNextNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
||||||
run: pnpm nx --project=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
|
# Add DMG signing step
|
||||||
|
|||||||
2
.github/actions/build-server/action.yml
vendored
2
.github/actions/build-server/action.yml
vendored
@@ -30,4 +30,4 @@ runs:
|
|||||||
mkdir -p upload
|
mkdir -p upload
|
||||||
file=$(find ./apps/server/out -name '*.tar.xz' -print -quit)
|
file=$(find ./apps/server/out -name '*.tar.xz' -print -quit)
|
||||||
name=${{ github.ref_name }}
|
name=${{ github.ref_name }}
|
||||||
cp "$file" "upload/TriliumNextNotes-Server-${name//\//-}-${{ inputs.os }}-${{ inputs.arch }}.tar.xz"
|
cp "$file" "upload/TriliumNotes-Server-${name//\//-}-${{ inputs.os }}-${{ inputs.arch }}.tar.xz"
|
||||||
|
|||||||
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -13,9 +13,9 @@ name: "CodeQL Advanced"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ "develop" ]
|
branches: [ "main" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "develop" ]
|
branches: [ "main" ]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '20 7 * * 0'
|
- cron: '20 7 * * 0'
|
||||||
|
|
||||||
|
|||||||
91
.github/workflows/dev.yml
vendored
91
.github/workflows/dev.yml
vendored
@@ -1,9 +1,9 @@
|
|||||||
name: Dev
|
name: Dev
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ develop ]
|
branches: [ main ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ develop ]
|
branches: [ main ]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -12,8 +12,8 @@ concurrency:
|
|||||||
env:
|
env:
|
||||||
GHCR_REGISTRY: ghcr.io
|
GHCR_REGISTRY: ghcr.io
|
||||||
DOCKERHUB_REGISTRY: docker.io
|
DOCKERHUB_REGISTRY: docker.io
|
||||||
IMAGE_NAME: ${{ github.repository_owner }}/notes
|
IMAGE_NAME: ${{ github.repository}}
|
||||||
TEST_TAG: ${{ github.repository_owner }}/notes:test
|
TEST_TAG: ${{ github.repository}}:test
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write # for PR comments
|
pull-requests: write # for PR comments
|
||||||
@@ -39,76 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
- name: Check affected
|
- name: Check affected
|
||||||
run: pnpm nx affected -t build rebuild-deps
|
run: pnpm nx affected --verbose -t typecheck build rebuild-deps test-build
|
||||||
|
|
||||||
report-electron-size:
|
|
||||||
name: Report Electron size
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- check-affected
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
- name: Run the build
|
|
||||||
uses: ./.github/actions/build-electron
|
|
||||||
with:
|
|
||||||
os: linux
|
|
||||||
arch: x64
|
|
||||||
shell: bash
|
|
||||||
forge_platform: linux
|
|
||||||
|
|
||||||
- name: Run the Electron size report
|
|
||||||
uses: ./.github/actions/report-size
|
|
||||||
with:
|
|
||||||
paths: 'upload/**/*'
|
|
||||||
onlyDiff: 'true'
|
|
||||||
branch: 'develop'
|
|
||||||
header: 'Electron size report'
|
|
||||||
unit: "MB"
|
|
||||||
ghToken: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
report-server-size:
|
|
||||||
name: Report server size
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs:
|
|
||||||
- check-affected
|
|
||||||
steps:
|
|
||||||
- name: Checkout the repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
- name: Set up node & dependencies
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
cache: "pnpm"
|
|
||||||
|
|
||||||
- run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Run the build
|
|
||||||
uses: ./.github/actions/build-server
|
|
||||||
with:
|
|
||||||
os: linux
|
|
||||||
arch: x64
|
|
||||||
|
|
||||||
- name: Run the server size report
|
|
||||||
uses: ./.github/actions/report-size
|
|
||||||
with:
|
|
||||||
paths: 'upload/**/*'
|
|
||||||
onlyDiff: 'true'
|
|
||||||
branch: 'develop'
|
|
||||||
header: 'Server size report'
|
|
||||||
unit: "MB"
|
|
||||||
ghToken: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
test_dev:
|
test_dev:
|
||||||
name: Test development
|
name: Test development
|
||||||
@@ -128,7 +59,7 @@ jobs:
|
|||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run the unit tests
|
- name: Run the unit tests
|
||||||
run: pnpm run test
|
run: pnpm run test:all
|
||||||
|
|
||||||
build_docker:
|
build_docker:
|
||||||
name: Build Docker image
|
name: Build Docker image
|
||||||
@@ -143,7 +74,15 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
- name: Update build info
|
- name: Update build info
|
||||||
run: pnpm run chore:update-build-info
|
run: pnpm run chore:update-build-info
|
||||||
- name: Trigger build
|
- name: Trigger client build
|
||||||
|
run: pnpm nx run client:build
|
||||||
|
- name: Send client bundle stats to RelativeCI
|
||||||
|
if: false
|
||||||
|
uses: relative-ci/agent-action@v3
|
||||||
|
with:
|
||||||
|
webpackStatsFile: ./apps/client/dist/webpack-stats.json
|
||||||
|
key: ${{ secrets.RELATIVE_CI_CLIENT_KEY }}
|
||||||
|
- name: Trigger server build
|
||||||
run: pnpm nx run server:build
|
run: pnpm nx run server:build
|
||||||
- uses: docker/setup-buildx-action@v3
|
- uses: docker/setup-buildx-action@v3
|
||||||
- uses: docker/build-push-action@v6
|
- uses: docker/build-push-action@v6
|
||||||
|
|||||||
31
.github/workflows/main-docker.yml
vendored
31
.github/workflows/main-docker.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- "develop"
|
- "main"
|
||||||
- "feature/update**"
|
- "feature/update**"
|
||||||
- "feature/server_esm**"
|
- "feature/server_esm**"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
@@ -14,8 +14,8 @@ on:
|
|||||||
env:
|
env:
|
||||||
GHCR_REGISTRY: ghcr.io
|
GHCR_REGISTRY: ghcr.io
|
||||||
DOCKERHUB_REGISTRY: docker.io
|
DOCKERHUB_REGISTRY: docker.io
|
||||||
IMAGE_NAME: ${{ github.repository_owner }}/notes
|
IMAGE_NAME: ${{ github.repository}}
|
||||||
TEST_TAG: ${{ github.repository_owner }}/notes:test
|
TEST_TAG: ${{ github.repository}}:test
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -53,7 +53,7 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Install Playwright Browsers
|
- name: Install Playwright Browsers
|
||||||
run: npx playwright install --with-deps
|
run: pnpm exec playwright install --with-deps
|
||||||
|
|
||||||
- name: Run the TypeScript build
|
- name: Run the TypeScript build
|
||||||
run: pnpm run server:build
|
run: pnpm run server:build
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
file: ${{ matrix.dockerfile }}
|
file: apps/server/${{ matrix.dockerfile }}
|
||||||
load: true
|
load: true
|
||||||
tags: ${{ env.TEST_TAG }}
|
tags: ${{ env.TEST_TAG }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Validate container run output
|
- name: Validate container run output
|
||||||
run: |
|
run: |
|
||||||
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./integration-tests/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
|
CONTAINER_ID=$(docker run -d --log-driver=journald --rm --network=host -e TRILIUM_PORT=8082 --volume ./apps/server/spec/db:/home/node/trilium-data --name trilium_local ${{ env.TEST_TAG }})
|
||||||
echo "Container ID: $CONTAINER_ID"
|
echo "Container ID: $CONTAINER_ID"
|
||||||
|
|
||||||
- name: Wait for the healthchecks to pass
|
- name: Wait for the healthchecks to pass
|
||||||
@@ -82,7 +82,15 @@ jobs:
|
|||||||
require-healthy: true
|
require-healthy: true
|
||||||
|
|
||||||
- name: Run Playwright tests
|
- name: Run Playwright tests
|
||||||
run: TRILIUM_DOCKER=1 npx playwright test
|
run: TRILIUM_DOCKER=1 TRILIUM_PORT=8082 pnpm exec nx run server-e2e:e2e
|
||||||
|
|
||||||
|
- name: Upload Playwright trace
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Playwright trace (${{ matrix.dockerfile }})
|
||||||
|
path: test-output/playwright/output
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
@@ -111,6 +119,9 @@ jobs:
|
|||||||
- dockerfile: Dockerfile
|
- dockerfile: Dockerfile
|
||||||
platform: linux/arm/v7
|
platform: linux/arm/v7
|
||||||
image: ubuntu-24.04-arm
|
image: ubuntu-24.04-arm
|
||||||
|
- dockerfile: Dockerfile
|
||||||
|
platform: linux/arm/v8
|
||||||
|
image: ubuntu-24.04-arm
|
||||||
runs-on: ${{ matrix.image }}
|
runs-on: ${{ matrix.image }}
|
||||||
needs:
|
needs:
|
||||||
- test_docker
|
- test_docker
|
||||||
@@ -129,7 +140,6 @@ jobs:
|
|||||||
- name: Set TEST_TAG to lowercase
|
- name: Set TEST_TAG to lowercase
|
||||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
@@ -142,6 +152,9 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Run the TypeScript build
|
||||||
|
run: pnpm run server:build
|
||||||
|
|
||||||
- name: Update build info
|
- name: Update build info
|
||||||
run: pnpm run chore:update-build-info
|
run: pnpm run chore:update-build-info
|
||||||
|
|
||||||
@@ -184,7 +197,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: apps/server
|
context: apps/server
|
||||||
file: ${{ matrix.dockerfile }}
|
file: apps/server/${{ matrix.dockerfile }}
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,name=${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
||||||
|
|||||||
13
.github/workflows/nightly.yml
vendored
13
.github/workflows/nightly.yml
vendored
@@ -11,7 +11,8 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- .github/actions/build-electron/*
|
- .github/actions/build-electron/*
|
||||||
- forge.config.cjs
|
- .github/workflows/nightly.yml
|
||||||
|
- forge.config.ts
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -37,7 +38,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
forge_platform: darwin
|
forge_platform: darwin
|
||||||
- name: linux
|
- name: linux
|
||||||
image: ubuntu-latest
|
image: ubuntu-22.04
|
||||||
shell: bash
|
shell: bash
|
||||||
forge_platform: linux
|
forge_platform: linux
|
||||||
- name: windows
|
- name: windows
|
||||||
@@ -76,7 +77,7 @@ jobs:
|
|||||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2.3.2
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
make_latest: false
|
make_latest: false
|
||||||
@@ -91,7 +92,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
name: TriliumNextNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
name: TriliumNotes ${{ matrix.os.name }} ${{ matrix.arch }}
|
||||||
path: apps/desktop/upload
|
path: apps/desktop/upload
|
||||||
|
|
||||||
nightly-server:
|
nightly-server:
|
||||||
@@ -102,7 +103,7 @@ jobs:
|
|||||||
arch: [x64, arm64]
|
arch: [x64, arm64]
|
||||||
include:
|
include:
|
||||||
- arch: x64
|
- arch: x64
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
- arch: arm64
|
- arch: arm64
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
@@ -116,7 +117,7 @@ jobs:
|
|||||||
arch: ${{ matrix.arch }}
|
arch: ${{ matrix.arch }}
|
||||||
|
|
||||||
- name: Publish release
|
- name: Publish release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2.3.2
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
with:
|
with:
|
||||||
make_latest: false
|
make_latest: false
|
||||||
|
|||||||
6
.github/workflows/playwright.yml
vendored
6
.github/workflows/playwright.yml
vendored
@@ -3,7 +3,7 @@ name: playwright
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -33,11 +33,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
- run: npx playwright install --with-deps
|
- run: pnpm exec playwright install --with-deps
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
|
|
||||||
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
# Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
|
||||||
# - run: npx nx-cloud record -- echo Hello World
|
# - 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
|
# 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
|
# When you enable task distribution, run the e2e-ci task instead of e2e
|
||||||
- run: npx nx affected -t e2e
|
- run: pnpm exec nx affected -t e2e --exclude desktop-e2e
|
||||||
|
|||||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
forge_platform: darwin
|
forge_platform: darwin
|
||||||
- name: linux
|
- name: linux
|
||||||
image: ubuntu-latest
|
image: ubuntu-22.04
|
||||||
shell: bash
|
shell: bash
|
||||||
forge_platform: linux
|
forge_platform: linux
|
||||||
- name: windows
|
- name: windows
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
arch: [x64, arm64]
|
arch: [x64, arm64]
|
||||||
include:
|
include:
|
||||||
- arch: x64
|
- arch: x64
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
- arch: arm64
|
- arch: arm64
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
runs-on: ${{ matrix.runs-on }}
|
runs-on: ${{ matrix.runs-on }}
|
||||||
@@ -114,7 +114,7 @@ jobs:
|
|||||||
path: upload
|
path: upload
|
||||||
|
|
||||||
- name: Publish stable release
|
- name: Publish stable release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2.3.2
|
||||||
with:
|
with:
|
||||||
draft: false
|
draft: false
|
||||||
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md
|
body_path: docs/Release Notes/Release Notes/${{ github.ref_name }}.md
|
||||||
@@ -122,5 +122,5 @@ jobs:
|
|||||||
files: upload/*.*
|
files: upload/*.*
|
||||||
discussion_category_name: Announcements
|
discussion_category_name: Announcements
|
||||||
make_latest: ${{ !contains(github.ref, 'rc') }}
|
make_latest: ${{ !contains(github.ref, 'rc') }}
|
||||||
prerelease: ${{ !contains(github.ref, 'rc') }}
|
prerelease: ${{ contains(github.ref, 'rc') }}
|
||||||
token: ${{ secrets.RELEASE_PAT }}
|
token: ${{ secrets.RELEASE_PAT }}
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -44,3 +44,6 @@ upload
|
|||||||
|
|
||||||
.rollup.cache
|
.rollup.cache
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
/result
|
||||||
|
.svelte-kit
|
||||||
4
.vscode/extensions.json
vendored
4
.vscode/extensions.json
vendored
@@ -9,6 +9,8 @@
|
|||||||
"redhat.vscode-yaml",
|
"redhat.vscode-yaml",
|
||||||
"tobermory.es6-string-html",
|
"tobermory.es6-string-html",
|
||||||
"vitest.explorer",
|
"vitest.explorer",
|
||||||
"yzhang.markdown-all-in-one"
|
"yzhang.markdown-all-in-one",
|
||||||
|
"svelte.svelte-vscode",
|
||||||
|
"bradlc.vscode-tailwindcss"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -24,5 +24,9 @@
|
|||||||
},
|
},
|
||||||
"github-actions.workflows.pinned.workflows": [
|
"github-actions.workflows.pinned.workflows": [
|
||||||
".github/workflows/nightly.yml"
|
".github/workflows/nightly.yml"
|
||||||
]
|
],
|
||||||
|
"typescript.validate.enable": true,
|
||||||
|
"typescript.tsserver.experimental.enableProjectDiagnostics": true,
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||||
}
|
}
|
||||||
151
README.md
151
README.md
@@ -1,18 +1,54 @@
|
|||||||
# TriliumNext Notes
|
# Trilium Notes
|
||||||
|
|
||||||
  
|

|
||||||
|

|
||||||
|

|
||||||
|
[](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp)
|
||||||
|
|
||||||
[English](./README.md) | [Chinese](./docs/README-ZH_CN.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
|
[English](./README.md) | [Chinese](./docs/README-ZH_CN.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
|
||||||
|
|
||||||
TriliumNext Notes is an open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
|
Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
|
||||||
|
|
||||||
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
|
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for quick overview:
|
||||||
|
|
||||||
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
|
||||||
|
|
||||||
|
## 🎁 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))
|
||||||
|
* Rich WYSIWYG note editor including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
||||||
|
* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
|
||||||
|
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
||||||
|
* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
|
||||||
|
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be used for note organization, querying and advanced [scripting](https://triliumnext.github.io/Docs/Wiki/scripts)
|
||||||
|
* UI available in English, German, Spanish, French, Romanian, and Chinese (simplified and traditional)
|
||||||
|
* Direct [OpenID and TOTP integration](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/Multi-Factor%20Authentication.md) for more secure login
|
||||||
|
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization) with self-hosted sync server
|
||||||
|
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting)
|
||||||
|
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes to public internet
|
||||||
|
* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity
|
||||||
|
* Sketching diagrams, based on [Excalidraw](https://excalidraw.com/) (note type "canvas")
|
||||||
|
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations
|
||||||
|
* Mind maps, based on [Mind Elixir](https://docs.mind-elixir.com/)
|
||||||
|
* [Geo maps](./docs/User%20Guide/User%20Guide/Note%20Types/Geo%20Map.md) with location pins and GPX tracks
|
||||||
|
* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
|
||||||
|
* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation
|
||||||
|
* Scales well in both usability and performance upwards of 100 000 notes
|
||||||
|
* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets
|
||||||
|
* Built-in [dark theme](https://triliumnext.github.io/Docs/Wiki/themes), support for user themes
|
||||||
|
* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
|
||||||
|
* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
|
||||||
|
* Customizable UI (sidebar buttons, user-defined widgets, ...)
|
||||||
|
* [Metrics](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics.md), along with a [Grafana Dashboard](./docs/User%20Guide/User%20Guide/Advanced%20Usage/Metrics/grafana-dashboard.json)
|
||||||
|
|
||||||
|
✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
|
||||||
|
|
||||||
|
- [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 project is in maintenance mode](https://github.com/zadam/trilium/issues/4620)
|
[The original Trilium project is in maintenance mode](https://github.com/zadam/trilium/issues/4620).
|
||||||
|
|
||||||
### Migrating from Trilium?
|
### Migrating from Trilium?
|
||||||
|
|
||||||
@@ -20,53 +56,49 @@ There are no special migration steps to migrate from a zadam/Trilium instance to
|
|||||||
|
|
||||||
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.
|
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
|
## 💬 Discuss with us
|
||||||
|
|
||||||
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!
|
Feel free to join our official conversations. We would love to hear what features, suggestions, or issues you may have!
|
||||||
|
|
||||||
- [Matrix](https://matrix.to/#/#triliumnext:matrix.org) (For synchronous discussions)
|
- [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)
|
- The `General` Matrix room is also bridged to [XMPP](xmpp:discuss@trilium.thisgreat.party?join)
|
||||||
- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For Asynchronous discussions)
|
- [Github Discussions](https://github.com/TriliumNext/Notes/discussions) (For asynchronous discussions.)
|
||||||
- [Wiki](https://triliumnext.github.io/Docs/) (For common how-to questions and user guides)
|
- [Github Issues](https://github.com/TriliumNext/Notes/issues) (For bug reports and feature requests.)
|
||||||
|
|
||||||
## 🎁 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))
|
|
||||||
* Rich WYSIWYG note editing including e.g. tables, images and [math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown [autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
|
|
||||||
* Support for editing [notes with source code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax highlighting
|
|
||||||
* Fast and easy [navigation between notes](https://triliumnext.github.io/Docs/Wiki/note-navigation), full text search and [note hoisting](https://triliumnext.github.io/Docs/Wiki/note-hoisting)
|
|
||||||
* Seamless [note versioning](https://triliumnext.github.io/Docs/Wiki/note-revisions)
|
|
||||||
* Note [attributes](https://triliumnext.github.io/Docs/Wiki/attributes) can be used for note organization, querying and advanced [scripting](https://triliumnext.github.io/Docs/Wiki/scripts)
|
|
||||||
* Direct OpenID and TOTP integration for more secure login
|
|
||||||
* [Synchronization](https://triliumnext.github.io/Docs/Wiki/synchronization) with self-hosted sync server
|
|
||||||
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting)
|
|
||||||
* [Sharing](https://triliumnext.github.io/Docs/Wiki/sharing) (publishing) notes to public internet
|
|
||||||
* Strong [note encryption](https://triliumnext.github.io/Docs/Wiki/protected-notes) with per-note granularity
|
|
||||||
* Sketching diagrams with built-in Excalidraw (note type "canvas")
|
|
||||||
* [Relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map) and [link maps](https://triliumnext.github.io/Docs/Wiki/link-map) for visualizing notes and their relations
|
|
||||||
* [Scripting](https://triliumnext.github.io/Docs/Wiki/scripts) - see [Advanced showcases](https://triliumnext.github.io/Docs/Wiki/advanced-showcases)
|
|
||||||
* [REST API](https://triliumnext.github.io/Docs/Wiki/etapi) for automation
|
|
||||||
* Scales well in both usability and performance upwards of 100 000 notes
|
|
||||||
* Touch optimized [mobile frontend](https://triliumnext.github.io/Docs/Wiki/mobile-frontend) for smartphones and tablets
|
|
||||||
* [Night theme](https://triliumnext.github.io/Docs/Wiki/themes)
|
|
||||||
* [Evernote](https://triliumnext.github.io/Docs/Wiki/evernote-import) and [Markdown import & export](https://triliumnext.github.io/Docs/Wiki/markdown)
|
|
||||||
* [Web Clipper](https://triliumnext.github.io/Docs/Wiki/web-clipper) for easy saving of web content
|
|
||||||
|
|
||||||
✨ Check out the following third-party resources/communities for more TriliumNext related goodies:
|
|
||||||
|
|
||||||
- [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.
|
|
||||||
|
|
||||||
## 🏗 Installation
|
## 🏗 Installation
|
||||||
|
|
||||||
### Desktop
|
### Windows / MacOS
|
||||||
|
|
||||||
To use TriliumNext on your desktop machine (Linux, MacOS, and Windows) you have a few options:
|
Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
|
||||||
|
|
||||||
* Download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the ```trilium``` executable.
|
### Linux
|
||||||
* Access TriliumNext via the web interface of a server installation (see below)
|
|
||||||
* Currently only the latest versions of Chrome & Firefox are supported (and tested).
|
If your distribution is listed in the table below, use your distribution's package.
|
||||||
* TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
|
|
||||||
|
[](https://repology.org/project/triliumnext/versions)
|
||||||
|
|
||||||
|
You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable.
|
||||||
|
|
||||||
|
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
|
||||||
|
|
||||||
|
### Browser (any OS)
|
||||||
|
|
||||||
|
If you use a server installation (see below), you can directly access the web interface (which is almost identical to the desktop app).
|
||||||
|
|
||||||
|
Currently only the latest versions of Chrome & Firefox are supported (and tested).
|
||||||
|
|
||||||
### Mobile
|
### Mobile
|
||||||
|
|
||||||
@@ -80,33 +112,48 @@ See issue https://github.com/TriliumNext/Notes/issues/72 for more information on
|
|||||||
|
|
||||||
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/notes)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
To install TriliumNext on your own server (including via Docker from [Dockerhub](https://hub.docker.com/r/triliumnext/notes)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
||||||
|
|
||||||
## 📝 Documentation
|
|
||||||
|
|
||||||
[See wiki for complete list of documentation pages.](https://triliumnext.github.io/Docs)
|
|
||||||
|
|
||||||
You can also read [Patterns of personal knowledge base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge) to get some inspiration on how you might use TriliumNext.
|
|
||||||
|
|
||||||
## 💻 Contribute
|
## 💻 Contribute
|
||||||
|
|
||||||
### Code
|
### Code
|
||||||
|
|
||||||
|
Download the repository, install dependencies using `pnpm` and then run the server (available at http://localhost:8080):
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/TriliumNext/Notes.git
|
git clone https://github.com/TriliumNext/Notes.git
|
||||||
cd Notes
|
cd Notes
|
||||||
npm install
|
pnpm install
|
||||||
npm run server:start
|
pnpm run server:start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
Download the repository, install dependencies using `pnpm` and then run the environment required to edit the documentation:
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/TriliumNext/Notes.git
|
||||||
|
cd Notes
|
||||||
|
pnpm install
|
||||||
|
pnpm nx run edit-docs:edit-docs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building the Executable
|
||||||
|
Download the repository, install dependencies using `pnpm` and then build the desktop app for Windows:
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/TriliumNext/Notes.git
|
||||||
|
cd Notes
|
||||||
|
pnpm install
|
||||||
|
pnpm nx --project=desktop electron-forge:make -- --arch=x64 --platform=win32
|
||||||
```
|
```
|
||||||
|
|
||||||
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).
|
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).
|
||||||
|
|
||||||
### Documentation
|
### Developer Documentation
|
||||||
|
|
||||||
See the [documentation guide](https://github.com/TriliumNext/Notes/blob/develop/docs/Developer%20Guide/Developer%20Guide/Documentation.md) for details.
|
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
|
## 👏 Shoutouts
|
||||||
|
|
||||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
|
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
|
||||||
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. TriliumNext Notes would not be the same without it.
|
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. Trilium Notes would not be the same without it.
|
||||||
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
|
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
|
||||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map)
|
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://triliumnext.github.io/Docs/Wiki/relation-map.html) and [link maps](https://triliumnext.github.io/Docs/Wiki/note-map.html#link-map)
|
||||||
|
|
||||||
@@ -119,4 +166,6 @@ Support for the TriliumNext organization will be possible in the near future. Fo
|
|||||||
|
|
||||||
## 🔑 License
|
## 🔑 License
|
||||||
|
|
||||||
|
Copyright 2017-2025 zadam, Elian Doran, and other contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e # Fail on any command error
|
|
||||||
|
|
||||||
VERSION=`jq -r ".version" package.json`
|
|
||||||
SERIES=${VERSION:0:4}-latest
|
|
||||||
|
|
||||||
sudo docker build -t triliumnext/notes:$VERSION --network host -t triliumnext/notes:$SERIES .
|
|
||||||
|
|
||||||
if [[ $VERSION != *"beta"* ]]; then
|
|
||||||
sudo docker tag triliumnext/notes:$VERSION triliumnext/notes:latest
|
|
||||||
fi
|
|
||||||
@@ -24,7 +24,7 @@ if ! git diff-index --quiet HEAD --; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BASE_BRANCH=master
|
BASE_BRANCH=main
|
||||||
|
|
||||||
if [[ "$VERSION" == *"beta"* ]]; then
|
if [[ "$VERSION" == *"beta"* ]]; then
|
||||||
BASE_BRANCH=beta
|
BASE_BRANCH=beta
|
||||||
|
|||||||
@@ -47,11 +47,3 @@ echo "Tagging commit with $TAG"
|
|||||||
|
|
||||||
git tag $TAG
|
git tag $TAG
|
||||||
git push origin $TAG
|
git push origin $TAG
|
||||||
|
|
||||||
echo "Updating master"
|
|
||||||
|
|
||||||
git fetch
|
|
||||||
git checkout master
|
|
||||||
git reset --hard origin/master
|
|
||||||
git merge origin/develop
|
|
||||||
git push
|
|
||||||
@@ -25,9 +25,10 @@ stats() {
|
|||||||
# Print the number of existing strings on the JSON files for each locale
|
# Print the number of existing strings on the JSON files for each locale
|
||||||
s=$(number_of_keys "${paths[0]}/en/server.json")
|
s=$(number_of_keys "${paths[0]}/en/server.json")
|
||||||
c=$(number_of_keys "${paths[1]}/en/translation.json")
|
c=$(number_of_keys "${paths[1]}/en/translation.json")
|
||||||
echo "| locale |server strings |client strings |"
|
echo "| locale | server strings | client strings |"
|
||||||
echo "|--------|---------------|---------------|"
|
echo "|--------|----------------|----------------|"
|
||||||
echo "| en | ${s} | ${c} |"
|
echo "| en | ${s} | ${c} |"
|
||||||
|
echo "|--------|----------------|----------------|"
|
||||||
for locale in "${locales[@]}"; do
|
for locale in "${locales[@]}"; do
|
||||||
s=$(number_of_keys "${paths[0]}/${locale}/server.json")
|
s=$(number_of_keys "${paths[0]}/${locale}/server.json")
|
||||||
c=$(number_of_keys "${paths[1]}/${locale}/translation.json")
|
c=$(number_of_keys "${paths[1]}/${locale}/translation.json")
|
||||||
@@ -78,7 +79,10 @@ file_path="$(
|
|||||||
cd -- "$(dirname "${0}")" >/dev/null 2>&1 || exit
|
cd -- "$(dirname "${0}")" >/dev/null 2>&1 || exit
|
||||||
pwd -P
|
pwd -P
|
||||||
)"
|
)"
|
||||||
paths=("${file_path}/../translations/" "${file_path}/../src/public/translations/")
|
paths=(
|
||||||
|
"${file_path}/../../apps/server/src/assets/translations/"
|
||||||
|
"${file_path}/../../apps/client/src/translations/"
|
||||||
|
)
|
||||||
locales=(cn de es fr pt_br ro tw)
|
locales=(cn de es fr pt_br ro tw)
|
||||||
|
|
||||||
if [ $# -eq 1 ]; then
|
if [ $# -eq 1 ]; then
|
||||||
|
|||||||
@@ -1,548 +0,0 @@
|
|||||||
/*
|
|
||||||
* CKEditor 5 (v41.0.0) content styles.
|
|
||||||
* Generated on Fri, 26 Jan 2024 10:23:49 GMT.
|
|
||||||
* For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--ck-color-image-caption-background: hsl(0, 0%, 97%);
|
|
||||||
--ck-color-image-caption-text: hsl(0, 0%, 20%);
|
|
||||||
--ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
|
|
||||||
--ck-color-mention-text: hsl(341, 100%, 30%);
|
|
||||||
--ck-color-selector-caption-background: hsl(0, 0%, 97%);
|
|
||||||
--ck-color-selector-caption-text: hsl(0, 0%, 20%);
|
|
||||||
--ck-highlight-marker-blue: hsl(201, 97%, 72%);
|
|
||||||
--ck-highlight-marker-green: hsl(120, 93%, 68%);
|
|
||||||
--ck-highlight-marker-pink: hsl(345, 96%, 73%);
|
|
||||||
--ck-highlight-marker-yellow: hsl(60, 97%, 73%);
|
|
||||||
--ck-highlight-pen-green: hsl(112, 100%, 27%);
|
|
||||||
--ck-highlight-pen-red: hsl(0, 85%, 49%);
|
|
||||||
--ck-image-style-spacing: 1.5em;
|
|
||||||
--ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2);
|
|
||||||
--ck-todo-list-checkmark-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table .ck-table-resized {
|
|
||||||
table-layout: fixed;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table table {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table td,
|
|
||||||
.ck-content .table th {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table {
|
|
||||||
margin: 0.9em auto;
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px double hsl(0, 0%, 70%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table td,
|
|
||||||
.ck-content .table table th {
|
|
||||||
min-width: 2em;
|
|
||||||
padding: .4em;
|
|
||||||
border: 1px solid hsl(0, 0%, 75%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table th {
|
|
||||||
font-weight: bold;
|
|
||||||
background: hsla(0, 0%, 0%, 5%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content[dir="rtl"] .table th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content[dir="ltr"] .table th {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecaption.css */
|
|
||||||
.ck-content .table > figcaption {
|
|
||||||
display: table-caption;
|
|
||||||
caption-side: top;
|
|
||||||
word-break: break-word;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--ck-color-selector-caption-text);
|
|
||||||
background-color: var(--ck-color-selector-caption-background);
|
|
||||||
padding: .6em;
|
|
||||||
font-size: .75em;
|
|
||||||
outline-offset: -1px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break {
|
|
||||||
position: relative;
|
|
||||||
clear: both;
|
|
||||||
padding: 5px 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
border-bottom: 2px dashed hsl(0, 0%, 77%);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break__label {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
padding: .3em .6em;
|
|
||||||
display: block;
|
|
||||||
text-transform: uppercase;
|
|
||||||
border: 1px solid hsl(0, 0%, 77%);
|
|
||||||
border-radius: 2px;
|
|
||||||
font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
|
|
||||||
font-size: 0.75em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: hsl(0, 0%, 20%);
|
|
||||||
background: hsl(0, 0%, 100%);
|
|
||||||
box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-media-embed/theme/mediaembed.css */
|
|
||||||
.ck-content .media {
|
|
||||||
clear: both;
|
|
||||||
margin: 0.9em 0;
|
|
||||||
display: block;
|
|
||||||
min-width: 15em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list li {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list li .todo-list {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: var(--ck-todo-list-checkmark-size);
|
|
||||||
height: var(--ck-todo-list-checkmark-size);
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 0;
|
|
||||||
left: -25px;
|
|
||||||
margin-right: -15px;
|
|
||||||
right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content[dir=rtl] .todo-list .todo-list__label > input {
|
|
||||||
left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
right: -25px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input::before {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid hsl(0, 0%, 20%);
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: 250ms ease-in-out box-shadow;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input::after {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: content-box;
|
|
||||||
pointer-events: none;
|
|
||||||
content: '';
|
|
||||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
|
||||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input[checked]::before {
|
|
||||||
background: hsl(126, 64%, 41%);
|
|
||||||
border-color: hsl(126, 64%, 41%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input[checked]::after {
|
|
||||||
border-color: hsl(0, 0%, 100%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label .todo-list__label__description {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > input,
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > input:hover::before, .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input:hover::before {
|
|
||||||
box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: var(--ck-todo-list-checkmark-size);
|
|
||||||
height: var(--ck-todo-list-checkmark-size);
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 0;
|
|
||||||
left: -25px;
|
|
||||||
margin-right: -15px;
|
|
||||||
right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content[dir=rtl] .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
right: -25px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::before {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid hsl(0, 0%, 20%);
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: 250ms ease-in-out box-shadow;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::after {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: content-box;
|
|
||||||
pointer-events: none;
|
|
||||||
content: '';
|
|
||||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
|
||||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::before {
|
|
||||||
background: hsl(126, 64%, 41%);
|
|
||||||
border-color: hsl(126, 64%, 41%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::after {
|
|
||||||
border-color: hsl(0, 0%, 100%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol {
|
|
||||||
list-style-type: decimal;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol {
|
|
||||||
list-style-type: lower-latin;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol {
|
|
||||||
list-style-type: lower-roman;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol ol {
|
|
||||||
list-style-type: upper-latin;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol ol ol {
|
|
||||||
list-style-type: upper-roman;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul {
|
|
||||||
list-style-type: disc;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul {
|
|
||||||
list-style-type: circle;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul ul {
|
|
||||||
list-style-type: square;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul ul ul {
|
|
||||||
list-style-type: square;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image {
|
|
||||||
display: table;
|
|
||||||
clear: both;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0.9em auto;
|
|
||||||
min-width: 50px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
min-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline {
|
|
||||||
/*
|
|
||||||
* Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).;
|
|
||||||
* Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root.
|
|
||||||
* This strange behavior does not happen with inline-flex.
|
|
||||||
*/
|
|
||||||
display: inline-flex;
|
|
||||||
max-width: 100%;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline picture {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline picture,
|
|
||||||
.ck-content .image-inline img {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content img.image_resized {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized {
|
|
||||||
max-width: 100%;
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized > figcaption {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagecaption.css */
|
|
||||||
.ck-content .image > figcaption {
|
|
||||||
display: table-caption;
|
|
||||||
caption-side: bottom;
|
|
||||||
word-break: break-word;
|
|
||||||
color: var(--ck-color-image-caption-text);
|
|
||||||
background-color: var(--ck-color-image-caption-background);
|
|
||||||
padding: .6em;
|
|
||||||
font-size: .75em;
|
|
||||||
outline-offset: -1px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-left,
|
|
||||||
.ck-content .image-style-block-align-right {
|
|
||||||
max-width: calc(100% - var(--ck-image-style-spacing));
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-left,
|
|
||||||
.ck-content .image-style-align-right {
|
|
||||||
clear: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-side {
|
|
||||||
float: right;
|
|
||||||
margin-left: var(--ck-image-style-spacing);
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-left {
|
|
||||||
float: left;
|
|
||||||
margin-right: var(--ck-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-center {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-right {
|
|
||||||
float: right;
|
|
||||||
margin-left: var(--ck-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-right {
|
|
||||||
margin-right: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-left {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content p + .image-style-align-left,
|
|
||||||
.ck-content p + .image-style-align-right,
|
|
||||||
.ck-content p + .image-style-side {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-left,
|
|
||||||
.ck-content .image-inline.image-style-align-right {
|
|
||||||
margin-top: var(--ck-inline-image-style-spacing);
|
|
||||||
margin-bottom: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-left {
|
|
||||||
margin-right: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-right {
|
|
||||||
margin-left: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-yellow {
|
|
||||||
background-color: var(--ck-highlight-marker-yellow);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-green {
|
|
||||||
background-color: var(--ck-highlight-marker-green);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-pink {
|
|
||||||
background-color: var(--ck-highlight-marker-pink);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-blue {
|
|
||||||
background-color: var(--ck-highlight-marker-blue);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .pen-red {
|
|
||||||
color: var(--ck-highlight-pen-red);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .pen-green {
|
|
||||||
color: var(--ck-highlight-pen-green);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
|
|
||||||
.ck-content blockquote {
|
|
||||||
overflow: hidden;
|
|
||||||
padding-right: 1.5em;
|
|
||||||
padding-left: 1.5em;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
font-style: italic;
|
|
||||||
border-left: solid 5px hsl(0, 0%, 80%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
|
|
||||||
.ck-content[dir="rtl"] blockquote {
|
|
||||||
border-left: 0;
|
|
||||||
border-right: solid 5px hsl(0, 0%, 80%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-basic-styles/theme/code.css */
|
|
||||||
.ck-content code {
|
|
||||||
background-color: hsla(0, 0%, 78%, 0.3);
|
|
||||||
padding: .15em;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-tiny {
|
|
||||||
font-size: .7em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-small {
|
|
||||||
font-size: .85em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-big {
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-huge {
|
|
||||||
font-size: 1.8em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-mention/theme/mention.css */
|
|
||||||
.ck-content .mention {
|
|
||||||
background: var(--ck-color-mention-background);
|
|
||||||
color: var(--ck-color-mention-text);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css */
|
|
||||||
.ck-content hr {
|
|
||||||
margin: 15px 0;
|
|
||||||
height: 4px;
|
|
||||||
background: hsl(0, 0%, 87%);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
|
|
||||||
.ck-content pre {
|
|
||||||
padding: 1em;
|
|
||||||
text-align: left;
|
|
||||||
direction: ltr;
|
|
||||||
tab-size: 4;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-style: normal;
|
|
||||||
min-width: 200px;
|
|
||||||
border: 0px;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
.ck-content pre:not(.hljs) {
|
|
||||||
color: hsl(0, 0%, 20.8%);
|
|
||||||
background: hsla(0, 0%, 78%, 0.3);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
|
|
||||||
.ck-content pre code {
|
|
||||||
background: unset;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
@media print {
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break::after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,593 +0,0 @@
|
|||||||
/* !!!!!! TRILIUM CUSTOM CHANGES !!!!!! */
|
|
||||||
|
|
||||||
.printed-content .ck-widget__selection-handle, .printed-content .ck-widget__type-around { /* gets rid of triangles: https://github.com/zadam/trilium/issues/1129 */
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-break {
|
|
||||||
page-break-after: always;
|
|
||||||
}
|
|
||||||
|
|
||||||
.printed-content .page-break:after,
|
|
||||||
.printed-content .page-break > * {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ck-content li p {
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admonition {
|
|
||||||
--accent-color: var(--card-border-color);
|
|
||||||
border: 1px solid var(--accent-color);
|
|
||||||
box-shadow: var(--card-box-shadow);
|
|
||||||
background: var(--card-background-color);
|
|
||||||
border-radius: 0.5em;
|
|
||||||
padding: 1em;
|
|
||||||
margin: 1.25em 0;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admonition p:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admonition p, h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admonition.note { --accent-color: #69c7ff; }
|
|
||||||
.admonition.tip { --accent-color: #40c025; }
|
|
||||||
.admonition.important { --accent-color: #9839f7; }
|
|
||||||
.admonition.caution { --accent-color: #ff2e2e; }
|
|
||||||
.admonition.warning { --accent-color: #e2aa03; }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* CKEditor 5 (v41.0.0) content styles.
|
|
||||||
* Generated on Fri, 26 Jan 2024 10:23:49 GMT.
|
|
||||||
* For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--ck-color-image-caption-background: hsl(0, 0%, 97%);
|
|
||||||
--ck-color-image-caption-text: hsl(0, 0%, 20%);
|
|
||||||
--ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
|
|
||||||
--ck-color-mention-text: hsl(341, 100%, 30%);
|
|
||||||
--ck-color-selector-caption-background: hsl(0, 0%, 97%);
|
|
||||||
--ck-color-selector-caption-text: hsl(0, 0%, 20%);
|
|
||||||
--ck-highlight-marker-blue: hsl(201, 97%, 72%);
|
|
||||||
--ck-highlight-marker-green: hsl(120, 93%, 68%);
|
|
||||||
--ck-highlight-marker-pink: hsl(345, 96%, 73%);
|
|
||||||
--ck-highlight-marker-yellow: hsl(60, 97%, 73%);
|
|
||||||
--ck-highlight-pen-green: hsl(112, 100%, 27%);
|
|
||||||
--ck-highlight-pen-red: hsl(0, 85%, 49%);
|
|
||||||
--ck-image-style-spacing: 1.5em;
|
|
||||||
--ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2);
|
|
||||||
--ck-todo-list-checkmark-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table .ck-table-resized {
|
|
||||||
table-layout: fixed;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table table {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */
|
|
||||||
.ck-content .table td,
|
|
||||||
.ck-content .table th {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table {
|
|
||||||
margin: 0.9em auto;
|
|
||||||
display: table;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px double hsl(0, 0%, 70%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table td,
|
|
||||||
.ck-content .table table th {
|
|
||||||
min-width: 2em;
|
|
||||||
padding: .4em;
|
|
||||||
border: 1px solid hsl(0, 0%, 75%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content .table table th {
|
|
||||||
font-weight: bold;
|
|
||||||
background: hsla(0, 0%, 0%, 5%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content[dir="rtl"] .table th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/table.css */
|
|
||||||
.ck-content[dir="ltr"] .table th {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-table/theme/tablecaption.css */
|
|
||||||
.ck-content .table > figcaption {
|
|
||||||
display: table-caption;
|
|
||||||
caption-side: top;
|
|
||||||
word-break: break-word;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--ck-color-selector-caption-text);
|
|
||||||
background-color: var(--ck-color-selector-caption-background);
|
|
||||||
padding: .6em;
|
|
||||||
font-size: .75em;
|
|
||||||
outline-offset: -1px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break {
|
|
||||||
position: relative;
|
|
||||||
clear: both;
|
|
||||||
padding: 5px 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
border-bottom: 2px dashed hsl(0, 0%, 77%);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break__label {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
padding: .3em .6em;
|
|
||||||
display: block;
|
|
||||||
text-transform: uppercase;
|
|
||||||
border: 1px solid hsl(0, 0%, 77%);
|
|
||||||
border-radius: 2px;
|
|
||||||
font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
|
|
||||||
font-size: 0.75em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: hsl(0, 0%, 20%);
|
|
||||||
background: hsl(0, 0%, 100%);
|
|
||||||
box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-media-embed/theme/mediaembed.css */
|
|
||||||
.ck-content .media {
|
|
||||||
clear: both;
|
|
||||||
margin: 0.9em 0;
|
|
||||||
display: block;
|
|
||||||
min-width: 15em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list li {
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list li .todo-list {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: var(--ck-todo-list-checkmark-size);
|
|
||||||
height: var(--ck-todo-list-checkmark-size);
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 0;
|
|
||||||
left: -25px;
|
|
||||||
margin-right: -15px;
|
|
||||||
right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content[dir=rtl] .todo-list .todo-list__label > input {
|
|
||||||
left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
right: -25px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input::before {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid hsl(0, 0%, 20%);
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: 250ms ease-in-out box-shadow;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input::after {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: content-box;
|
|
||||||
pointer-events: none;
|
|
||||||
content: '';
|
|
||||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
|
||||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input[checked]::before {
|
|
||||||
background: hsl(126, 64%, 41%);
|
|
||||||
border-color: hsl(126, 64%, 41%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label > input[checked]::after {
|
|
||||||
border-color: hsl(0, 0%, 100%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label .todo-list__label__description {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > input,
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > input:hover::before, .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input:hover::before {
|
|
||||||
box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: var(--ck-todo-list-checkmark-size);
|
|
||||||
height: var(--ck-todo-list-checkmark-size);
|
|
||||||
vertical-align: middle;
|
|
||||||
border: 0;
|
|
||||||
left: -25px;
|
|
||||||
margin-right: -15px;
|
|
||||||
right: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content[dir=rtl] .todo-list .todo-list__label > span[contenteditable=false] > input {
|
|
||||||
left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
right: -25px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::before {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 1px solid hsl(0, 0%, 20%);
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: 250ms ease-in-out box-shadow;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::after {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: content-box;
|
|
||||||
pointer-events: none;
|
|
||||||
content: '';
|
|
||||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
|
||||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
|
||||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
|
||||||
border-style: solid;
|
|
||||||
border-color: transparent;
|
|
||||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::before {
|
|
||||||
background: hsl(126, 64%, 41%);
|
|
||||||
border-color: hsl(126, 64%, 41%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::after {
|
|
||||||
border-color: hsl(0, 0%, 100%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/todolist.css */
|
|
||||||
.ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol {
|
|
||||||
list-style-type: decimal;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol {
|
|
||||||
list-style-type: lower-latin;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol {
|
|
||||||
list-style-type: lower-roman;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol ol {
|
|
||||||
list-style-type: upper-latin;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ol ol ol ol ol {
|
|
||||||
list-style-type: upper-roman;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul {
|
|
||||||
list-style-type: disc;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul {
|
|
||||||
list-style-type: circle;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul ul {
|
|
||||||
list-style-type: square;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-list/theme/list.css */
|
|
||||||
.ck-content ul ul ul ul {
|
|
||||||
list-style-type: square;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image {
|
|
||||||
display: table;
|
|
||||||
clear: both;
|
|
||||||
text-align: center;
|
|
||||||
margin: 0.9em auto;
|
|
||||||
min-width: 50px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image img {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 100%;
|
|
||||||
min-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline {
|
|
||||||
/*
|
|
||||||
* Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).;
|
|
||||||
* Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root.
|
|
||||||
* This strange behavior does not happen with inline-flex.
|
|
||||||
*/
|
|
||||||
display: inline-flex;
|
|
||||||
max-width: 100%;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline picture {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/image.css */
|
|
||||||
.ck-content .image-inline picture,
|
|
||||||
.ck-content .image-inline img {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content img.image_resized {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized {
|
|
||||||
max-width: 100%;
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imageresize.css */
|
|
||||||
.ck-content .image.image_resized > figcaption {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagecaption.css */
|
|
||||||
.ck-content .image > figcaption {
|
|
||||||
display: table-caption;
|
|
||||||
caption-side: bottom;
|
|
||||||
word-break: break-word;
|
|
||||||
color: var(--ck-color-image-caption-text);
|
|
||||||
background-color: var(--ck-color-image-caption-background);
|
|
||||||
padding: .6em;
|
|
||||||
font-size: .75em;
|
|
||||||
outline-offset: -1px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-left,
|
|
||||||
.ck-content .image-style-block-align-right {
|
|
||||||
max-width: calc(100% - var(--ck-image-style-spacing));
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-left,
|
|
||||||
.ck-content .image-style-align-right {
|
|
||||||
clear: none;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-side {
|
|
||||||
float: right;
|
|
||||||
margin-left: var(--ck-image-style-spacing);
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-left {
|
|
||||||
float: left;
|
|
||||||
margin-right: var(--ck-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-center {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-align-right {
|
|
||||||
float: right;
|
|
||||||
margin-left: var(--ck-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-right {
|
|
||||||
margin-right: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-style-block-align-left {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content p + .image-style-align-left,
|
|
||||||
.ck-content p + .image-style-align-right,
|
|
||||||
.ck-content p + .image-style-side {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-left,
|
|
||||||
.ck-content .image-inline.image-style-align-right {
|
|
||||||
margin-top: var(--ck-inline-image-style-spacing);
|
|
||||||
margin-bottom: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-left {
|
|
||||||
margin-right: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-image/theme/imagestyle.css */
|
|
||||||
.ck-content .image-inline.image-style-align-right {
|
|
||||||
margin-left: var(--ck-inline-image-style-spacing);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-yellow {
|
|
||||||
background-color: var(--ck-highlight-marker-yellow);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-green {
|
|
||||||
background-color: var(--ck-highlight-marker-green);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-pink {
|
|
||||||
background-color: var(--ck-highlight-marker-pink);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .marker-blue {
|
|
||||||
background-color: var(--ck-highlight-marker-blue);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .pen-red {
|
|
||||||
color: var(--ck-highlight-pen-red);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-highlight/theme/highlight.css */
|
|
||||||
.ck-content .pen-green {
|
|
||||||
color: var(--ck-highlight-pen-green);
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
|
|
||||||
.ck-content blockquote {
|
|
||||||
overflow: hidden;
|
|
||||||
padding-right: 1.5em;
|
|
||||||
padding-left: 1.5em;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
font-style: italic;
|
|
||||||
border-left: solid 5px hsl(0, 0%, 80%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */
|
|
||||||
.ck-content[dir="rtl"] blockquote {
|
|
||||||
border-left: 0;
|
|
||||||
border-right: solid 5px hsl(0, 0%, 80%);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-basic-styles/theme/code.css */
|
|
||||||
.ck-content code {
|
|
||||||
background-color: hsla(0, 0%, 78%, 0.3);
|
|
||||||
padding: .15em;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-tiny {
|
|
||||||
font-size: .7em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-small {
|
|
||||||
font-size: .85em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-big {
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-font/theme/fontsize.css */
|
|
||||||
.ck-content .text-huge {
|
|
||||||
font-size: 1.8em;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-mention/theme/mention.css */
|
|
||||||
.ck-content .mention {
|
|
||||||
background: var(--ck-color-mention-background);
|
|
||||||
color: var(--ck-color-mention-text);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css */
|
|
||||||
.ck-content hr {
|
|
||||||
margin: 15px 0;
|
|
||||||
height: 4px;
|
|
||||||
background: hsl(0, 0%, 87%);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
|
|
||||||
.ck-content pre {
|
|
||||||
padding: 1em;
|
|
||||||
text-align: left;
|
|
||||||
direction: ltr;
|
|
||||||
tab-size: 4;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-style: normal;
|
|
||||||
min-width: 200px;
|
|
||||||
border: 0px;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
.ck-content pre:not(.hljs) {
|
|
||||||
color: hsl(0, 0%, 20.8%);
|
|
||||||
background: hsla(0, 0%, 78%, 0.3);
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-code-block/theme/codeblock.css */
|
|
||||||
.ck-content pre code {
|
|
||||||
background: unset;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
@media print {
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
/* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */
|
|
||||||
.ck-content .page-break::after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -44,7 +44,6 @@ export default tseslint.config(
|
|||||||
"dist/*",
|
"dist/*",
|
||||||
"docs/*",
|
"docs/*",
|
||||||
"demo/*",
|
"demo/*",
|
||||||
"libraries/*",
|
|
||||||
"src/public/app-dist/*",
|
"src/public/app-dist/*",
|
||||||
"src/public/app/doc_notes/*"
|
"src/public/app/doc_notes/*"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ export default [
|
|||||||
"dist/*",
|
"dist/*",
|
||||||
"docs/*",
|
"docs/*",
|
||||||
"demo/*",
|
"demo/*",
|
||||||
"libraries/*",
|
|
||||||
// TriliumNextTODO: check if we want to format packages here as well - for now skipping it
|
// TriliumNextTODO: check if we want to format packages here as well - for now skipping it
|
||||||
"packages/*",
|
"packages/*",
|
||||||
"src/public/app-dist/*",
|
"src/public/app-dist/*",
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"templates": {
|
|
||||||
"default": {
|
|
||||||
"includeDate": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,13 +35,13 @@
|
|||||||
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
"chore:generate-openapi": "tsx bin/generate-openapi.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.52.0",
|
"@playwright/test": "1.53.1",
|
||||||
"@stylistic/eslint-plugin": "4.2.0",
|
"@stylistic/eslint-plugin": "5.0.0",
|
||||||
"@types/express": "5.0.1",
|
"@types/express": "5.0.3",
|
||||||
"@types/node": "22.15.17",
|
"@types/node": "22.15.33",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
"@vitest/coverage-v8": "3.1.3",
|
"@vitest/coverage-v8": "3.2.4",
|
||||||
"eslint": "9.26.0",
|
"eslint": "9.29.0",
|
||||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
"eslint-plugin-simple-import-sort": "12.1.1",
|
||||||
"esm": "3.2.25",
|
"esm": "3.2.25",
|
||||||
"jsdoc": "4.0.4",
|
"jsdoc": "4.0.4",
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"rcedit": "4.0.1",
|
"rcedit": "4.0.1",
|
||||||
"rimraf": "6.0.1",
|
"rimraf": "6.0.1",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"typedoc": "0.28.4",
|
"typedoc": "0.28.5",
|
||||||
"typedoc-plugin-missing-exports": "4.0.0"
|
"typedoc-plugin-missing-exports": "4.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/auth/login
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"password": "1234"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
|
|
||||||
client.global.set("authToken", response.body.authToken);
|
|
||||||
%}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
GET {{triliumHost}}/etapi/app-info
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.clipperProtocolVersion === "1.0");
|
|
||||||
%}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
GET {{triliumHost}}/etapi/app-info
|
|
||||||
Authorization: Basic etapi {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.clipperProtocolVersion === "1.0");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/app-info
|
|
||||||
Authorization: Basic etapi wrong
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/app-info
|
|
||||||
Authorization: Basic wrong {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
PUT {{triliumHost}}/etapi/backup/etapi_test
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 201); %}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "forcedId{{$randomInt}}",
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!",
|
|
||||||
"dateCreated": "2023-08-21 23:38:51.123+0200",
|
|
||||||
"utcDateCreated": "2023-08-21 23:38:51.123Z"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.assert(response.body.note.noteId.startsWith("forcedId"));
|
|
||||||
client.assert(response.body.note.title == "Hello");
|
|
||||||
client.assert(response.body.note.dateCreated == "2023-08-21 23:38:51.123+0200");
|
|
||||||
client.assert(response.body.note.utcDateCreated == "2023-08-21 23:38:51.123Z");
|
|
||||||
client.assert(response.body.branch.parentNoteId == "root");
|
|
||||||
|
|
||||||
client.log(`Created note ` + response.body.note.noteId + ` and branch ` + response.body.branch.branchId);
|
|
||||||
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Clone to another location
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/branches
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"parentNoteId": "_hidden"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.assert(response.body.parentNoteId == "_hidden");
|
|
||||||
|
|
||||||
client.global.set("clonedBranchId", response.body.branchId);
|
|
||||||
|
|
||||||
client.log(`Created cloned branch ` + response.body.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.noteId == client.global.get("createdNoteId"));
|
|
||||||
client.assert(response.body.title == "Hello");
|
|
||||||
// order is not defined and may fail in the future
|
|
||||||
client.assert(response.body.parentBranchIds[0] == client.global.get("clonedBranchId"))
|
|
||||||
client.assert(response.body.parentBranchIds[1] == client.global.get("createdBranchId"));
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body == "Hi there!");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.branchId == client.global.get("createdBranchId"));
|
|
||||||
client.assert(response.body.parentNoteId == "root");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{clonedBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.branchId == client.global.get("clonedBranchId"));
|
|
||||||
client.assert(response.body.parentNoteId == "_hidden");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Content-Type: application/json
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
{
|
|
||||||
"attributeId": "forcedAttributeId{{$randomInt}}",
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.assert(response.body.attributeId.startsWith("forcedAttributeId"));
|
|
||||||
|
|
||||||
client.global.set("createdAttributeId", response.body.attributeId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.attributeId == client.global.get("createdAttributeId"));
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attachments
|
|
||||||
Content-Type: application/json
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "{{createdNoteId}}",
|
|
||||||
"role": "file",
|
|
||||||
"mime": "plain/text",
|
|
||||||
"title": "my attachment",
|
|
||||||
"content": "my text"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
|
|
||||||
client.global.set("createdAttachmentId", response.body.attachmentId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.attachmentId == client.global.get("createdAttachmentId"));
|
|
||||||
client.assert(response.body.role == "file");
|
|
||||||
client.assert(response.body.mime == "plain/text");
|
|
||||||
client.assert(response.body.title == "my attachment");
|
|
||||||
%}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attachments
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "{{createdNoteId}}",
|
|
||||||
"role": "file",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"title": "my attachment",
|
|
||||||
"content": "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttachmentId", response.body.attachmentId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
### repeat the DELETE request to test the idempotency
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "ATTACHMENT_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttributeId", response.body.attributeId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
### repeat the DELETE request to test the idempotency
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "ATTRIBUTE_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Clone to another location
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/branches
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"parentNoteId": "_hidden"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("clonedBranchId", response.body.branchId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{clonedBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
### repeat the DELETE request to test the idempotency
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "BRANCH_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{clonedBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttributeId", response.body.attributeId); %}
|
|
||||||
|
|
||||||
### Clone to another location
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/branches
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"parentNoteId": "_hidden"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("clonedBranchId", response.body.branchId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{clonedBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
### repeat the DELETE request to test the idempotency
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204, "Response status is not 204"); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "BRANCH_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{clonedBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code == "BRANCH_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "NOTE_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 404, "Response status is not 404");
|
|
||||||
client.assert(response.body.code === "ATTRIBUTE_NOT_FOUND");
|
|
||||||
%}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
GET {{triliumHost}}/etapi/notes/root/export
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.headers.valueOf("Content-Type") == "application/zip");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root/export?format=html
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.headers.valueOf("Content-Type") == "application/zip");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root/export?format=markdown
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.headers.valueOf("Content-Type") == "application/zip");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root/export?format=wrong
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code === "UNRECOGNIZED_EXPORT_FORMAT");
|
|
||||||
%}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
GET {{triliumHost}}/etapi/inbox/2022-01-01
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/days/2022-01-01
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/days/2022-1
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code === "DATE_INVALID");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/weeks/2022-01-01
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/weeks/2022-1
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code === "DATE_INVALID");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/months/2022-01
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/months/2022-1
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code === "MONTH_INVALID");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/years/2022
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/years/202
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code === "YEAR_INVALID");
|
|
||||||
%}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello parent",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.global.set("parentNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("parentBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Create inheritable parent attribute
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{parentNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "",
|
|
||||||
"isInheritable": true,
|
|
||||||
"position": 10
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.global.set("parentAttributeId", response.body.attributeId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Create child note under root
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello child",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.global.set("childNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("childBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Create child attribute
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{childNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": false,
|
|
||||||
"position": 10
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.global.set("childAttributeId", response.body.attributeId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Clone child to parent
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/branches
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{childNoteId}}",
|
|
||||||
"parentNoteId": "{{parentNoteId}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.assert(response.body.parentNoteId == client.global.get("parentNoteId"));
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{childNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
|
|
||||||
function hasAttribute(list, attributeId) {
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
|
||||||
if (list[i]["attributeId"] === attributeId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
client.log(JSON.stringify(response.body.attributes));
|
|
||||||
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.noteId == client.global.get("childNoteId"));
|
|
||||||
client.assert(response.body.attributes.length == 2);
|
|
||||||
client.assert(hasAttribute(response.body.attributes, client.global.get("parentAttributeId")));
|
|
||||||
client.assert(hasAttribute(response.body.attributes, client.global.get("childAttributeId")));
|
|
||||||
%}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "GetInheritedAttributes Test Note",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.global.set("parentNoteId", response.body.note.noteId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{parentNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttributeId", response.body.attributeId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "{{parentNoteId}}",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.noteId == client.global.get("createdNoteId"));
|
|
||||||
client.assert(response.body.attributes.length == 1);
|
|
||||||
client.assert(response.body.attributes[0].attributeId == client.global.get("createdAttributeId"));
|
|
||||||
%}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body === "Hi there!");
|
|
||||||
%}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"dev": {
|
|
||||||
"triliumHost": "http://localhost:37740"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/notes/root/import
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/octet-stream
|
|
||||||
Content-Transfer-Encoding: binary
|
|
||||||
|
|
||||||
< ../db/demo.zip
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
client.assert(response.body.note.title == "Trilium Demo");
|
|
||||||
client.assert(response.body.branch.parentNoteId == "root");
|
|
||||||
%}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/auth/login
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"password": "1234"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 201);
|
|
||||||
|
|
||||||
client.global.set("testAuthToken", response.body.authToken);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root
|
|
||||||
Authorization: {{testAuthToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/auth/logout
|
|
||||||
Authorization: {{testAuthToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root
|
|
||||||
Authorization: {{testAuthToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
GET {{triliumHost}}/etapi/notes?search=aaa
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/root
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/notes/root
|
|
||||||
Authorization: fakeauth
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/notes/root
|
|
||||||
Authorization: fakeauth
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/root
|
|
||||||
Authorization: fakeauth
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/branches/root
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/branches/root
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/000
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attributes/000
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
DELETE {{triliumHost}}/etapi/attributes/000
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/inbox/2022-02-22
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/days/2022-02-22
|
|
||||||
Authorization: fakeauth
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/weeks/2022-02-22
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/months/2022-02
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/calendar/years/2022
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/app-info
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 401); %}
|
|
||||||
|
|
||||||
### Fake URL will get a 404 even without token
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/zzzzzz
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 404); %}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/refresh-note-ordering/root
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 200); %}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attachments
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "{{createdNoteId}}",
|
|
||||||
"role": "file",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"title": "my attachment",
|
|
||||||
"content": "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttachmentId", response.body.attachmentId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"title": "CHANGED",
|
|
||||||
"position": 999
|
|
||||||
}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.body.title === "CHANGED");
|
|
||||||
client.assert(response.body.position === 999);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "root"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_NOT_ALLOWED");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"title": null
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_VALIDATION_ERROR");
|
|
||||||
%}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.global.set("createdNoteId", response.body.note.noteId);
|
|
||||||
client.global.set("createdBranchId", response.body.branch.branchId);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attributes
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "{{createdNoteId}}",
|
|
||||||
"type": "label",
|
|
||||||
"name": "mylabel",
|
|
||||||
"value": "val",
|
|
||||||
"isInheritable": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttributeId", response.body.attributeId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"value": "CHANGED"
|
|
||||||
}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.body.value === "CHANGED");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"noteId": "root"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_NOT_ALLOWED");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/attributes/{{createdAttributeId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"value": null
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_VALIDATION_ERROR");
|
|
||||||
%}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"type": "text",
|
|
||||||
"title": "Hello",
|
|
||||||
"content": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdBranchId", response.body.branch.branchId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"prefix": "pref",
|
|
||||||
"notePosition": 666,
|
|
||||||
"isExpanded": true
|
|
||||||
}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.prefix === 'pref');
|
|
||||||
client.assert(response.body.notePosition === 666);
|
|
||||||
client.assert(response.body.isExpanded === true);
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_NOT_ALLOWED");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/branches/{{createdBranchId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"prefix": 123
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_VALIDATION_ERROR");
|
|
||||||
%}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "code",
|
|
||||||
"mime": "application/json",
|
|
||||||
"content": "{}"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.title === 'Hello');
|
|
||||||
client.assert(response.body.type === 'code');
|
|
||||||
client.assert(response.body.mime === 'application/json');
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"title": "Wassup",
|
|
||||||
"type": "html",
|
|
||||||
"mime": "text/html",
|
|
||||||
"dateCreated": "2023-08-21 23:38:51.123+0200",
|
|
||||||
"utcDateCreated": "2023-08-21 23:38:51.123Z"
|
|
||||||
}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.title === 'Wassup');
|
|
||||||
client.assert(response.body.type === 'html');
|
|
||||||
client.assert(response.body.mime === 'text/html');
|
|
||||||
client.assert(response.body.dateCreated == "2023-08-21 23:38:51.123+0200");
|
|
||||||
client.assert(response.body.utcDateCreated == "2023-08-21 23:38:51.123Z");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"isProtected": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_NOT_ALLOWED");
|
|
||||||
%}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PATCH {{triliumHost}}/etapi/notes/{{createdNoteId}}
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"title": true
|
|
||||||
}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 400);
|
|
||||||
client.assert(response.body.code == "PROPERTY_VALIDATION_ERROR");
|
|
||||||
%}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "code",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/notes/{{createdNoteId}}/revision
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: text/plain
|
|
||||||
|
|
||||||
Changed content
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attachments
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "{{createdNoteId}}",
|
|
||||||
"role": "file",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"title": "my attachment",
|
|
||||||
"content": "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttachmentId", response.body.attachmentId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PUT {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/octet-stream
|
|
||||||
Content-Transfer-Encoding: binary
|
|
||||||
|
|
||||||
< ../images/icon-color.png
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "text",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST {{triliumHost}}/etapi/attachments
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"ownerId": "{{createdNoteId}}",
|
|
||||||
"role": "file",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"title": "my attachment",
|
|
||||||
"content": "text"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdAttachmentId", response.body.attachmentId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PUT {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: text/plain
|
|
||||||
|
|
||||||
Changed content
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/attachments/{{createdAttachmentId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.body === "Changed content"); %}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "image",
|
|
||||||
"mime": "image/png",
|
|
||||||
"content": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PUT {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/octet-stream
|
|
||||||
Content-Transfer-Encoding: binary
|
|
||||||
|
|
||||||
< ../images/icon-color.png
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "Hello",
|
|
||||||
"type": "code",
|
|
||||||
"mime": "text/plain",
|
|
||||||
"content": "Hi there!"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
PUT {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: text/plain
|
|
||||||
|
|
||||||
Changed content
|
|
||||||
|
|
||||||
> {% client.assert(response.status === 204); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.assert(response.body === "Changed content"); %}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
POST {{triliumHost}}/etapi/create-note
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
Content-Type: application/json
|
|
||||||
|
|
||||||
{
|
|
||||||
"parentNoteId": "root",
|
|
||||||
"title": "title",
|
|
||||||
"type": "text",
|
|
||||||
"content": "{{$uuid}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes/{{createdNoteId}}/content
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {% client.global.set("content", response.body); %}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes?search={{content}}&debug=true
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.results.length === 1);
|
|
||||||
%}
|
|
||||||
|
|
||||||
### Same but with fast search which doesn't look in the content so 0 notes should be found
|
|
||||||
|
|
||||||
GET {{triliumHost}}/etapi/notes?search={{content}}&fastSearch=true
|
|
||||||
Authorization: {{authToken}}
|
|
||||||
|
|
||||||
> {%
|
|
||||||
client.assert(response.status === 200);
|
|
||||||
client.assert(response.body.results.length === 0);
|
|
||||||
%}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/public" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/spec-es6" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/src/public/app-dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/libraries" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/libraries" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/docs" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/bin/better-sqlite3" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/data" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.flatpak-builder" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="@types/jquery" level="application" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
4
apps/client/.env
Normal file
4
apps/client/.env
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# The development license key for premium CKEditor features.
|
||||||
|
# Note: This key must only be used for the Trilium Notes project.
|
||||||
|
# Expires on: 2025-09-13
|
||||||
|
VITE_CKEDITOR_KEY=eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3NTc3MjE1OTksImp0aSI6ImFiN2E0NjZmLWJlZGMtNDNiYy1iMzU4LTk0NGQ0YWJhY2I3ZiIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsic2giLCJkcnVwYWwiXSwid2hpdGVMYWJlbCI6dHJ1ZSwiZmVhdHVyZXMiOlsiRFJVUCIsIkNNVCIsIkRPIiwiRlAiLCJTQyIsIlRPQyIsIlRQTCIsIlBPRSIsIkNDIiwiTUYiLCJTRUUiLCJFQ0giLCJFSVMiXSwidmMiOiI1MzlkOWY5YyJ9.2rvKPql4hmukyXhEtWPZ8MLxKvzPIwzCdykO653g7IxRRZy2QJpeRszElZx9DakKYZKXekVRAwQKgHxwkgbE_w
|
||||||
1
apps/client/.env.production
Normal file
1
apps/client/.env.production
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_CKEDITOR_ENABLE_INSPECTOR=false
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "@triliumnext/client",
|
"name": "@triliumnext/client",
|
||||||
"version": "0.94.0",
|
"version": "0.95.0",
|
||||||
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
|
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "TriliumNext Notes Team",
|
"name": "Trilium Notes Team",
|
||||||
"email": "contact@eliandoran.me",
|
"email": "contact@eliandoran.me",
|
||||||
"url": "https://github.com/TriliumNext/Notes"
|
"url": "https://github.com/TriliumNext/Notes"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/js": "9.26.0",
|
"@eslint/js": "9.29.0",
|
||||||
"@excalidraw/excalidraw": "0.18.0",
|
"@excalidraw/excalidraw": "0.18.0",
|
||||||
"@fullcalendar/core": "6.1.17",
|
"@fullcalendar/core": "6.1.17",
|
||||||
"@fullcalendar/daygrid": "6.1.17",
|
"@fullcalendar/daygrid": "6.1.17",
|
||||||
@@ -18,35 +18,40 @@
|
|||||||
"@fullcalendar/list": "6.1.17",
|
"@fullcalendar/list": "6.1.17",
|
||||||
"@fullcalendar/multimonth": "6.1.17",
|
"@fullcalendar/multimonth": "6.1.17",
|
||||||
"@fullcalendar/timegrid": "6.1.17",
|
"@fullcalendar/timegrid": "6.1.17",
|
||||||
"@mermaid-js/layout-elk": "0.1.7",
|
"@mermaid-js/layout-elk": "0.1.8",
|
||||||
"@mind-elixir/node-menu": "1.0.5",
|
"@mind-elixir/node-menu": "1.0.5",
|
||||||
"@popperjs/core": "2.11.8",
|
"@popperjs/core": "2.11.8",
|
||||||
"@triliumnext/ckeditor5": "workspace:*",
|
"@triliumnext/ckeditor5": "workspace:*",
|
||||||
|
"@triliumnext/codemirror": "workspace:*",
|
||||||
"@triliumnext/commons": "workspace:*",
|
"@triliumnext/commons": "workspace:*",
|
||||||
"bootstrap": "5.3.6",
|
"@triliumnext/highlightjs": "workspace:*",
|
||||||
|
"@triliumnext/share-theme": "workspace:*",
|
||||||
|
"autocomplete.js": "0.38.1",
|
||||||
|
"bootstrap": "5.3.7",
|
||||||
|
"boxicons": "2.1.4",
|
||||||
"dayjs": "1.11.13",
|
"dayjs": "1.11.13",
|
||||||
"dayjs-plugin-utc": "0.1.2",
|
"dayjs-plugin-utc": "0.1.2",
|
||||||
"debounce": "2.2.0",
|
"debounce": "2.2.0",
|
||||||
"draggabilly": "3.0.0",
|
"draggabilly": "3.0.0",
|
||||||
"eslint-linter-browserify": "9.26.0",
|
"force-graph": "1.49.6",
|
||||||
"force-graph": "1.49.5",
|
"globals": "16.2.0",
|
||||||
"globals": "16.1.0",
|
"i18next": "25.2.1",
|
||||||
"i18next": "25.1.2",
|
|
||||||
"i18next-http-backend": "3.0.2",
|
"i18next-http-backend": "3.0.2",
|
||||||
"jquery": "3.7.1",
|
"jquery": "3.7.1",
|
||||||
"jquery-hotkeys": "0.2.2",
|
"jquery-hotkeys": "0.2.2",
|
||||||
"jquery.fancytree": "2.38.5",
|
"jquery.fancytree": "2.38.5",
|
||||||
"jsplumb": "2.15.6",
|
"jsplumb": "2.15.6",
|
||||||
|
"katex": "0.16.22",
|
||||||
"knockout": "3.5.1",
|
"knockout": "3.5.1",
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
"leaflet-gpx": "2.2.0",
|
"leaflet-gpx": "2.2.0",
|
||||||
"mark.js": "8.11.1",
|
"mark.js": "8.11.1",
|
||||||
"marked": "15.0.11",
|
"marked": "15.0.12",
|
||||||
"mermaid": "11.6.0",
|
"mermaid": "11.7.0",
|
||||||
"mind-elixir": "4.5.2",
|
"mind-elixir": "4.6.1",
|
||||||
|
"normalize.css": "8.0.1",
|
||||||
"panzoom": "9.4.3",
|
"panzoom": "9.4.3",
|
||||||
"react": "19.1.0",
|
"preact": "10.26.9",
|
||||||
"react-dom": "19.1.0",
|
|
||||||
"split.js": "1.6.5",
|
"split.js": "1.6.5",
|
||||||
"svg-pan-zoom": "3.6.2",
|
"svg-pan-zoom": "3.6.2",
|
||||||
"vanilla-js-wheel-zoom": "9.0.4"
|
"vanilla-js-wheel-zoom": "9.0.4"
|
||||||
@@ -55,15 +60,25 @@
|
|||||||
"@ckeditor/ckeditor5-inspector": "4.1.0",
|
"@ckeditor/ckeditor5-inspector": "4.1.0",
|
||||||
"@types/bootstrap": "5.2.10",
|
"@types/bootstrap": "5.2.10",
|
||||||
"@types/jquery": "3.5.32",
|
"@types/jquery": "3.5.32",
|
||||||
"@types/leaflet": "1.9.17",
|
"@types/leaflet": "1.9.19",
|
||||||
"@types/leaflet-gpx": "1.3.7",
|
"@types/leaflet-gpx": "1.3.7",
|
||||||
"@types/react": "19.1.3",
|
"@types/mark.js": "8.11.12",
|
||||||
"@types/react-dom": "19.1.3",
|
|
||||||
"copy-webpack-plugin": "13.0.0",
|
"copy-webpack-plugin": "13.0.0",
|
||||||
"happy-dom": "17.4.6",
|
"happy-dom": "18.0.1",
|
||||||
"script-loader": "0.7.2"
|
"script-loader": "0.7.2",
|
||||||
|
"vite-plugin-static-copy": "3.1.0"
|
||||||
},
|
},
|
||||||
"nx": {
|
"nx": {
|
||||||
"name": "client"
|
"name": "client",
|
||||||
|
"targets": {
|
||||||
|
"serve": {
|
||||||
|
"dependsOn": [
|
||||||
|
"^build"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"circular-deps": {
|
||||||
|
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
/*
|
|
||||||
* Remove template code below
|
|
||||||
*/
|
|
||||||
html {
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
|
||||||
'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif,
|
|
||||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
|
||||||
'Noto Color Emoji';
|
|
||||||
line-height: 1.5;
|
|
||||||
tab-size: 4;
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-family: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
p,
|
|
||||||
pre {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
*,
|
|
||||||
::before,
|
|
||||||
::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-width: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: currentColor;
|
|
||||||
}
|
|
||||||
h1,
|
|
||||||
h2 {
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
||||||
'Liberation Mono', 'Courier New', monospace;
|
|
||||||
}
|
|
||||||
svg {
|
|
||||||
display: block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
shape-rendering: auto;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
background-color: rgba(55, 65, 81, 1);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
color: rgba(229, 231, 235, 1);
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
||||||
'Liberation Mono', 'Courier New', monospace;
|
|
||||||
overflow: scroll;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
box-shadow: 0 0 #0000, 0 0 #0000, 0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
|
||||||
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
.rounded {
|
|
||||||
border-radius: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-width: 768px;
|
|
||||||
padding-bottom: 3rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
#welcome {
|
|
||||||
margin-top: 2.5rem;
|
|
||||||
}
|
|
||||||
#welcome h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
#welcome span {
|
|
||||||
display: block;
|
|
||||||
font-size: 1.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 2.25rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
#hero {
|
|
||||||
align-items: center;
|
|
||||||
background-color: hsla(214, 62%, 21%, 1);
|
|
||||||
border: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
#hero .text-container {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
padding: 3rem 2rem;
|
|
||||||
}
|
|
||||||
#hero .text-container h2 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: 2rem;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#hero .text-container h2 svg {
|
|
||||||
color: hsla(162, 47%, 50%, 1);
|
|
||||||
height: 2rem;
|
|
||||||
left: -0.25rem;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 2rem;
|
|
||||||
}
|
|
||||||
#hero .text-container h2 span {
|
|
||||||
margin-left: 2.5rem;
|
|
||||||
}
|
|
||||||
#hero .text-container a {
|
|
||||||
background-color: rgba(255, 255, 255, 1);
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
display: inline-block;
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
#hero .logo-container {
|
|
||||||
display: none;
|
|
||||||
justify-content: center;
|
|
||||||
padding-left: 2rem;
|
|
||||||
padding-right: 2rem;
|
|
||||||
}
|
|
||||||
#hero .logo-container svg {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
width: 66.666667%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#middle-content {
|
|
||||||
align-items: flex-start;
|
|
||||||
display: grid;
|
|
||||||
gap: 4rem;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#learning-materials {
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
}
|
|
||||||
#learning-materials h2 {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
.list-item-link {
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.list-item-link svg:first-child {
|
|
||||||
margin-right: 1rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 1.5rem;
|
|
||||||
}
|
|
||||||
.list-item-link > span {
|
|
||||||
flex-grow: 1;
|
|
||||||
font-weight: 400;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
.list-item-link > span > span {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
display: block;
|
|
||||||
flex-grow: 1;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
.list-item-link svg:last-child {
|
|
||||||
height: 1rem;
|
|
||||||
transition-property: all;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 1rem;
|
|
||||||
}
|
|
||||||
.list-item-link:hover {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
background-color: hsla(162, 47%, 50%, 1);
|
|
||||||
}
|
|
||||||
.list-item-link:hover > span {
|
|
||||||
}
|
|
||||||
.list-item-link:hover > span > span {
|
|
||||||
color: rgba(243, 244, 246, 1);
|
|
||||||
}
|
|
||||||
.list-item-link:hover svg:last-child {
|
|
||||||
transform: translateX(0.25rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
#other-links {
|
|
||||||
}
|
|
||||||
.button-pill {
|
|
||||||
padding: 1.5rem 2rem;
|
|
||||||
transition-duration: 300ms;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.button-pill svg {
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 3rem;
|
|
||||||
}
|
|
||||||
.button-pill > span {
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
.button-pill span span {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
}
|
|
||||||
.button-pill:hover svg,
|
|
||||||
.button-pill:hover {
|
|
||||||
color: rgba(255, 255, 255, 1) !important;
|
|
||||||
}
|
|
||||||
#nx-console:hover {
|
|
||||||
background-color: rgba(0, 122, 204, 1);
|
|
||||||
}
|
|
||||||
#nx-console svg {
|
|
||||||
color: rgba(0, 122, 204, 1);
|
|
||||||
}
|
|
||||||
#nx-console-jetbrains {
|
|
||||||
margin-top: 2rem;
|
|
||||||
}
|
|
||||||
#nx-console-jetbrains:hover {
|
|
||||||
background-color: rgba(255, 49, 140, 1);
|
|
||||||
}
|
|
||||||
#nx-console-jetbrains svg {
|
|
||||||
color: rgba(255, 49, 140, 1);
|
|
||||||
}
|
|
||||||
#nx-repo:hover {
|
|
||||||
background-color: rgba(24, 23, 23, 1);
|
|
||||||
}
|
|
||||||
#nx-repo svg {
|
|
||||||
color: rgba(24, 23, 23, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nx-cloud {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
#nx-cloud > div svg {
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 3rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div h2 {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div h2 span {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
}
|
|
||||||
#nx-cloud p {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud pre {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud a {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
#nx-cloud a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#commands {
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
#commands h2 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
#commands p {
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
details {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
details pre > span {
|
|
||||||
color: rgba(181, 181, 181, 1);
|
|
||||||
}
|
|
||||||
summary {
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
display: flex;
|
|
||||||
font-weight: 400;
|
|
||||||
padding: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
summary:hover {
|
|
||||||
background-color: rgba(243, 244, 246, 1);
|
|
||||||
}
|
|
||||||
summary svg {
|
|
||||||
height: 1.5rem;
|
|
||||||
margin-right: 1rem;
|
|
||||||
width: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#love {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
opacity: 0.6;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#love svg {
|
|
||||||
color: rgba(252, 165, 165, 1);
|
|
||||||
width: 1.25rem;
|
|
||||||
height: 1.25rem;
|
|
||||||
display: inline;
|
|
||||||
margin-top: -0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
#hero {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
#hero .logo-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
#middle-content {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { AppElement } from './app.element';
|
|
||||||
|
|
||||||
describe('AppElement', () => {
|
|
||||||
let app: AppElement;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
app = new AppElement();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create successfully', () => {
|
|
||||||
expect(app).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should have a greeting', () => {
|
|
||||||
app.connectedCallback();
|
|
||||||
|
|
||||||
expect(app.querySelector('h1').innerHTML).toContain(
|
|
||||||
'Welcome @triliumnext/client'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
import './app.element.css';
|
|
||||||
|
|
||||||
export class AppElement extends HTMLElement {
|
|
||||||
public static observedAttributes = [
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
const title = '@triliumnext/client';
|
|
||||||
this.innerHTML = `
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="container">
|
|
||||||
<!-- WELCOME -->
|
|
||||||
<div id="welcome">
|
|
||||||
<h1>
|
|
||||||
<span> Hello there, </span>
|
|
||||||
Welcome ${title} 👋
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- HERO -->
|
|
||||||
<div id="hero" class="rounded">
|
|
||||||
<div class="text-container">
|
|
||||||
<h2>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>You're up and running</span>
|
|
||||||
</h2>
|
|
||||||
<a href="#commands"> What's next? </a>
|
|
||||||
</div>
|
|
||||||
<div class="logo-container">
|
|
||||||
<svg
|
|
||||||
fill="currentColor"
|
|
||||||
role="img"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- MIDDLE CONTENT -->
|
|
||||||
<div id="middle-content">
|
|
||||||
<div id="learning-materials" class="rounded shadow">
|
|
||||||
<h2>Learning materials</h2>
|
|
||||||
<a href="https://nx.dev/getting-started/intro?utm_source=nx-project" target="_blank" rel="noreferrer" class="list-item-link">
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Documentation
|
|
||||||
<span> Everything is in there </span>
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 5l7 7-7 7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a href="https://nx.dev/blog/?utm_source=nx-project" target="_blank" rel="noreferrer" class="list-item-link">
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Blog
|
|
||||||
<span> Changelog, features & events </span>
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 5l7 7-7 7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.youtube.com/@NxDevtools/videos?utm_source=nx-project&sub_confirmation=1" target="_blank" rel="noreferrer" class="list-item-link">
|
|
||||||
<svg
|
|
||||||
role="img"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<title>YouTube</title>
|
|
||||||
<path
|
|
||||||
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
YouTube channel
|
|
||||||
<span> Nx Show, talks & tutorials </span>
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 5l7 7-7 7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a href="https://nx.dev/react-tutorial/1-code-generation?utm_source=nx-project" target="_blank" rel="noreferrer" class="list-item-link">
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Interactive tutorials
|
|
||||||
<span> Create an app, step-by-step </span>
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 5l7 7-7 7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
<a href="https://nxplaybook.com/?utm_source=nx-project" target="_blank" rel="noreferrer" class="list-item-link">
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path d="M12 14l9-5-9-5-9 5 9 5z" />
|
|
||||||
<path
|
|
||||||
d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Video courses
|
|
||||||
<span> Nx custom courses </span>
|
|
||||||
</span>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M9 5l7 7-7 7"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div id="other-links">
|
|
||||||
<a id="nx-console" class="button-pill rounded shadow" href="https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console&utm_source=nx-project" target="_blank" rel="noreferrer">
|
|
||||||
<svg
|
|
||||||
fill="currentColor"
|
|
||||||
role="img"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<title>Visual Studio Code</title>
|
|
||||||
<path
|
|
||||||
d="M23.15 2.587L18.21.21a1.494 1.494 0 0 0-1.705.29l-9.46 8.63-4.12-3.128a.999.999 0 0 0-1.276.057L.327 7.261A1 1 0 0 0 .326 8.74L3.899 12 .326 15.26a1 1 0 0 0 .001 1.479L1.65 17.94a.999.999 0 0 0 1.276.057l4.12-3.128 9.46 8.63a1.492 1.492 0 0 0 1.704.29l4.942-2.377A1.5 1.5 0 0 0 24 20.06V3.939a1.5 1.5 0 0 0-.85-1.352zm-5.146 14.861L10.826 12l7.178-5.448v10.896z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Install Nx Console for VSCode
|
|
||||||
<span>The official VSCode extension for Nx.</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
id="nx-console-jetbrains"
|
|
||||||
class="button-pill rounded shadow"
|
|
||||||
href="https://plugins.jetbrains.com/plugin/21060-nx-console"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
height="48"
|
|
||||||
width="48"
|
|
||||||
viewBox="20 20 60 60"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path d="m22.5 22.5h60v60h-60z" />
|
|
||||||
<g fill="#fff">
|
|
||||||
<path d="m29.03 71.25h22.5v3.75h-22.5z" />
|
|
||||||
<path d="m28.09 38 1.67-1.58a1.88 1.88 0 0 0 1.47.87c.64 0 1.06-.44 1.06-1.31v-5.98h2.58v6a3.48 3.48 0 0 1 -.87 2.6 3.56 3.56 0 0 1 -2.57.95 3.84 3.84 0 0 1 -3.34-1.55z" />
|
|
||||||
<path d="m36 30h7.53v2.19h-5v1.44h4.49v2h-4.42v1.49h5v2.21h-7.6z" />
|
|
||||||
<path d="m47.23 32.29h-2.8v-2.29h8.21v2.27h-2.81v7.1h-2.6z" />
|
|
||||||
<path d="m29.13 43.08h4.42a3.53 3.53 0 0 1 2.55.83 2.09 2.09 0 0 1 .6 1.53 2.16 2.16 0 0 1 -1.44 2.09 2.27 2.27 0 0 1 1.86 2.29c0 1.61-1.31 2.59-3.55 2.59h-4.44zm5 2.89c0-.52-.42-.8-1.18-.8h-1.29v1.64h1.24c.79 0 1.25-.26 1.25-.81zm-.9 2.66h-1.57v1.73h1.62c.8 0 1.24-.31 1.24-.86 0-.5-.4-.87-1.27-.87z" />
|
|
||||||
<path d="m38 43.08h4.1a4.19 4.19 0 0 1 3 1 2.93 2.93 0 0 1 .9 2.19 3 3 0 0 1 -1.93 2.89l2.24 3.27h-3l-1.88-2.84h-.87v2.84h-2.56zm4 4.5c.87 0 1.39-.43 1.39-1.11 0-.75-.54-1.12-1.4-1.12h-1.44v2.26z" />
|
|
||||||
<path d="m49.59 43h2.5l4 9.44h-2.79l-.67-1.69h-3.63l-.67 1.69h-2.71zm2.27 5.73-1-2.65-1.06 2.65z" />
|
|
||||||
<path d="m56.46 43.05h2.6v9.37h-2.6z" />
|
|
||||||
<path d="m60.06 43.05h2.42l3.37 5v-5h2.57v9.37h-2.26l-3.53-5.14v5.14h-2.57z" />
|
|
||||||
<path d="m68.86 51 1.45-1.73a4.84 4.84 0 0 0 3 1.13c.71 0 1.08-.24 1.08-.65 0-.4-.31-.6-1.59-.91-2-.46-3.53-1-3.53-2.93 0-1.74 1.37-3 3.62-3a5.89 5.89 0 0 1 3.86 1.25l-1.26 1.84a4.63 4.63 0 0 0 -2.62-.92c-.63 0-.94.25-.94.6 0 .42.32.61 1.63.91 2.14.46 3.44 1.16 3.44 2.91 0 1.91-1.51 3-3.79 3a6.58 6.58 0 0 1 -4.35-1.5z" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Install Nx Console for JetBrains
|
|
||||||
<span>
|
|
||||||
Available for WebStorm, Intellij IDEA Ultimate and more!
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
<div id="nx-cloud" class="rounded shadow">
|
|
||||||
<div>
|
|
||||||
<svg id="nx-cloud-logo" role="img" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" fill="transparent" viewBox="0 0 24 24">
|
|
||||||
<path stroke-width="2" d="M23 3.75V6.5c-3.036 0-5.5 2.464-5.5 5.5s-2.464 5.5-5.5 5.5-5.5 2.464-5.5 5.5H3.75C2.232 23 1 21.768 1 20.25V3.75C1 2.232 2.232 1 3.75 1h16.5C21.768 1 23 2.232 23 3.75Z" />
|
|
||||||
<path stroke-width="2" d="M23 6v14.1667C23 21.7307 21.7307 23 20.1667 23H6c0-3.128 2.53867-5.6667 5.6667-5.6667 3.128 0 5.6666-2.5386 5.6666-5.6666C17.3333 8.53867 19.872 6 23 6Z" />
|
|
||||||
</svg>
|
|
||||||
<h2>
|
|
||||||
Nx Cloud
|
|
||||||
<span>
|
|
||||||
Enable faster CI & better DX
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
You can activate distributed tasks executions and caching by
|
|
||||||
running:
|
|
||||||
</p>
|
|
||||||
<pre>nx connect</pre>
|
|
||||||
<a href="https://nx.app/?utm_source=nx-project" target="_blank" rel="noreferrer"> What is Nx Cloud? </a>
|
|
||||||
</div>
|
|
||||||
<a id="nx-repo" class="button-pill rounded shadow" href="https://github.com/nrwl/nx?utm_source=nx-project" target="_blank" rel="noreferrer">
|
|
||||||
<svg
|
|
||||||
fill="currentColor"
|
|
||||||
role="img"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>
|
|
||||||
Nx is open source
|
|
||||||
<span> Love Nx? Give us a star! </span>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- COMMANDS -->
|
|
||||||
<div id="commands" class="rounded shadow">
|
|
||||||
<h2>Next steps</h2>
|
|
||||||
<p>Here are some things you can do with Nx:</p>
|
|
||||||
<details>
|
|
||||||
<summary>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Add UI library
|
|
||||||
</summary>
|
|
||||||
<pre><span># Generate UI lib</span>
|
|
||||||
nx g @nx/angular:lib ui
|
|
||||||
|
|
||||||
<span># Add a component</span>
|
|
||||||
nx g @nx/angular:component ui/src/lib/button</pre>
|
|
||||||
</details>
|
|
||||||
<details>
|
|
||||||
<summary>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
View interactive project graph
|
|
||||||
</summary>
|
|
||||||
<pre>nx graph</pre>
|
|
||||||
</details>
|
|
||||||
<details>
|
|
||||||
<summary>
|
|
||||||
<svg
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
Run affected commands
|
|
||||||
</summary>
|
|
||||||
<pre><span># see what's been affected by changes</span>
|
|
||||||
nx affected:graph
|
|
||||||
|
|
||||||
<span># run tests for current changes</span>
|
|
||||||
nx affected:test
|
|
||||||
|
|
||||||
<span># run e2e tests for current changes</span>
|
|
||||||
nx affected:e2e</pre>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p id="love">
|
|
||||||
Carefully crafted with
|
|
||||||
<svg
|
|
||||||
fill="currentColor"
|
|
||||||
stroke="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customElements.define('triliumnext-root', AppElement);
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,14 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>Client</title>
|
|
||||||
<base href="/" />
|
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<triliumnext-root></triliumnext-root>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import './app/app.element';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import froca from "../services/froca.js";
|
import froca from "../services/froca.js";
|
||||||
import bundleService from "../services/bundle.js";
|
|
||||||
import RootCommandExecutor from "./root_command_executor.js";
|
import RootCommandExecutor from "./root_command_executor.js";
|
||||||
import Entrypoints, { type SqlExecuteResults } from "./entrypoints.js";
|
import Entrypoints, { type SqlExecuteResults } from "./entrypoints.js";
|
||||||
import options from "../services/options.js";
|
import options from "../services/options.js";
|
||||||
@@ -27,6 +26,8 @@ import type EditableTextTypeWidget from "../widgets/type_widgets/editable_text.j
|
|||||||
import type { NativeImage, TouchBar } from "electron";
|
import type { NativeImage, TouchBar } from "electron";
|
||||||
import TouchBarComponent from "./touch_bar.js";
|
import TouchBarComponent from "./touch_bar.js";
|
||||||
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
||||||
|
import type CodeMirror from "@triliumnext/codemirror";
|
||||||
|
import { StartupChecks } from "./startup_checks.js";
|
||||||
|
|
||||||
interface Layout {
|
interface Layout {
|
||||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||||
@@ -127,6 +128,7 @@ export type CommandMappings = {
|
|||||||
openAboutDialog: CommandData;
|
openAboutDialog: CommandData;
|
||||||
hideFloatingButtons: {};
|
hideFloatingButtons: {};
|
||||||
hideLeftPane: CommandData;
|
hideLeftPane: CommandData;
|
||||||
|
showCpuArchWarning: CommandData;
|
||||||
showLeftPane: CommandData;
|
showLeftPane: CommandData;
|
||||||
hoistNote: CommandData & { noteId: string };
|
hoistNote: CommandData & { noteId: string };
|
||||||
leaveProtectedSession: CommandData;
|
leaveProtectedSession: CommandData;
|
||||||
@@ -191,7 +193,7 @@ export type CommandMappings = {
|
|||||||
ExecuteCommandData<CKTextEditor> & {
|
ExecuteCommandData<CKTextEditor> & {
|
||||||
callback?: GetTextEditorCallback;
|
callback?: GetTextEditorCallback;
|
||||||
};
|
};
|
||||||
executeWithCodeEditor: CommandData & ExecuteCommandData<CodeMirrorInstance>;
|
executeWithCodeEditor: CommandData & ExecuteCommandData<CodeMirror>;
|
||||||
/**
|
/**
|
||||||
* Called upon when attempting to retrieve the content element of a {@link NoteContext}.
|
* Called upon when attempting to retrieve the content element of a {@link NoteContext}.
|
||||||
* Generally should not be invoked manually, as it is used by {@link NoteContext.getContentElement}.
|
* Generally should not be invoked manually, as it is used by {@link NoteContext.getContentElement}.
|
||||||
@@ -278,11 +280,15 @@ export type CommandMappings = {
|
|||||||
buildIcon(name: string): NativeImage;
|
buildIcon(name: string): NativeImage;
|
||||||
};
|
};
|
||||||
refreshTouchBar: CommandData;
|
refreshTouchBar: CommandData;
|
||||||
|
reloadTextEditor: CommandData;
|
||||||
};
|
};
|
||||||
|
|
||||||
type EventMappings = {
|
type EventMappings = {
|
||||||
initialRenderComplete: {};
|
initialRenderComplete: {};
|
||||||
frocaReloaded: {};
|
frocaReloaded: {};
|
||||||
|
setLeftPaneVisibility: {
|
||||||
|
leftPaneVisible: boolean | null;
|
||||||
|
}
|
||||||
protectedSessionStarted: {};
|
protectedSessionStarted: {};
|
||||||
notesReloaded: {
|
notesReloaded: {
|
||||||
noteIds: string[];
|
noteIds: string[];
|
||||||
@@ -463,13 +469,21 @@ export class AppContext extends Component {
|
|||||||
|
|
||||||
this.tabManager.loadTabs();
|
this.tabManager.loadTabs();
|
||||||
|
|
||||||
|
const bundleService = (await import("../services/bundle.js")).default;
|
||||||
setTimeout(() => bundleService.executeStartupBundles(), 2000);
|
setTimeout(() => bundleService.executeStartupBundles(), 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
initComponents() {
|
initComponents() {
|
||||||
this.tabManager = new TabManager();
|
this.tabManager = new TabManager();
|
||||||
|
|
||||||
this.components = [this.tabManager, new RootCommandExecutor(), new Entrypoints(), new MainTreeExecutors(), new ShortcutComponent()];
|
this.components = [
|
||||||
|
this.tabManager,
|
||||||
|
new RootCommandExecutor(),
|
||||||
|
new Entrypoints(),
|
||||||
|
new MainTreeExecutors(),
|
||||||
|
new ShortcutComponent(),
|
||||||
|
new StartupChecks()
|
||||||
|
];
|
||||||
|
|
||||||
if (utils.isMobile()) {
|
if (utils.isMobile()) {
|
||||||
this.components.push(new MobileScreenSwitcherExecutor());
|
this.components.push(new MobileScreenSwitcherExecutor());
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import type { ViewScope } from "../services/link.js";
|
|||||||
import type FNote from "../entities/fnote.js";
|
import type FNote from "../entities/fnote.js";
|
||||||
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
import type TypeWidget from "../widgets/type_widgets/type_widget.js";
|
||||||
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
||||||
|
import type CodeMirror from "@triliumnext/codemirror";
|
||||||
|
import { closeActiveDialog } from "../services/dialog.js";
|
||||||
|
|
||||||
export interface SetNoteOpts {
|
export interface SetNoteOpts {
|
||||||
triggerSwitchEvent?: unknown;
|
triggerSwitchEvent?: unknown;
|
||||||
@@ -82,7 +84,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
|
|
||||||
await this.triggerEvent("beforeNoteSwitch", { noteContext: this });
|
await this.triggerEvent("beforeNoteSwitch", { noteContext: this });
|
||||||
|
|
||||||
utils.closeActiveDialog();
|
closeActiveDialog();
|
||||||
|
|
||||||
this.notePath = resolvedNotePath;
|
this.notePath = resolvedNotePath;
|
||||||
this.viewScope = opts.viewScope;
|
this.viewScope = opts.viewScope;
|
||||||
@@ -158,6 +160,9 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveToRecentNotes(resolvedNotePath: string) {
|
saveToRecentNotes(resolvedNotePath: string) {
|
||||||
|
if (options.is("databaseReadonly")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
// we include the note in the recent list only if the user stayed on the note at least 5 seconds
|
// we include the note in the recent list only if the user stayed on the note at least 5 seconds
|
||||||
if (resolvedNotePath && resolvedNotePath === this.notePath) {
|
if (resolvedNotePath && resolvedNotePath === this.notePath) {
|
||||||
@@ -253,6 +258,10 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.is("databaseReadonly")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.note.isLabelTruthy("readOnly")) {
|
if (this.note.isLabelTruthy("readOnly")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -261,14 +270,32 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the initial decision about read-only status in the viewScope
|
||||||
|
// This will be "remembered" until the viewScope is refreshed
|
||||||
|
if (!this.viewScope) {
|
||||||
|
this.resetViewScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewScope = this.viewScope!;
|
||||||
|
|
||||||
|
if (viewScope.isReadOnly === undefined) {
|
||||||
const blob = await this.note.getBlob();
|
const blob = await this.note.getBlob();
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
|
viewScope.isReadOnly = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizeLimit = this.note.type === "text" ? options.getInt("autoReadonlySizeText") : options.getInt("autoReadonlySizeCode");
|
const sizeLimit = this.note.type === "text"
|
||||||
|
? options.getInt("autoReadonlySizeText")
|
||||||
|
: options.getInt("autoReadonlySizeCode");
|
||||||
|
|
||||||
return sizeLimit && blob.contentLength > sizeLimit && !this.note.isLabelTruthy("autoReadOnlyDisabled");
|
viewScope.isReadOnly = Boolean(sizeLimit &&
|
||||||
|
blob.contentLength > sizeLimit &&
|
||||||
|
!this.note.isLabelTruthy("autoReadOnlyDisabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the cached decision, which won't change until viewScope is reset
|
||||||
|
return viewScope.isReadOnly || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
async entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||||
@@ -312,7 +339,7 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
|||||||
|
|
||||||
async getCodeEditor() {
|
async getCodeEditor() {
|
||||||
return this.timeout(
|
return this.timeout(
|
||||||
new Promise<CodeMirrorInstance>((resolve) =>
|
new Promise<CodeMirror>((resolve) =>
|
||||||
appContext.triggerCommand("executeWithCodeEditor", {
|
appContext.triggerCommand("executeWithCodeEditor", {
|
||||||
resolve,
|
resolve,
|
||||||
ntxId: this.ntxId
|
ntxId: this.ntxId
|
||||||
|
|||||||
@@ -78,15 +78,15 @@ export default class RootCommandExecutor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hideLeftPaneCommand() {
|
hideLeftPaneCommand() {
|
||||||
options.save(`leftPaneVisible`, "false");
|
appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
showLeftPaneCommand() {
|
showLeftPaneCommand() {
|
||||||
options.save(`leftPaneVisible`, "true");
|
appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLeftPaneCommand() {
|
toggleLeftPaneCommand() {
|
||||||
options.toggle("leftPaneVisible");
|
appContext.triggerEvent("setLeftPaneVisibility", { leftPaneVisible: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
async showBackendLogCommand() {
|
async showBackendLogCommand() {
|
||||||
|
|||||||
26
apps/client/src/components/startup_checks.ts
Normal file
26
apps/client/src/components/startup_checks.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import server from "../services/server";
|
||||||
|
import Component from "./component";
|
||||||
|
|
||||||
|
// TODO: Deduplicate.
|
||||||
|
interface CpuArchResponse {
|
||||||
|
isCpuArchMismatch: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StartupChecks extends Component {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.checkCpuArchMismatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkCpuArchMismatch() {
|
||||||
|
try {
|
||||||
|
const response = await server.get("system-checks") as CpuArchResponse;
|
||||||
|
if (response.isCpuArchMismatch) {
|
||||||
|
this.triggerCommand("showCpuArchWarning", {});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("Could not check CPU arch status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,9 @@ export default class TabManager extends Component {
|
|||||||
if (!appContext.isMainWindow) {
|
if (!appContext.isMainWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (options.is("databaseReadonly")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const openNoteContexts = this.noteContexts
|
const openNoteContexts = this.noteContexts
|
||||||
.map((nc) => nc.getPojoState())
|
.map((nc) => nc.getPojoState())
|
||||||
@@ -277,10 +280,18 @@ export default class TabManager extends Component {
|
|||||||
return noteContext;
|
return noteContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
async openInNewTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
async openInNewTab(targetNoteId: string, hoistedNoteId: string | null = null, activate: boolean = false) {
|
||||||
const noteContext = await this.openEmptyTab(null, hoistedNoteId || this.getActiveContext()?.hoistedNoteId);
|
const noteContext = await this.openEmptyTab(null, hoistedNoteId || this.getActiveContext()?.hoistedNoteId);
|
||||||
|
|
||||||
await noteContext.setNote(targetNoteId);
|
await noteContext.setNote(targetNoteId);
|
||||||
|
|
||||||
|
if (activate && noteContext.notePath) {
|
||||||
|
this.activateNoteContext(noteContext.ntxId, false);
|
||||||
|
await this.triggerEvent("noteSwitchedAndActivated", {
|
||||||
|
noteContext,
|
||||||
|
notePath: noteContext.notePath
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openInSameTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
async openInSameTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
||||||
@@ -677,7 +688,7 @@ export default class TabManager extends Component {
|
|||||||
const titleFragments = [
|
const titleFragments = [
|
||||||
// it helps to navigate in history if note title is included in the title
|
// it helps to navigate in history if note title is included in the title
|
||||||
await activeNoteContext.getNavigationTitle(),
|
await activeNoteContext.getNavigationTitle(),
|
||||||
"TriliumNext Notes"
|
"Trilium Notes"
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
document.title = titleFragments.join(" - ");
|
document.title = titleFragments.join(" - ");
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default class TouchBarComponent extends Component {
|
|||||||
#refreshTouchBar() {
|
#refreshTouchBar() {
|
||||||
const { TouchBar } = this.remote;
|
const { TouchBar } = this.remote;
|
||||||
const parentComponent = this.lastFocusedComponent;
|
const parentComponent = this.lastFocusedComponent;
|
||||||
let touchBar = null;
|
let touchBar: Electron.CrossProcessExports.TouchBar | null = null;
|
||||||
|
|
||||||
if (this.$activeModal?.length) {
|
if (this.$activeModal?.length) {
|
||||||
touchBar = this.#buildModalTouchBar();
|
touchBar = this.#buildModalTouchBar();
|
||||||
|
|||||||
@@ -8,9 +8,13 @@ import electronContextMenu from "./menus/electron_context_menu.js";
|
|||||||
import glob from "./services/glob.js";
|
import glob from "./services/glob.js";
|
||||||
import { t } from "./services/i18n.js";
|
import { t } from "./services/i18n.js";
|
||||||
import options from "./services/options.js";
|
import options from "./services/options.js";
|
||||||
|
import server from "./services/server.js";
|
||||||
import type ElectronRemote from "@electron/remote";
|
import type ElectronRemote from "@electron/remote";
|
||||||
import type Electron from "electron";
|
import type Electron from "electron";
|
||||||
import "./stylesheets/bootstrap.scss";
|
import "./stylesheets/bootstrap.scss";
|
||||||
|
import "boxicons/css/boxicons.min.css";
|
||||||
|
import "jquery-hotkeys";
|
||||||
|
import "autocomplete.js/index_jquery.js";
|
||||||
|
|
||||||
await appContext.earlyInit();
|
await appContext.earlyInit();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import server from "../services/server.js";
|
import server from "../services/server.js";
|
||||||
import noteAttributeCache from "../services/note_attribute_cache.js";
|
import noteAttributeCache from "../services/note_attribute_cache.js";
|
||||||
import ws from "../services/ws.js";
|
import ws from "../services/ws.js";
|
||||||
import froca from "../services/froca.js";
|
|
||||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||||
import cssClassManager from "../services/css_class_manager.js";
|
import cssClassManager from "../services/css_class_manager.js";
|
||||||
import type { Froca } from "../services/froca-interface.js";
|
import type { Froca } from "../services/froca-interface.js";
|
||||||
@@ -410,8 +409,8 @@ class FNote {
|
|||||||
const notePaths: NotePathRecord[] = this.getAllNotePaths().map((path) => ({
|
const notePaths: NotePathRecord[] = this.getAllNotePaths().map((path) => ({
|
||||||
notePath: path,
|
notePath: path,
|
||||||
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
||||||
isArchived: path.some((noteId) => froca.notes[noteId].isArchived),
|
isArchived: path.some((noteId) => this.froca.notes[noteId].isArchived),
|
||||||
isSearch: path.some((noteId) => froca.notes[noteId].type === "search"),
|
isSearch: path.some((noteId) => this.froca.notes[noteId].type === "search"),
|
||||||
isHidden: path.includes("_hidden")
|
isHidden: path.includes("_hidden")
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -789,7 +788,7 @@ class FNote {
|
|||||||
*/
|
*/
|
||||||
async getRelationTargets(name: string) {
|
async getRelationTargets(name: string) {
|
||||||
const relations = this.getRelations(name);
|
const relations = this.getRelations(name);
|
||||||
const targets = [];
|
const targets: (FNote | null)[] = [];
|
||||||
|
|
||||||
for (const relation of relations) {
|
for (const relation of relations) {
|
||||||
targets.push(await this.froca.getNote(relation.value));
|
targets.push(await this.froca.getNote(relation.value));
|
||||||
@@ -982,7 +981,7 @@ class FNote {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentNote = froca.notes[parentNoteId];
|
const parentNote = this.froca.notes[parentNoteId];
|
||||||
|
|
||||||
if (!parentNote || parentNote.type === "search") {
|
if (!parentNote || parentNote.type === "search") {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import ConfirmDialog from "../widgets/dialogs/confirm.js";
|
|||||||
import RevisionsDialog from "../widgets/dialogs/revisions.js";
|
import RevisionsDialog from "../widgets/dialogs/revisions.js";
|
||||||
import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js";
|
import DeleteNotesDialog from "../widgets/dialogs/delete_notes.js";
|
||||||
import InfoDialog from "../widgets/dialogs/info.js";
|
import InfoDialog from "../widgets/dialogs/info.js";
|
||||||
|
import IncorrectCpuArchDialog from "../widgets/dialogs/incorrect_cpu_arch.js";
|
||||||
|
|
||||||
export function applyModals(rootContainer: RootContainer) {
|
export function applyModals(rootContainer: RootContainer) {
|
||||||
rootContainer
|
rootContainer
|
||||||
@@ -45,4 +46,5 @@ export function applyModals(rootContainer: RootContainer) {
|
|||||||
.child(new InfoDialog())
|
.child(new InfoDialog())
|
||||||
.child(new ConfirmDialog())
|
.child(new ConfirmDialog())
|
||||||
.child(new PromptDialog())
|
.child(new PromptDialog())
|
||||||
|
.child(new IncorrectCpuArchDialog())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
||||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
|
||||||
|
|
||||||
(function(mod) {
|
|
||||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
||||||
mod(require("../../lib/codemirror"));
|
|
||||||
else if (typeof define == "function" && define.amd) // AMD
|
|
||||||
define(["../../lib/codemirror"], mod);
|
|
||||||
else // Plain browser env
|
|
||||||
mod(CodeMirror);
|
|
||||||
})(function(CodeMirror) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
async function validatorHtml(text, options) {
|
|
||||||
const result = /<script[^>]*>([\s\S]+)<\/script>/ig.exec(text);
|
|
||||||
|
|
||||||
if (result !== null) {
|
|
||||||
// preceding code is copied over but any (non-newline) character is replaced with space
|
|
||||||
// this will preserve line numbers etc.
|
|
||||||
const prefix = text.substr(0, result.index).replace(/./g, " ");
|
|
||||||
|
|
||||||
const js = prefix + result[1];
|
|
||||||
|
|
||||||
return await validatorJavaScript(js, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function validatorJavaScript(text, options) {
|
|
||||||
if (glob.isMobile()
|
|
||||||
|| glob.getActiveContextNote() == null
|
|
||||||
|| glob.getActiveContextNote().mime === 'application/json') {
|
|
||||||
// eslint doesn't seem to validate pure JSON well
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text.length > 20000) {
|
|
||||||
console.log("Skipping linting because of large size: ", text.length);
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const errors = await glob.linter(text, glob.getActiveContextNote().mime);
|
|
||||||
|
|
||||||
console.log(errors);
|
|
||||||
|
|
||||||
const result = [];
|
|
||||||
if (errors) {
|
|
||||||
parseErrors(errors, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeMirror.registerHelper("lint", "javascript", validatorJavaScript);
|
|
||||||
CodeMirror.registerHelper("lint", "html", validatorHtml);
|
|
||||||
|
|
||||||
function parseErrors(errors, output) {
|
|
||||||
for (const error of errors) {
|
|
||||||
const startLine = error.line - 1;
|
|
||||||
const endLine = error.endLine !== undefined ? error.endLine - 1 : startLine;
|
|
||||||
const startCol = error.column - 1;
|
|
||||||
const endCol = error.endColumn !== undefined ? error.endColumn - 1 : startCol + 1;
|
|
||||||
|
|
||||||
output.push({
|
|
||||||
message: error.message,
|
|
||||||
severity: error.severity === 1 ? "warning" : "error",
|
|
||||||
from: CodeMirror.Pos(startLine, startCol),
|
|
||||||
to: CodeMirror.Pos(endLine, endCol)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
// Source: https://github.com/codemirror/codemirror5/pull/7080/files
|
|
||||||
|
|
||||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|
||||||
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
|
|
||||||
|
|
||||||
(function (mod) {
|
|
||||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|
||||||
mod(require("../../lib/codemirror"));
|
|
||||||
else if (typeof define == "function" && define.amd) // AMD
|
|
||||||
define(["../../lib/codemirror"], mod);
|
|
||||||
else // Plain browser env
|
|
||||||
mod(CodeMirror);
|
|
||||||
})(function (CodeMirror) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
CodeMirror.defineMode("hcl", function (config) {
|
|
||||||
var indentUnit = config.indentUnit;
|
|
||||||
|
|
||||||
var keywords = {
|
|
||||||
"resource": true,
|
|
||||||
"variable": true,
|
|
||||||
"output": true,
|
|
||||||
"module": true,
|
|
||||||
"provider": true,
|
|
||||||
"data": true,
|
|
||||||
"locals": true,
|
|
||||||
"terraform": true,
|
|
||||||
"if": true,
|
|
||||||
"else": true,
|
|
||||||
"for": true,
|
|
||||||
"foreach": true,
|
|
||||||
"in": true,
|
|
||||||
"true": true,
|
|
||||||
"false": true,
|
|
||||||
"null": true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var atoms = {
|
|
||||||
"true": true,
|
|
||||||
"false": true,
|
|
||||||
"null": true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var isOperatorChar = /[+\-*&^%:=<>!|\/]/;
|
|
||||||
|
|
||||||
var curPunc;
|
|
||||||
|
|
||||||
function tokenBase(stream, state) {
|
|
||||||
var ch = stream.next();
|
|
||||||
if (ch == '"' || ch == "'" || ch == "`") {
|
|
||||||
state.tokenize = tokenString(ch);
|
|
||||||
return state.tokenize(stream, state);
|
|
||||||
}
|
|
||||||
if (/[\d\.]/.test(ch)) {
|
|
||||||
if (ch == ".") {
|
|
||||||
stream.match(/^[0-9_]+([eE][\-+]?[0-9_]+)?/);
|
|
||||||
} else {
|
|
||||||
stream.match(/^[0-9_]*\.?[0-9_]*([eE][\-+]?[0-9_]+)?/);
|
|
||||||
}
|
|
||||||
return "number";
|
|
||||||
}
|
|
||||||
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
|
||||||
curPunc = ch;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (ch == "/") {
|
|
||||||
if (stream.eat("*")) {
|
|
||||||
state.tokenize = tokenComment;
|
|
||||||
return tokenComment(stream, state);
|
|
||||||
}
|
|
||||||
if (stream.eat("/")) {
|
|
||||||
stream.skipToEnd();
|
|
||||||
return "comment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isOperatorChar.test(ch)) {
|
|
||||||
stream.eatWhile(isOperatorChar);
|
|
||||||
return "operator";
|
|
||||||
}
|
|
||||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
|
||||||
var cur = stream.current();
|
|
||||||
if (keywords.propertyIsEnumerable(cur)) {
|
|
||||||
return "keyword";
|
|
||||||
}
|
|
||||||
if (atoms.propertyIsEnumerable(cur)) return "atom";
|
|
||||||
return "variable";
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenString(quote) {
|
|
||||||
return function (stream, state) {
|
|
||||||
var escaped = false,
|
|
||||||
next,
|
|
||||||
end = false;
|
|
||||||
while ((next = stream.next()) != null) {
|
|
||||||
if (next == quote && !escaped) {
|
|
||||||
end = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
escaped = !escaped && quote != "`" && next == "\\";
|
|
||||||
}
|
|
||||||
if (end || !(escaped || quote == "`"))
|
|
||||||
state.tokenize = tokenBase;
|
|
||||||
return "string";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function tokenComment(stream, state) {
|
|
||||||
var maybeEnd = false,
|
|
||||||
ch;
|
|
||||||
while (ch = stream.next()) {
|
|
||||||
if (ch == "/" && maybeEnd) {
|
|
||||||
state.tokenize = tokenBase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
maybeEnd = (ch == "*");
|
|
||||||
}
|
|
||||||
return "comment";
|
|
||||||
}
|
|
||||||
|
|
||||||
function Context(indented, column, type, align, prev) {
|
|
||||||
this.indented = indented;
|
|
||||||
this.column = column;
|
|
||||||
this.type = type;
|
|
||||||
this.align = align;
|
|
||||||
this.prev = prev;
|
|
||||||
}
|
|
||||||
function pushContext(state, col, type) {
|
|
||||||
return state.context = new Context(state.indented, col, type, null, state.context);
|
|
||||||
}
|
|
||||||
function popContext(state) {
|
|
||||||
if (!state.context.prev) return;
|
|
||||||
var t = state.context.type;
|
|
||||||
if (t == ")" || t == "]" || t == "}")
|
|
||||||
state.indented = state.context.indented;
|
|
||||||
return state.context = state.context.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface
|
|
||||||
|
|
||||||
return {
|
|
||||||
startState: function (basecolumn) {
|
|
||||||
return {
|
|
||||||
tokenize: null,
|
|
||||||
context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
|
|
||||||
indented: 0,
|
|
||||||
startOfLine: true
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
token: function (stream, state) {
|
|
||||||
var ctx = state.context;
|
|
||||||
if (stream.sol()) {
|
|
||||||
if (ctx.align == null) ctx.align = false;
|
|
||||||
state.indented = stream.indentation();
|
|
||||||
state.startOfLine = true;
|
|
||||||
}
|
|
||||||
if (stream.eatSpace()) return null;
|
|
||||||
curPunc = null;
|
|
||||||
var style = (state.tokenize || tokenBase)(stream, state);
|
|
||||||
if (style == "comment") return style;
|
|
||||||
if (ctx.align == null) ctx.align = true;
|
|
||||||
|
|
||||||
if (curPunc == "{") pushContext(state, stream.column(), "}");
|
|
||||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
|
||||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
|
||||||
else if (curPunc == "}" && ctx.type == "}") popContext(state);
|
|
||||||
else if (curPunc == ctx.type) popContext(state);
|
|
||||||
state.startOfLine = false;
|
|
||||||
return style;
|
|
||||||
},
|
|
||||||
|
|
||||||
indent: function (state, textAfter) {
|
|
||||||
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
|
|
||||||
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
|
|
||||||
if (firstChar == "#" || firstChar == ";") return 0;
|
|
||||||
if (stream.sol()) {
|
|
||||||
if (ctx.type == "case" && /^(?:case|default)\b/.test(textAfter)) {
|
|
||||||
state.context.type = "}";
|
|
||||||
return ctx.indented;
|
|
||||||
}
|
|
||||||
var closing = firstChar == ctx.type;
|
|
||||||
if (ctx.align) return ctx.column + (closing ? 0 : 1);
|
|
||||||
else return ctx.indented + (closing ? 0 : indentUnit);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
electricChars: "{}):",
|
|
||||||
closeBrackets: "()[]{}''\"\"``",
|
|
||||||
fold: "brace",
|
|
||||||
blockCommentStart: "/*",
|
|
||||||
blockCommentEnd: "*/",
|
|
||||||
lineComment: "//"
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeMirror.defineMIME("text/x-hcl", "hcl");
|
|
||||||
CodeMirror.modeInfo.push({
|
|
||||||
ext: [ "hcl " ],
|
|
||||||
mime: "text/x-hcl",
|
|
||||||
mode: "hcl",
|
|
||||||
name: "Terraform (HCL)"
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* highlight.js terraform syntax highlighting definition
|
|
||||||
*
|
|
||||||
* @see https://github.com/highlightjs/highlight.js
|
|
||||||
*
|
|
||||||
* :TODO:
|
|
||||||
*
|
|
||||||
* @package: highlightjs-terraform
|
|
||||||
* @author: Nikos Tsirmirakis <nikos.tsirmirakis@winopsdba.com>
|
|
||||||
* @since: 2019-03-20
|
|
||||||
*
|
|
||||||
* Description: Terraform (HCL) language definition
|
|
||||||
* Category: scripting
|
|
||||||
*/
|
|
||||||
|
|
||||||
var module = module ? module : {}; // shim for browser use
|
|
||||||
|
|
||||||
function hljsDefineTerraform(hljs) {
|
|
||||||
var NUMBERS = {
|
|
||||||
className: 'number',
|
|
||||||
begin: '\\b\\d+(\\.\\d+)?',
|
|
||||||
relevance: 0
|
|
||||||
};
|
|
||||||
var STRINGS = {
|
|
||||||
className: 'string',
|
|
||||||
begin: '"',
|
|
||||||
end: '"',
|
|
||||||
contains: [{
|
|
||||||
className: 'variable',
|
|
||||||
begin: '\\${',
|
|
||||||
end: '\\}',
|
|
||||||
relevance: 9,
|
|
||||||
contains: [{
|
|
||||||
className: 'string',
|
|
||||||
begin: '"',
|
|
||||||
end: '"'
|
|
||||||
}, {
|
|
||||||
className: 'meta',
|
|
||||||
begin: '[A-Za-z_0-9]*' + '\\(',
|
|
||||||
end: '\\)',
|
|
||||||
contains: [
|
|
||||||
NUMBERS, {
|
|
||||||
className: 'string',
|
|
||||||
begin: '"',
|
|
||||||
end: '"',
|
|
||||||
contains: [{
|
|
||||||
className: 'variable',
|
|
||||||
begin: '\\${',
|
|
||||||
end: '\\}',
|
|
||||||
contains: [{
|
|
||||||
className: 'string',
|
|
||||||
begin: '"',
|
|
||||||
end: '"',
|
|
||||||
contains: [{
|
|
||||||
className: 'variable',
|
|
||||||
begin: '\\${',
|
|
||||||
end: '\\}'
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
className: 'meta',
|
|
||||||
begin: '[A-Za-z_0-9]*' + '\\(',
|
|
||||||
end: '\\)'
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
'self']
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
aliases: ['tf', 'hcl'],
|
|
||||||
keywords: 'resource variable provider output locals module data terraform|10',
|
|
||||||
literal: 'false true null',
|
|
||||||
contains: [
|
|
||||||
hljs.COMMENT('\\#', '$'),
|
|
||||||
NUMBERS,
|
|
||||||
STRINGS
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hljs.registerLanguage('terraform', hljsDefineTerraform);
|
|
||||||
@@ -192,12 +192,16 @@ class ContextMenu {
|
|||||||
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
||||||
// might be handled again by top-level menu
|
// might be handled again by top-level menu
|
||||||
return false;
|
return false;
|
||||||
})
|
});
|
||||||
.on("mouseup", (e) =>{
|
|
||||||
|
$item.on("mouseup", (e) => {
|
||||||
|
// Prevent submenu from failing to expand on mobile
|
||||||
|
if (!this.isMobile || !("items" in item && item.items)) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
|
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
|
||||||
this.hide();
|
this.hide();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import appContext from "./components/app_context.js";
|
|||||||
import noteAutocompleteService from "./services/note_autocomplete.js";
|
import noteAutocompleteService from "./services/note_autocomplete.js";
|
||||||
import glob from "./services/glob.js";
|
import glob from "./services/glob.js";
|
||||||
import "./stylesheets/bootstrap.scss";
|
import "./stylesheets/bootstrap.scss";
|
||||||
|
import "boxicons/css/boxicons.min.css";
|
||||||
|
import "autocomplete.js/index_jquery.js";
|
||||||
|
|
||||||
glob.setupGlobs();
|
glob.setupGlobs();
|
||||||
|
|
||||||
|
|||||||
5
apps/client/src/runtime.ts
Normal file
5
apps/client/src/runtime.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import $ from "jquery";
|
||||||
|
(window as any).$ = $;
|
||||||
|
(window as any).jQuery = $;
|
||||||
|
|
||||||
|
$("body").show();
|
||||||
@@ -8,7 +8,7 @@ interface Entity {
|
|||||||
export interface EntityChange {
|
export interface EntityChange {
|
||||||
id?: number | null;
|
id?: number | null;
|
||||||
noteId?: string;
|
noteId?: string;
|
||||||
entityName: EntityRowNames;
|
entityName: EntityType;
|
||||||
entityId: string;
|
entityId: string;
|
||||||
entity?: Entity;
|
entity?: Entity;
|
||||||
positions?: Record<string, number>;
|
positions?: Record<string, number>;
|
||||||
@@ -22,3 +22,5 @@ export interface EntityChange {
|
|||||||
changeId?: string | null;
|
changeId?: string | null;
|
||||||
instanceId?: string | null;
|
instanceId?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type EntityType = "notes" | "branches" | "attributes" | "note_reordering" | "revisions" | "options" | "attachments" | "blobs" | "etapi_tokens";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import ScriptContext from "./script_context.js";
|
import ScriptContext from "./script_context.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import toastService from "./toast.js";
|
import toastService, { showError } from "./toast.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
@@ -37,7 +37,9 @@ async function executeBundle(bundle: Bundle, originEntity?: Entity | null, $cont
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
const note = await froca.getNote(bundle.noteId);
|
const note = await froca.getNote(bundle.noteId);
|
||||||
|
|
||||||
toastService.showAndLogError(`Execution of JS note "${note?.title}" with ID ${bundle.noteId} failed with error: ${e?.message}`);
|
const message = `Execution of JS note "${note?.title}" with ID ${bundle.noteId} failed with error: ${e?.message}`;
|
||||||
|
showError(message);
|
||||||
|
logError(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import froca from "./froca.js";
|
|||||||
import linkService from "./link.js";
|
import linkService from "./link.js";
|
||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
|
import { throwError } from "./ws.js";
|
||||||
|
|
||||||
let clipboardBranchIds: string[] = [];
|
let clipboardBranchIds: string[] = [];
|
||||||
let clipboardMode: string | null = null;
|
let clipboardMode: string | null = null;
|
||||||
@@ -36,7 +37,7 @@ async function pasteAfter(afterBranchId: string) {
|
|||||||
|
|
||||||
// copy will keep clipboardBranchIds and clipboardMode, so it's possible to paste into multiple places
|
// copy will keep clipboardBranchIds and clipboardMode, so it's possible to paste into multiple places
|
||||||
} else {
|
} else {
|
||||||
toastService.throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ async function pasteInto(parentBranchId: string) {
|
|||||||
|
|
||||||
// copy will keep clipboardBranchIds and clipboardMode, so it's possible to paste into multiple places
|
// copy will keep clipboardBranchIds and clipboardMode, so it's possible to paste into multiple places
|
||||||
} else {
|
} else {
|
||||||
toastService.throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +80,7 @@ async function copy(branchIds: string[]) {
|
|||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
// https://github.com/zadam/trilium/issues/2401
|
// https://github.com/zadam/trilium/issues/2401
|
||||||
const { clipboard } = require("electron");
|
const { clipboard } = require("electron");
|
||||||
const links = [];
|
const links: string[] = [];
|
||||||
|
|
||||||
for (const branch of froca.getBranches(clipboardBranchIds)) {
|
for (const branch of froca.getBranches(clipboardBranchIds)) {
|
||||||
const $link = await linkService.createLink(`${branch.parentNoteId}/${branch.noteId}`, { referenceLink: true });
|
const $link = await linkService.createLink(`${branch.parentNoteId}/${branch.noteId}`, { referenceLink: true });
|
||||||
|
|||||||
37
apps/client/src/services/clipboard_ext.ts
Normal file
37
apps/client/src/services/clipboard_ext.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
export function copyText(text: string) {
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(text);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Fallback method: https://stackoverflow.com/a/72239825
|
||||||
|
const textArea = document.createElement("textarea");
|
||||||
|
textArea.value = text;
|
||||||
|
try {
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.focus();
|
||||||
|
textArea.select();
|
||||||
|
return document.execCommand('copy');
|
||||||
|
} finally {
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function copyTextWithToast(text: string) {
|
||||||
|
const t = (await import("./i18n.js")).t;
|
||||||
|
const toast = (await import("./toast.js")).default;
|
||||||
|
|
||||||
|
if (copyText(text)) {
|
||||||
|
toast.showMessage(t("clipboard.copy_success"));
|
||||||
|
} else {
|
||||||
|
toast.showError(t("clipboard.copy_failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import renderService from "./render.js";
|
import renderService from "./render.js";
|
||||||
import protectedSessionService from "./protected_session.js";
|
import protectedSessionService from "./protected_session.js";
|
||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
import libraryLoader from "./library_loader.js";
|
|
||||||
import openService from "./open.js";
|
import openService from "./open.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
@@ -10,12 +9,13 @@ import treeService from "./tree.js";
|
|||||||
import FNote from "../entities/fnote.js";
|
import FNote from "../entities/fnote.js";
|
||||||
import FAttachment from "../entities/fattachment.js";
|
import FAttachment from "../entities/fattachment.js";
|
||||||
import imageContextMenuService from "../menus/image_context_menu.js";
|
import imageContextMenuService from "../menus/image_context_menu.js";
|
||||||
import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_highlight.js";
|
import { applySingleBlockSyntaxHighlight, formatCodeBlocks } from "./syntax_highlight.js";
|
||||||
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
|
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
|
||||||
import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
|
|
||||||
import renderDoc from "./doc_renderer.js";
|
import renderDoc from "./doc_renderer.js";
|
||||||
import { t } from "i18next";
|
import { t } from "../services/i18n.js";
|
||||||
import WheelZoom from 'vanilla-js-wheel-zoom';
|
import WheelZoom from 'vanilla-js-wheel-zoom';
|
||||||
|
import { renderMathInElement } from "./math.js";
|
||||||
|
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||||
|
|
||||||
let idCounter = 1;
|
let idCounter = 1;
|
||||||
|
|
||||||
@@ -94,8 +94,6 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
|
|||||||
$renderedContent.append($('<div class="ck-content">').html(blob.content));
|
$renderedContent.append($('<div class="ck-content">').html(blob.content));
|
||||||
|
|
||||||
if ($renderedContent.find("span.math-tex").length > 0) {
|
if ($renderedContent.find("span.math-tex").length > 0) {
|
||||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
|
||||||
|
|
||||||
renderMathInElement($renderedContent[0], { trust: true });
|
renderMathInElement($renderedContent[0], { trust: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +106,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
|
|||||||
await linkService.loadReferenceLinkTitle($(el));
|
await linkService.loadReferenceLinkTitle($(el));
|
||||||
}
|
}
|
||||||
|
|
||||||
await applySyntaxHighlight($renderedContent);
|
await formatCodeBlocks($renderedContent);
|
||||||
} else if (note instanceof FNote) {
|
} else if (note instanceof FNote) {
|
||||||
await renderChildrenList($renderedContent, note);
|
await renderChildrenList($renderedContent, note);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,41 @@
|
|||||||
|
import { Modal } from "bootstrap";
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions } from "../widgets/dialogs/confirm.js";
|
import type { ConfirmDialogOptions, ConfirmDialogResult, ConfirmWithMessageOptions } from "../widgets/dialogs/confirm.js";
|
||||||
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
import type { PromptDialogOptions } from "../widgets/dialogs/prompt.js";
|
||||||
|
import { focusSavedElement, saveFocusedElement } from "./focus.js";
|
||||||
|
|
||||||
|
export async function openDialog($dialog: JQuery<HTMLElement>, closeActDialog = true) {
|
||||||
|
if (closeActDialog) {
|
||||||
|
closeActiveDialog();
|
||||||
|
glob.activeDialog = $dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveFocusedElement();
|
||||||
|
Modal.getOrCreateInstance($dialog[0]).show();
|
||||||
|
|
||||||
|
$dialog.on("hidden.bs.modal", () => {
|
||||||
|
const $autocompleteEl = $(".aa-input");
|
||||||
|
if ("autocomplete" in $autocompleteEl) {
|
||||||
|
$autocompleteEl.autocomplete("close");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glob.activeDialog || glob.activeDialog === $dialog) {
|
||||||
|
focusSavedElement();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const keyboardActionsService = (await import("./keyboard_actions.js")).default;
|
||||||
|
keyboardActionsService.updateDisplayedShortcuts($dialog);
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeActiveDialog() {
|
||||||
|
if (glob.activeDialog) {
|
||||||
|
Modal.getOrCreateInstance(glob.activeDialog[0]).hide();
|
||||||
|
glob.activeDialog = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function info(message: string) {
|
async function info(message: string) {
|
||||||
return new Promise((res) => appContext.triggerCommand("showInfoDialog", { message, callback: res }));
|
return new Promise((res) => appContext.triggerCommand("showInfoDialog", { message, callback: res }));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type FNote from "../entities/fnote.js";
|
import type FNote from "../entities/fnote.js";
|
||||||
import { getCurrentLanguage } from "./i18n.js";
|
import { getCurrentLanguage } from "./i18n.js";
|
||||||
import { applySyntaxHighlight } from "./syntax_highlight.js";
|
import { formatCodeBlocks } from "./syntax_highlight.js";
|
||||||
|
|
||||||
export default function renderDoc(note: FNote) {
|
export default function renderDoc(note: FNote) {
|
||||||
return new Promise<JQuery<HTMLElement>>((resolve) => {
|
return new Promise<JQuery<HTMLElement>>((resolve) => {
|
||||||
@@ -41,12 +41,13 @@ function processContent(url: string, $content: JQuery<HTMLElement>) {
|
|||||||
$img.attr("src", dir + "/" + $img.attr("src"));
|
$img.attr("src", dir + "/" + $img.attr("src"));
|
||||||
});
|
});
|
||||||
|
|
||||||
applySyntaxHighlight($content);
|
formatCodeBlocks($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUrl(docNameValue: string, language: string) {
|
function getUrl(docNameValue: string, language: string) {
|
||||||
// Cannot have spaces in the URL due to how JQuery.load works.
|
// Cannot have spaces in the URL due to how JQuery.load works.
|
||||||
docNameValue = docNameValue.replaceAll(" ", "%20");
|
docNameValue = docNameValue.replaceAll(" ", "%20");
|
||||||
|
|
||||||
return `${window.glob.appPath}/doc_notes/${language}/${docNameValue}.html`;
|
const basePath = window.glob.isDev ? new URL(window.glob.assetPath).pathname : window.glob.assetPath;
|
||||||
|
return `${basePath}/doc_notes/${language}/${docNameValue}.html`;
|
||||||
}
|
}
|
||||||
|
|||||||
29
apps/client/src/services/focus.ts
Normal file
29
apps/client/src/services/focus.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
let $lastFocusedElement: JQuery<HTMLElement> | null;
|
||||||
|
|
||||||
|
// perhaps there should be saved focused element per tab?
|
||||||
|
export function saveFocusedElement() {
|
||||||
|
$lastFocusedElement = $(":focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function focusSavedElement() {
|
||||||
|
if (!$lastFocusedElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lastFocusedElement.hasClass("ck")) {
|
||||||
|
// must handle CKEditor separately because of this bug: https://github.com/ckeditor/ckeditor5/issues/607
|
||||||
|
// the bug manifests itself in resetting the cursor position to the first character - jumping above
|
||||||
|
|
||||||
|
const editor = $lastFocusedElement.closest(".ck-editor__editable").prop("ckeditorInstance");
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
editor.editing.view.focus();
|
||||||
|
} else {
|
||||||
|
console.log("Could not find CKEditor instance to focus last element");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$lastFocusedElement.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastFocusedElement = null;
|
||||||
|
}
|
||||||
@@ -245,6 +245,10 @@ class FrocaImpl implements Froca {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getNotes(noteIds: string[] | JQuery<string>, silentNotFoundError = false): Promise<FNote[]> {
|
async getNotes(noteIds: string[] | JQuery<string>, silentNotFoundError = false): Promise<FNote[]> {
|
||||||
|
if (noteIds.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
noteIds = Array.from(new Set(noteIds)); // make unique
|
noteIds = Array.from(new Set(noteIds)); // make unique
|
||||||
const missingNoteIds = noteIds.filter((noteId) => !this.notes[noteId]);
|
const missingNoteIds = noteIds.filter((noteId) => !this.notes[noteId]);
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
|
|||||||
} else if (ec.entityName === "attachments") {
|
} else if (ec.entityName === "attachments") {
|
||||||
processAttachment(loadResults, ec);
|
processAttachment(loadResults, ec);
|
||||||
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
|
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
|
||||||
// NOOP
|
// NOOP - these entities are handled at the backend level and don't require frontend processing
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unknown entityName '${ec.entityName}'`);
|
throw new Error(`Unknown entityName '${ec.entityName}'`);
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
|
|||||||
// To this we count: standard parent-child relationships and template/inherit relations (attribute inheritance follows them).
|
// To this we count: standard parent-child relationships and template/inherit relations (attribute inheritance follows them).
|
||||||
// Here we watch for changes which might violate this principle - e.g., an introduction of a new "inherit" relation might
|
// Here we watch for changes which might violate this principle - e.g., an introduction of a new "inherit" relation might
|
||||||
// mean we need to load the target of the relation (and then perhaps transitively the whole note path of this target).
|
// mean we need to load the target of the relation (and then perhaps transitively the whole note path of this target).
|
||||||
const missingNoteIds = [];
|
const missingNoteIds: string[] = [];
|
||||||
|
|
||||||
for (const { entityName, entity } of entityChanges) {
|
for (const { entityName, entity } of entityChanges) {
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import libraryLoader from "./library_loader.js";
|
|
||||||
import ws from "./ws.js";
|
import ws from "./ws.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import linkService from "./link.js";
|
import linkService from "./link.js";
|
||||||
import { lint } from "./eslint.js";
|
|
||||||
|
|
||||||
function setupGlobs() {
|
function setupGlobs() {
|
||||||
window.glob.isDesktop = utils.isDesktop;
|
window.glob.isDesktop = utils.isDesktop;
|
||||||
@@ -18,8 +16,6 @@ function setupGlobs() {
|
|||||||
|
|
||||||
// required for ESLint plugin and CKEditor
|
// required for ESLint plugin and CKEditor
|
||||||
window.glob.getActiveContextNote = () => appContext.tabManager.getActiveContextNote();
|
window.glob.getActiveContextNote = () => appContext.tabManager.getActiveContextNote();
|
||||||
window.glob.requireLibrary = libraryLoader.requireLibrary;
|
|
||||||
window.glob.linter = lint;
|
|
||||||
window.glob.appContext = appContext; // for debugging
|
window.glob.appContext = appContext; // for debugging
|
||||||
window.glob.froca = froca;
|
window.glob.froca = froca;
|
||||||
window.glob.treeCache = froca; // compatibility for CKEditor builds for a while
|
window.glob.treeCache = froca; // compatibility for CKEditor builds for a while
|
||||||
@@ -30,12 +26,18 @@ function setupGlobs() {
|
|||||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||||
const string = String(msg).toLowerCase();
|
const string = String(msg).toLowerCase();
|
||||||
|
|
||||||
|
let errorObjectString = "";
|
||||||
|
try {
|
||||||
|
errorObjectString = JSON.stringify(error);
|
||||||
|
} catch (e: any) {
|
||||||
|
errorObjectString = e.toString();
|
||||||
|
}
|
||||||
let message = "Uncaught error: ";
|
let message = "Uncaught error: ";
|
||||||
|
|
||||||
if (string.includes("script error")) {
|
if (string.includes("script error")) {
|
||||||
message += "No details available";
|
message += "No details available";
|
||||||
} else {
|
} else {
|
||||||
message += [`Message: ${msg}`, `URL: ${url}`, `Line: ${lineNo}`, `Column: ${columnNo}`, `Error object: ${JSON.stringify(error)}`, `Stack: ${error && error.stack}`].join(", ");
|
message += [`Message: ${msg}`, `URL: ${url}`, `Line: ${lineNo}`, `Column: ${columnNo}`, `Error object: ${errorObjectString}`, `Stack: ${error && error.stack}`].join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.logError(message);
|
ws.logError(message);
|
||||||
@@ -66,7 +68,7 @@ function setupGlobs() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const appCssNoteId of glob.appCssNoteIds || []) {
|
for (const appCssNoteId of glob.appCssNoteIds || []) {
|
||||||
libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`, false);
|
requireCss(`api/notes/download/${appCssNoteId}`, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.initHelpButtons($(window));
|
utils.initHelpButtons($(window));
|
||||||
@@ -78,6 +80,18 @@ function setupGlobs() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function requireCss(url: string, prependAssetPath = true) {
|
||||||
|
const cssLinks = Array.from(document.querySelectorAll("link")).map((el) => el.href);
|
||||||
|
|
||||||
|
if (!cssLinks.some((l) => l.endsWith(url))) {
|
||||||
|
if (prependAssetPath) {
|
||||||
|
url = `${window.glob.assetPath}/${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("head").append($('<link rel="stylesheet" type="text/css" />').attr("href", url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
setupGlobs
|
setupGlobs
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { LOCALES } from "@triliumnext/commons";
|
import { LOCALES } from "@triliumnext/commons";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
describe("i18n", () => {
|
describe("i18n", () => {
|
||||||
it("translations are valid JSON", () => {
|
it("translations are valid JSON", () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
import toastService from "./toast.js";
|
import toastService, { showError } from "./toast.js";
|
||||||
|
|
||||||
function copyImageReferenceToClipboard($imageWrapper: JQuery<HTMLElement>) {
|
function copyImageReferenceToClipboard($imageWrapper: JQuery<HTMLElement>) {
|
||||||
try {
|
try {
|
||||||
@@ -11,7 +11,9 @@ function copyImageReferenceToClipboard($imageWrapper: JQuery<HTMLElement>) {
|
|||||||
if (success) {
|
if (success) {
|
||||||
toastService.showMessage(t("image.copied-to-clipboard"));
|
toastService.showMessage(t("image.copied-to-clipboard"));
|
||||||
} else {
|
} else {
|
||||||
toastService.showAndLogError(t("image.cannot-copy"));
|
const message = t("image.cannot-copy");
|
||||||
|
showError(message);
|
||||||
|
logError(message);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
window.getSelection()?.removeAllRanges();
|
window.getSelection()?.removeAllRanges();
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ function updateDisplayedShortcuts($container: JQuery<HTMLElement>) {
|
|||||||
export default {
|
export default {
|
||||||
updateDisplayedShortcuts,
|
updateDisplayedShortcuts,
|
||||||
setupActionsForElement,
|
setupActionsForElement,
|
||||||
|
getAction,
|
||||||
getActions,
|
getActions,
|
||||||
getActionsForScope
|
getActionsForScope
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,158 +0,0 @@
|
|||||||
import mimeTypesService from "./mime_types.js";
|
|
||||||
import optionsService from "./options.js";
|
|
||||||
import { getStylesheetUrl } from "./syntax_highlight.js";
|
|
||||||
|
|
||||||
export interface Library {
|
|
||||||
js?: string[] | (() => string[]);
|
|
||||||
css?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const CODE_MIRROR: Library = {
|
|
||||||
js: () => {
|
|
||||||
const scriptsToLoad = [
|
|
||||||
"node_modules/codemirror/lib/codemirror.js",
|
|
||||||
"node_modules/codemirror/addon/display/placeholder.js",
|
|
||||||
"node_modules/codemirror/addon/edit/matchbrackets.js",
|
|
||||||
"node_modules/codemirror/addon/edit/matchtags.js",
|
|
||||||
"node_modules/codemirror/addon/fold/xml-fold.js",
|
|
||||||
"node_modules/codemirror/addon/lint/lint.js",
|
|
||||||
"node_modules/codemirror/addon/mode/loadmode.js",
|
|
||||||
"node_modules/codemirror/addon/mode/multiplex.js",
|
|
||||||
"node_modules/codemirror/addon/mode/overlay.js",
|
|
||||||
"node_modules/codemirror/addon/mode/simple.js",
|
|
||||||
"node_modules/codemirror/addon/search/match-highlighter.js",
|
|
||||||
"node_modules/codemirror/mode/meta.js",
|
|
||||||
"node_modules/codemirror/keymap/vim.js",
|
|
||||||
"libraries/codemirror/eslint.js"
|
|
||||||
];
|
|
||||||
|
|
||||||
const mimeTypes = mimeTypesService.getMimeTypes();
|
|
||||||
for (const mimeType of mimeTypes) {
|
|
||||||
if (mimeType.enabled && mimeType.codeMirrorSource) {
|
|
||||||
scriptsToLoad.push(mimeType.codeMirrorSource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return scriptsToLoad;
|
|
||||||
},
|
|
||||||
css: ["node_modules/codemirror/lib/codemirror.css", "node_modules/codemirror/addon/lint/lint.css"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const KATEX: Library = {
|
|
||||||
js: ["node_modules/katex/dist/katex.min.js", "node_modules/katex/dist/contrib/mhchem.min.js", "node_modules/katex/dist/contrib/auto-render.min.js"],
|
|
||||||
css: ["node_modules/katex/dist/katex.min.css"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const HIGHLIGHT_JS: Library = {
|
|
||||||
js: () => {
|
|
||||||
const mimeTypes = mimeTypesService.getMimeTypes();
|
|
||||||
const scriptsToLoad = new Set<string>();
|
|
||||||
scriptsToLoad.add("node_modules/@highlightjs/cdn-assets/highlight.min.js");
|
|
||||||
for (const mimeType of mimeTypes) {
|
|
||||||
const id = mimeType.highlightJs;
|
|
||||||
if (!mimeType.enabled || !id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mimeType.highlightJsSource === "libraries") {
|
|
||||||
scriptsToLoad.add(`libraries/highlightjs/${id}.js`);
|
|
||||||
} else {
|
|
||||||
// Built-in module.
|
|
||||||
scriptsToLoad.add(`node_modules/@highlightjs/cdn-assets/languages/${id}.min.js`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentTheme = String(optionsService.get("codeBlockTheme"));
|
|
||||||
loadHighlightingTheme(currentTheme);
|
|
||||||
|
|
||||||
return Array.from(scriptsToLoad);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
async function requireLibrary(library: Library) {
|
|
||||||
if (library.css) {
|
|
||||||
library.css.map((cssUrl) => requireCss(cssUrl));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (library.js) {
|
|
||||||
for (const scriptUrl of await unwrapValue(library.js)) {
|
|
||||||
await requireScript(scriptUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function unwrapValue<T>(value: T | (() => T) | Promise<T>) {
|
|
||||||
if (value && typeof value === "object" && "then" in value) {
|
|
||||||
return (await (value as Promise<() => T>))();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "function") {
|
|
||||||
return (value as () => T)();
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we save the promises in case of the same script being required concurrently multiple times
|
|
||||||
const loadedScriptPromises: Record<string, JQuery.jqXHR> = {};
|
|
||||||
|
|
||||||
async function requireScript(url: string) {
|
|
||||||
url = `${window.glob.assetPath}/${url}`;
|
|
||||||
|
|
||||||
if (!loadedScriptPromises[url]) {
|
|
||||||
loadedScriptPromises[url] = $.ajax({
|
|
||||||
url: url,
|
|
||||||
dataType: "script",
|
|
||||||
cache: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadedScriptPromises[url];
|
|
||||||
}
|
|
||||||
|
|
||||||
async function requireCss(url: string, prependAssetPath = true) {
|
|
||||||
const cssLinks = Array.from(document.querySelectorAll("link")).map((el) => el.href);
|
|
||||||
|
|
||||||
if (!cssLinks.some((l) => l.endsWith(url))) {
|
|
||||||
if (prependAssetPath) {
|
|
||||||
url = `${window.glob.assetPath}/${url}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
$("head").append($('<link rel="stylesheet" type="text/css" />').attr("href", url));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let highlightingThemeEl: JQuery<HTMLElement> | null = null;
|
|
||||||
function loadHighlightingTheme(theme: string) {
|
|
||||||
if (!theme) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theme === "none") {
|
|
||||||
// Deactivate the theme.
|
|
||||||
if (highlightingThemeEl) {
|
|
||||||
highlightingThemeEl.remove();
|
|
||||||
highlightingThemeEl = null;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!highlightingThemeEl) {
|
|
||||||
highlightingThemeEl = $(`<link rel="stylesheet" type="text/css" />`);
|
|
||||||
$("head").append(highlightingThemeEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = getStylesheetUrl(theme);
|
|
||||||
if (url) {
|
|
||||||
highlightingThemeEl.attr("href", url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
requireCss,
|
|
||||||
requireLibrary,
|
|
||||||
loadHighlightingTheme,
|
|
||||||
CODE_MIRROR,
|
|
||||||
KATEX,
|
|
||||||
HIGHLIGHT_JS
|
|
||||||
};
|
|
||||||
@@ -16,4 +16,29 @@ describe("Link", () => {
|
|||||||
const output = parseNavigationStateFromUrl(`#root/WWaBNf3SSA1b/mQ2tIzLVFKHL`);
|
const output = parseNavigationStateFromUrl(`#root/WWaBNf3SSA1b/mQ2tIzLVFKHL`);
|
||||||
expect(output).toMatchObject({ notePath: "root/WWaBNf3SSA1b/mQ2tIzLVFKHL", noteId: "mQ2tIzLVFKHL" });
|
expect(output).toMatchObject({ notePath: "root/WWaBNf3SSA1b/mQ2tIzLVFKHL", noteId: "mQ2tIzLVFKHL" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("parses notePath with spaces", () => {
|
||||||
|
const output = parseNavigationStateFromUrl(` #root/WWaBNf3SSA1b/mQ2tIzLVFKHL`);
|
||||||
|
expect(output).toMatchObject({ notePath: "root/WWaBNf3SSA1b/mQ2tIzLVFKHL", noteId: "mQ2tIzLVFKHL" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("parses notePath with extraWindow", () => {
|
||||||
|
const output = parseNavigationStateFromUrl(`127.0.0.1:8080/?extraWindow=1#root/QZGqKB7wVZF8?ntxId=0XPvXG`);
|
||||||
|
expect(output).toMatchObject({ notePath: "root/QZGqKB7wVZF8", noteId: "QZGqKB7wVZF8" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores external URL with internal hash anchor", () => {
|
||||||
|
const output = parseNavigationStateFromUrl(`https://en.wikipedia.org/wiki/Bearded_Collie#Health`);
|
||||||
|
expect(output).toMatchObject({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores malformed but hash-containing external URL", () => {
|
||||||
|
const output = parseNavigationStateFromUrl("https://abc.com/#drop?searchString=firefox");
|
||||||
|
expect(output).toStrictEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores non-hash internal path", () => {
|
||||||
|
const output = parseNavigationStateFromUrl("/root/abc123");
|
||||||
|
expect(output).toStrictEqual({});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -48,6 +48,13 @@ export interface ViewScope {
|
|||||||
viewMode?: ViewMode;
|
viewMode?: ViewMode;
|
||||||
attachmentId?: string;
|
attachmentId?: string;
|
||||||
readOnlyTemporarilyDisabled?: boolean;
|
readOnlyTemporarilyDisabled?: boolean;
|
||||||
|
/**
|
||||||
|
* If true, it indicates that the note in the view should be opened in read-only mode (for supported note types such as text or code).
|
||||||
|
*
|
||||||
|
* The reason why we store this information here is that a note can become read-only as the user types content in it, and we wouldn't want
|
||||||
|
* to immediately enter read-only mode.
|
||||||
|
*/
|
||||||
|
isReadOnly?: boolean;
|
||||||
highlightsListPreviousVisible?: boolean;
|
highlightsListPreviousVisible?: boolean;
|
||||||
highlightsListTemporarilyHidden?: boolean;
|
highlightsListTemporarilyHidden?: boolean;
|
||||||
tocTemporarilyHidden?: boolean;
|
tocTemporarilyHidden?: boolean;
|
||||||
@@ -58,6 +65,7 @@ export interface ViewScope {
|
|||||||
* toc will appear and then close immediately, because getToc(html) function will consume time
|
* toc will appear and then close immediately, because getToc(html) function will consume time
|
||||||
*/
|
*/
|
||||||
tocPreviousVisible?: boolean;
|
tocPreviousVisible?: boolean;
|
||||||
|
tocCollapsedHeadings?: Set<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateLinkOptions {
|
interface CreateLinkOptions {
|
||||||
@@ -203,20 +211,26 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url = url.trim();
|
||||||
const hashIdx = url.indexOf("#");
|
const hashIdx = url.indexOf("#");
|
||||||
if (hashIdx === -1) {
|
if (hashIdx === -1) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exclude external links that contain #
|
||||||
|
if (hashIdx !== 0 && !url.includes("/#root") && !url.includes("/#?searchString") && !url.includes("/?extraWindow")) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const hash = url.substr(hashIdx + 1); // strip also the initial '#'
|
const hash = url.substr(hashIdx + 1); // strip also the initial '#'
|
||||||
let [notePath, paramString] = hash.split("?");
|
let [notePath, paramString] = hash.split("?");
|
||||||
|
|
||||||
const viewScope: ViewScope = {
|
const viewScope: ViewScope = {
|
||||||
viewMode: "default"
|
viewMode: "default"
|
||||||
};
|
};
|
||||||
let ntxId = null;
|
let ntxId: string | null = null;
|
||||||
let hoistedNoteId = null;
|
let hoistedNoteId: string | null = null;
|
||||||
let searchString = null;
|
let searchString: string | null = null;
|
||||||
|
|
||||||
if (paramString) {
|
if (paramString) {
|
||||||
for (const pair of paramString.split("&")) {
|
for (const pair of paramString.split("&")) {
|
||||||
@@ -271,8 +285,10 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent
|
|||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
|
|
||||||
if (hrefLink?.startsWith("#fn") && $link) {
|
if (hrefLink && hrefLink.startsWith("#") && !hrefLink.startsWith("#root/") && $link) {
|
||||||
return handleFootnote(hrefLink, $link);
|
if (handleAnchor(hrefLink, $link)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { notePath, viewScope } = parseNavigationStateFromUrl(hrefLink);
|
const { notePath, viewScope } = parseNavigationStateFromUrl(hrefLink);
|
||||||
@@ -334,18 +350,19 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scrolls to either the footnote (if clicking on a reference such as `[1]`), or to the reference of a footnote (if clicking on the footnote `^` arrow).
|
* Scrolls to either the footnote (if clicking on a reference such as `[1]`), or to the reference of a footnote (if clicking on the footnote `^` arrow),
|
||||||
|
* or CKEditor bookmarks.
|
||||||
*
|
*
|
||||||
* @param hrefLink the URL of the link that was clicked (it should be in the form of `#fn` or `#fnref`).
|
* @param hrefLink the URL of the link that was clicked (it should be in the form of `#fn` or `#fnref`).
|
||||||
* @param $link the element of the link that was clicked.
|
* @param $link the element of the link that was clicked.
|
||||||
* @returns whether the event should be consumed or not.
|
* @returns `true` if the link was handled (i.e., the element was found and scrolled to), `false` otherwise.
|
||||||
*/
|
*/
|
||||||
function handleFootnote(hrefLink: string, $link: JQuery<HTMLElement>) {
|
function handleAnchor(hrefLink: string, $link: JQuery<HTMLElement>) {
|
||||||
const el = $link.closest(".ck-content").find(hrefLink)[0];
|
const el = $link.closest(".ck-content").find(hrefLink)[0];
|
||||||
if (el) {
|
if (el) {
|
||||||
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
el.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
}
|
}
|
||||||
return true;
|
return !!el;
|
||||||
}
|
}
|
||||||
|
|
||||||
function linkContextMenu(e: PointerEvent) {
|
function linkContextMenu(e: PointerEvent) {
|
||||||
|
|||||||
@@ -44,10 +44,7 @@ interface OptionRow {}
|
|||||||
|
|
||||||
interface NoteReorderingRow {}
|
interface NoteReorderingRow {}
|
||||||
|
|
||||||
interface ContentNoteIdToComponentIdRow {
|
|
||||||
noteId: string;
|
|
||||||
componentId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type EntityRowMappings = {
|
type EntityRowMappings = {
|
||||||
notes: NoteRow;
|
notes: NoteRow;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user