mirror of
https://github.com/zadam/trilium.git
synced 2025-12-26 18:19:57 +01:00
Compare commits
311 Commits
feat/llm-t
...
feature/el
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f6912cd57 | ||
|
|
d32dbf40f8 | ||
|
|
1dfcf960d3 | ||
|
|
9bdc51a3fb | ||
|
|
dbf3bcfacf | ||
|
|
3d5b269315 | ||
|
|
48f97da9cc | ||
|
|
9c954fbd81 | ||
|
|
c6bd41654f | ||
|
|
d65a74bb23 | ||
|
|
ff08bca042 | ||
|
|
a5d3d2e3b4 | ||
|
|
496a0667ee | ||
|
|
9be688b667 | ||
|
|
f3d9008c61 | ||
|
|
649a43c978 | ||
|
|
50568704ca | ||
|
|
b66b4dec83 | ||
|
|
8d0e807435 | ||
|
|
bf05ed7caf | ||
|
|
b5080eff00 | ||
|
|
c474769dd6 | ||
|
|
a6ae01da0b | ||
|
|
2bf4c44dbf | ||
|
|
5ca0fbba13 | ||
|
|
4cd84b2019 | ||
|
|
c502a45cf5 | ||
|
|
9e66914306 | ||
|
|
d33d27ee82 | ||
|
|
e2b13573ae | ||
|
|
ec74f5f1de | ||
|
|
5dee56debc | ||
|
|
5623fc992d | ||
|
|
1d28bfc570 | ||
|
|
084327e973 | ||
|
|
b2885efdc1 | ||
|
|
b65a75f138 | ||
|
|
0ee7f50bb4 | ||
|
|
02ce21bc18 | ||
|
|
3ba487bb00 | ||
|
|
384a89b0e3 | ||
|
|
e7fd9371b6 | ||
|
|
aa83429816 | ||
|
|
221ab02c24 | ||
|
|
0c4b751e8f | ||
|
|
43fd0924a1 | ||
|
|
7a036fc777 | ||
|
|
54efa6b38c | ||
|
|
6e37c9ee5a | ||
|
|
963f4586f3 | ||
|
|
4d0edebed3 | ||
|
|
cb39e8d0f8 | ||
|
|
a336f472b8 | ||
|
|
0a097e72be | ||
|
|
077f10af7b | ||
|
|
9317658fc7 | ||
|
|
21a13f2124 | ||
|
|
db6658c05f | ||
|
|
653af0bc06 | ||
|
|
93c5281af7 | ||
|
|
ce28fbc968 | ||
|
|
eb41c45711 | ||
|
|
17ab14e098 | ||
|
|
a42f7b4ece | ||
|
|
c7d69fa66b | ||
|
|
1da5c083ee | ||
|
|
4fb911da40 | ||
|
|
881417f860 | ||
|
|
9748b8bf94 | ||
|
|
337326da2b | ||
|
|
a088134d9b | ||
|
|
e49100f3f4 | ||
|
|
3c638e1574 | ||
|
|
9131edf021 | ||
|
|
52a1318475 | ||
|
|
5a7483d7c7 | ||
|
|
41f2748829 | ||
|
|
66bd5268ca | ||
|
|
ebef134af7 | ||
|
|
1173bf22ab | ||
|
|
e8f6828168 | ||
|
|
02c9339f9c | ||
|
|
c72bf42684 | ||
|
|
f42eeb7ee8 | ||
|
|
3d876121cc | ||
|
|
f9bcd7d90a | ||
|
|
b3af14fccb | ||
|
|
d224f33913 | ||
|
|
3a5f33ba91 | ||
|
|
e1ae8701b2 | ||
|
|
aff5a4d0d5 | ||
|
|
17467a9c29 | ||
|
|
ebed661863 | ||
|
|
c2e9f4764b | ||
|
|
7e5b87f00a | ||
|
|
70182e863c | ||
|
|
f0d30c4e34 | ||
|
|
013e7a6aa4 | ||
|
|
1b25b18d9e | ||
|
|
72ff384187 | ||
|
|
bac048f60f | ||
|
|
d8d0a64134 | ||
|
|
b2db87db4e | ||
|
|
1baaee582e | ||
|
|
9212b72351 | ||
|
|
24af820477 | ||
|
|
6c4c2d22c6 | ||
|
|
2e9b20be71 | ||
|
|
3216de5d89 | ||
|
|
4bf7cb8099 | ||
|
|
4871dbd7ef | ||
|
|
e125809fe0 | ||
|
|
27b80b573f | ||
|
|
38d6ae87b6 | ||
|
|
1a7cbc13e0 | ||
|
|
8e4691d4a4 | ||
|
|
b371337ed2 | ||
|
|
4d4b76ce39 | ||
|
|
289d3e9882 | ||
|
|
a57eb8f27f | ||
|
|
27023f1fd5 | ||
|
|
20a152993f | ||
|
|
ba7636db75 | ||
|
|
e3e51a2e1f | ||
|
|
93b601fe98 | ||
|
|
203ebb0e7a | ||
|
|
041c2e5693 | ||
|
|
258c0d511e | ||
|
|
15705553c7 | ||
|
|
27f023e399 | ||
|
|
0d2242171c | ||
|
|
0c62ecda65 | ||
|
|
7cd7fec93b | ||
|
|
cfab5e6217 | ||
|
|
0c313e8b8f | ||
|
|
61366061e6 | ||
|
|
b2c0685c09 | ||
|
|
e3ee284e91 | ||
|
|
58901855af | ||
|
|
c7f8a49c47 | ||
|
|
10685fe183 | ||
|
|
9e514fe95e | ||
|
|
f28a319e26 | ||
|
|
decfb58142 | ||
|
|
415bbc3b0a | ||
|
|
5b669ca287 | ||
|
|
1700217241 | ||
|
|
f00c0d5d73 | ||
|
|
64ce0d2911 | ||
|
|
82dce7a0d3 | ||
|
|
b94f67aa72 | ||
|
|
1ff77a1464 | ||
|
|
adb0e1e844 | ||
|
|
2043a06a48 | ||
|
|
738ebb66ac | ||
|
|
abf1f6c041 | ||
|
|
7db0e90506 | ||
|
|
400f9cf911 | ||
|
|
2d3b99c959 | ||
|
|
fd1ea05c78 | ||
|
|
d7c4b8f530 | ||
|
|
238f358d6a | ||
|
|
50afdca150 | ||
|
|
b5555d94f5 | ||
|
|
3d81633214 | ||
|
|
5db7997a17 | ||
|
|
71dd428919 | ||
|
|
a20d66a6b5 | ||
|
|
3caefa5409 | ||
|
|
a6e56be55a | ||
|
|
6d582f09be | ||
|
|
40cd46cd09 | ||
|
|
3cc59149cf | ||
|
|
e659266d62 | ||
|
|
14e09f5ea0 | ||
|
|
11f6462a31 | ||
|
|
48eebbe2fe | ||
|
|
f7093c035b | ||
|
|
b25e9cdee6 | ||
|
|
5cd7e4707a | ||
|
|
861374bb87 | ||
|
|
d3519b3059 | ||
|
|
da1f18c60f | ||
|
|
b7482f2a6a | ||
|
|
fd616cafca | ||
|
|
b262a5181f | ||
|
|
adb54a9054 | ||
|
|
5eb05f5550 | ||
|
|
2950c5eaa4 | ||
|
|
16fd67c070 | ||
|
|
9e3559f97c | ||
|
|
83eea30ea0 | ||
|
|
6ceccf1c7a | ||
|
|
31e1c4c712 | ||
|
|
fa97ec6c72 | ||
|
|
cd5467bf5c | ||
|
|
899f85f4e7 | ||
|
|
7c79fbefa6 | ||
|
|
18c6fe7ebd | ||
|
|
6f6643d758 | ||
|
|
356adebbce | ||
|
|
5c8e4fd6fd | ||
|
|
5be9bb47a7 | ||
|
|
60c5dc525b | ||
|
|
abfffcec07 | ||
|
|
09b12052f0 | ||
|
|
78bb0ab016 | ||
|
|
4cd4c2f607 | ||
|
|
f95b5d6f14 | ||
|
|
4a53be1e33 | ||
|
|
cbbe845d7b | ||
|
|
b2b52e92a4 | ||
|
|
15a97a4675 | ||
|
|
a01f25ec12 | ||
|
|
2f175765ec | ||
|
|
6a7ae72b1b | ||
|
|
e396bb1641 | ||
|
|
baedac4746 | ||
|
|
268ef626ca | ||
|
|
40c7ad4b46 | ||
|
|
54f9ce87f9 | ||
|
|
12b8a70e5c | ||
|
|
acf204d0e3 | ||
|
|
ee19f9ccaa | ||
|
|
34c0cf33b9 | ||
|
|
34ec624e46 | ||
|
|
056d3f9f36 | ||
|
|
040673af0b | ||
|
|
48fb0c5e21 | ||
|
|
4c1a55708f | ||
|
|
6e1951b356 | ||
|
|
3dd6b05d2e | ||
|
|
05f1ae01f3 | ||
|
|
3975041798 | ||
|
|
3a29d65777 | ||
|
|
d975790e79 | ||
|
|
4d28df7a89 | ||
|
|
bd6c690160 | ||
|
|
c0d7278827 | ||
|
|
f9eb0a20f7 | ||
|
|
8d27a5aa39 | ||
|
|
90f9416524 | ||
|
|
a593ce7c40 | ||
|
|
31fbf2cb57 | ||
|
|
c0d3027e65 | ||
|
|
bde270b73f | ||
|
|
edd18b53d0 | ||
|
|
2ad4b26c9e | ||
|
|
f39a5c55ba | ||
|
|
0af5feab79 | ||
|
|
68dd54a100 | ||
|
|
7a0f148d28 | ||
|
|
958b1592f8 | ||
|
|
7ac0828ae7 | ||
|
|
f7e7b38551 | ||
|
|
33e3112290 | ||
|
|
2a40d6bb7e | ||
|
|
f196a78728 | ||
|
|
523c7ac273 | ||
|
|
ce324586f8 | ||
|
|
35bd210062 | ||
|
|
0cfe3351bb | ||
|
|
7202f47716 | ||
|
|
bde4545afc | ||
|
|
b3c81ce5f2 | ||
|
|
02b0d1fb5e | ||
|
|
87d9ea06f3 | ||
|
|
a4e6a964c9 | ||
|
|
79c5d479fc | ||
|
|
8f0a9f91c1 | ||
|
|
93fae9cc8c | ||
|
|
134c869b07 | ||
|
|
beb0487513 | ||
|
|
aa9ffb8f6b | ||
|
|
18eb704b81 | ||
|
|
83fb62d4df | ||
|
|
cb650b70cb | ||
|
|
d5e42318dd | ||
|
|
24ed474c8c | ||
|
|
a9c25b4edd | ||
|
|
c89737ae7b | ||
|
|
e619a6ef7c | ||
|
|
583ab8dc92 | ||
|
|
db1619af31 | ||
|
|
22740a6c8d | ||
|
|
e9409577db | ||
|
|
9cef8c8e70 | ||
|
|
53bcec602d | ||
|
|
a62f12b427 | ||
|
|
e20816a7ce | ||
|
|
58535df676 | ||
|
|
057040af06 | ||
|
|
c603783a44 | ||
|
|
1928356ad5 | ||
|
|
e53ad2c62a | ||
|
|
bca397e3e4 | ||
|
|
164feaa3ec | ||
|
|
4d09fabad8 | ||
|
|
04913394c6 | ||
|
|
f8b563704f | ||
|
|
5d9bd0f6d3 | ||
|
|
1229c26098 | ||
|
|
77818d5453 | ||
|
|
2d358342c5 | ||
|
|
6c79be881d | ||
|
|
51a8937c64 | ||
|
|
c436455b32 | ||
|
|
18f89b979d | ||
|
|
8094259c78 | ||
|
|
b4f503b81e | ||
|
|
4db04519bd |
22
.github/actions/build-electron/action.yml
vendored
22
.github/actions/build-electron/action.yml
vendored
@@ -162,3 +162,25 @@ runs:
|
||||
echo "Found ZIP: $zip_file"
|
||||
echo "Note: ZIP files are not code signed, but their contents should be"
|
||||
fi
|
||||
|
||||
- name: Sign the RPM
|
||||
if: inputs.os == 'linux'
|
||||
shell: ${{ inputs.shell }}
|
||||
run: |
|
||||
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
|
||||
|
||||
# Import the key into RPM for verification
|
||||
gpg --export -a > pubkey
|
||||
rpm --import pubkey
|
||||
rm pubkey
|
||||
|
||||
# Sign the RPM
|
||||
rpm_file=$(find ./apps/desktop/upload -name "*.rpm" -print -quit)
|
||||
rpmsign --define "_gpg_name Trilium Notes Signing Key <triliumnotes@outlook.com>" --addsign "$rpm_file"
|
||||
rpm -Kv "$rpm_file"
|
||||
|
||||
# Validate code signing
|
||||
if ! rpm -K "$rpm_file" | grep -q "digests signatures OK"; then
|
||||
echo .rpm file not signed
|
||||
exit 1
|
||||
fi
|
||||
|
||||
2
.github/actions/report-size/action.yml
vendored
2
.github/actions/report-size/action.yml
vendored
@@ -44,7 +44,7 @@ runs:
|
||||
steps:
|
||||
# Checkout branch to compare to [required]
|
||||
- name: Checkout base branch
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ inputs.branch }}
|
||||
path: br-base
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# Add any setup steps before running the `github/codeql-action/init` action.
|
||||
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
||||
|
||||
8
.github/workflows/dev.yml
vendored
8
.github/workflows/dev.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # needed for https://github.com/marketplace/actions/nx-set-shas
|
||||
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
- check-affected
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
- test_dev
|
||||
- check-affected
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
- dockerfile: Dockerfile
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Install dependencies
|
||||
|
||||
4
.github/workflows/main-docker.yml
vendored
4
.github/workflows/main-docker.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- dockerfile: Dockerfile
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set IMAGE_NAME to lowercase
|
||||
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> $GITHUB_ENV
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
run: echo "TEST_TAG=${TEST_TAG,,}" >> $GITHUB_ENV
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
|
||||
7
.github/workflows/nightly.yml
vendored
7
.github/workflows/nightly.yml
vendored
@@ -27,6 +27,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
nightly-electron:
|
||||
if: github.repository == 'TriliumNext/Trilium'
|
||||
name: Deploy nightly
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -47,7 +48,7 @@ jobs:
|
||||
forge_platform: win32
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
@@ -75,6 +76,7 @@ jobs:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
||||
|
||||
- name: Publish release
|
||||
uses: softprops/action-gh-release@v2.3.2
|
||||
@@ -96,6 +98,7 @@ jobs:
|
||||
path: apps/desktop/upload
|
||||
|
||||
nightly-server:
|
||||
if: github.repository == 'TriliumNext/Trilium'
|
||||
name: Deploy server nightly
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -108,7 +111,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
|
||||
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
filter: tree:0
|
||||
fetch-depth: 0
|
||||
|
||||
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
forge_platform: win32
|
||||
runs-on: ${{ matrix.os.image }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Set up node & dependencies
|
||||
uses: actions/setup-node@v4
|
||||
@@ -58,6 +58,7 @@ jobs:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
WINDOWS_SIGN_EXECUTABLE: ${{ vars.WINDOWS_SIGN_EXECUTABLE }}
|
||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGN_KEY }}
|
||||
|
||||
- name: Upload the artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -78,7 +79,7 @@ jobs:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Run the build
|
||||
uses: ./.github/actions/build-server
|
||||
@@ -101,7 +102,7 @@ jobs:
|
||||
steps:
|
||||
- run: mkdir upload
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: |
|
||||
docs/Release Notes
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,6 +10,7 @@ node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
|
||||
6
.idea/.gitignore
generated
vendored
6
.idea/.gitignore
generated
vendored
@@ -1,6 +0,0 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
||||
|
||||
# Datasource local storage ignored files
|
||||
/dataSources.local.xml
|
||||
/dataSources/
|
||||
15
.idea/codeStyles/Project.xml
generated
15
.idea/codeStyles/Project.xml
generated
@@ -1,15 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="OTHER_INDENT_OPTIONS">
|
||||
<value>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</value>
|
||||
</option>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
12
.idea/dataSources.xml
generated
12
.idea/dataSources.xml
generated
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="document.db" uuid="2a4ac1e6-b828-4a2a-8e4a-3f59f10aff26">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/data/document.db</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
4
.idea/encodings.xml
generated
4
.idea/encodings.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
||||
15
.idea/git_toolbox_prj.xml
generated
15
.idea/git_toolbox_prj.xml
generated
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GitToolBoxProjectSettings">
|
||||
<option name="commitMessageIssueKeyValidationOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
<option name="commitMessageValidationEnabledOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
11
.idea/inspectionProfiles/Project_Default.xml
generated
11
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,11 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
6
.idea/jsLibraryMappings.xml
generated
6
.idea/jsLibraryMappings.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
||||
9
.idea/jsLinters/jslint.xml
generated
9
.idea/jsLinters/jslint.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JSLintConfiguration">
|
||||
<option devel="true" />
|
||||
<option es6="true" />
|
||||
<option maxerr="50" />
|
||||
<option node="true" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/misc.xml
generated
8
.idea/misc.xml
generated
@@ -1,8 +0,0 @@
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/trilium.iml" filepath="$PROJECT_DIR$/trilium.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/sqldialects.xml
generated
7
.idea/sqldialects.xml
generated
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$" dialect="SQLite" />
|
||||
<file url="PROJECT" dialect="SQLite" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
4
.vscode/i18n-ally-custom-framework.yml
vendored
4
.vscode/i18n-ally-custom-framework.yml
vendored
@@ -3,6 +3,7 @@
|
||||
languageIds:
|
||||
- javascript
|
||||
- typescript
|
||||
- typescriptreact
|
||||
- html
|
||||
|
||||
# An array of RegExes to find the key usage. **The key should be captured in the first match group**.
|
||||
@@ -25,9 +26,10 @@ scopeRangeRegex: "useTranslation\\(\\s*\\[?\\s*['\"`](.*?)['\"`]"
|
||||
# The "$1" will be replaced by the keypath specified.
|
||||
refactorTemplates:
|
||||
- t("$1")
|
||||
- {t("$1")}
|
||||
- ${t("$1")}
|
||||
- <%= t("$1") %>
|
||||
|
||||
|
||||
# If set to true, only enables this custom framework (will disable all built-in frameworks)
|
||||
monopoly: true
|
||||
monopoly: true
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||

|
||||
[](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp) [](https://hosted.weblate.org/engage/trilium/)
|
||||
|
||||
[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 (Simplified)](./docs/README-ZH_CN.md) | [Chinese (Traditional)](./docs/README-ZH_TW.md) | [Russian](./docs/README.ru.md) | [Japanese](./docs/README.ja.md) | [Italian](./docs/README.it.md) | [Spanish](./docs/README.es.md)
|
||||
|
||||
Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases.
|
||||
|
||||
@@ -82,7 +82,7 @@ Feel free to join our official conversations. We would love to hear what feature
|
||||
|
||||
### Windows / MacOS
|
||||
|
||||
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/Trilium/releases/latest), unzip the package and run the `trilium` executable.
|
||||
|
||||
### Linux
|
||||
|
||||
@@ -90,7 +90,7 @@ If your distribution is listed in the table below, use your distribution's packa
|
||||
|
||||
[](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.
|
||||
You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Trilium/releases/latest), unzip the package and run the `trilium` executable.
|
||||
|
||||
TriliumNext is also provided as a Flatpak, but not yet published on FlatHub.
|
||||
|
||||
@@ -110,7 +110,7 @@ See issue https://github.com/TriliumNext/Notes/issues/72 for more information on
|
||||
|
||||
### Server
|
||||
|
||||
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/trilium)) follow [the server installation docs](https://triliumnext.github.io/Docs/Wiki/server-installation).
|
||||
|
||||
|
||||
## 💻 Contribute
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.54.2",
|
||||
"@stylistic/eslint-plugin": "5.2.2",
|
||||
"@stylistic/eslint-plugin": "5.2.3",
|
||||
"@types/express": "5.0.3",
|
||||
"@types/node": "22.17.0",
|
||||
"@types/node": "22.17.1",
|
||||
"@types/yargs": "17.0.33",
|
||||
"@vitest/coverage-v8": "3.2.4",
|
||||
"eslint": "9.32.0",
|
||||
"eslint": "9.33.0",
|
||||
"eslint-plugin-simple-import-sort": "12.1.1",
|
||||
"esm": "3.2.25",
|
||||
"jsdoc": "4.0.4",
|
||||
@@ -49,8 +49,8 @@
|
||||
"rcedit": "4.0.1",
|
||||
"rimraf": "6.0.1",
|
||||
"tslib": "2.8.1",
|
||||
"typedoc": "0.28.9",
|
||||
"typedoc-plugin-missing-exports": "4.0.0"
|
||||
"typedoc": "0.28.10",
|
||||
"typedoc-plugin-missing-exports": "4.1.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"appdmg": "0.6.6"
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
"url": "https://github.com/TriliumNext/Notes"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "9.32.0",
|
||||
"@eslint/js": "9.33.0",
|
||||
"@excalidraw/excalidraw": "0.18.0",
|
||||
"@fullcalendar/core": "6.1.18",
|
||||
"@fullcalendar/daygrid": "6.1.18",
|
||||
"@fullcalendar/interaction": "6.1.18",
|
||||
"@fullcalendar/list": "6.1.18",
|
||||
"@fullcalendar/multimonth": "6.1.18",
|
||||
"@fullcalendar/timegrid": "6.1.18",
|
||||
"@fullcalendar/core": "6.1.19",
|
||||
"@fullcalendar/daygrid": "6.1.19",
|
||||
"@fullcalendar/interaction": "6.1.19",
|
||||
"@fullcalendar/list": "6.1.19",
|
||||
"@fullcalendar/multimonth": "6.1.19",
|
||||
"@fullcalendar/timegrid": "6.1.19",
|
||||
"@maplibre/maplibre-gl-leaflet": "0.1.3",
|
||||
"@mermaid-js/layout-elk": "0.1.8",
|
||||
"@mind-elixir/node-menu": "5.0.0",
|
||||
@@ -36,7 +36,7 @@
|
||||
"draggabilly": "3.0.0",
|
||||
"force-graph": "1.50.1",
|
||||
"globals": "16.3.0",
|
||||
"i18next": "25.3.2",
|
||||
"i18next": "25.3.4",
|
||||
"i18next-http-backend": "3.0.2",
|
||||
"jquery": "3.7.1",
|
||||
"jquery.fancytree": "2.38.5",
|
||||
@@ -48,7 +48,7 @@
|
||||
"mark.js": "8.11.1",
|
||||
"marked": "16.1.2",
|
||||
"mermaid": "11.9.0",
|
||||
"mind-elixir": "5.0.4",
|
||||
"mind-elixir": "5.0.5",
|
||||
"normalize.css": "8.0.1",
|
||||
"panzoom": "9.4.3",
|
||||
"preact": "10.27.0",
|
||||
@@ -65,8 +65,8 @@
|
||||
"@types/leaflet": "1.9.20",
|
||||
"@types/leaflet-gpx": "1.3.7",
|
||||
"@types/mark.js": "8.11.12",
|
||||
"@types/tabulator-tables": "6.2.9",
|
||||
"copy-webpack-plugin": "13.0.0",
|
||||
"@types/tabulator-tables": "6.2.10",
|
||||
"copy-webpack-plugin": "13.0.1",
|
||||
"happy-dom": "18.0.1",
|
||||
"script-loader": "0.7.2",
|
||||
"vite-plugin-static-copy": "3.1.1"
|
||||
|
||||
@@ -30,6 +30,7 @@ import type CodeMirror from "@triliumnext/codemirror";
|
||||
import { StartupChecks } from "./startup_checks.js";
|
||||
import type { CreateNoteOpts } from "../services/note_create.js";
|
||||
import { ColumnComponent } from "tabulator-tables";
|
||||
import { ChooseNoteTypeCallback } from "../widgets/dialogs/note_type_chooser.jsx";
|
||||
|
||||
interface Layout {
|
||||
getRootWidget: (appContext: AppContext) => RootWidget;
|
||||
@@ -92,7 +93,9 @@ export type CommandMappings = {
|
||||
closeTocCommand: CommandData;
|
||||
closeHlt: CommandData;
|
||||
showLaunchBarSubtree: CommandData;
|
||||
showRevisions: CommandData;
|
||||
showRevisions: CommandData & {
|
||||
noteId?: string | null;
|
||||
};
|
||||
showLlmChat: CommandData;
|
||||
createAiChat: CommandData;
|
||||
showOptions: CommandData & {
|
||||
@@ -368,6 +371,9 @@ export type CommandMappings = {
|
||||
};
|
||||
refreshTouchBar: CommandData;
|
||||
reloadTextEditor: CommandData;
|
||||
chooseNoteType: CommandData & {
|
||||
callback: ChooseNoteTypeCallback
|
||||
}
|
||||
};
|
||||
|
||||
type EventMappings = {
|
||||
|
||||
@@ -30,6 +30,7 @@ import ClassicEditorToolbar from "../widgets/ribbon_widgets/classic_editor_toolb
|
||||
import PromotedAttributesWidget from "../widgets/ribbon_widgets/promoted_attributes.js";
|
||||
import NoteDetailWidget from "../widgets/note_detail.js";
|
||||
import NoteListWidget from "../widgets/note_list.js";
|
||||
import { CallToActionDialog } from "../widgets/dialogs/call_to_action.jsx";
|
||||
|
||||
export function applyModals(rootContainer: RootContainer) {
|
||||
rootContainer
|
||||
@@ -66,4 +67,5 @@ export function applyModals(rootContainer: RootContainer) {
|
||||
.child(new PromotedAttributesWidget())
|
||||
.child(new NoteDetailWidget())
|
||||
.child(new NoteListWidget(true)))
|
||||
.child(new CallToActionDialog());
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import TabRowWidget from "../widgets/tab_row.js";
|
||||
import RefreshButton from "../widgets/floating_buttons/refresh_button.js";
|
||||
import MobileEditorToolbar from "../widgets/ribbon_widgets/mobile_editor_toolbar.js";
|
||||
import { applyModals } from "./layout_commons.js";
|
||||
import CloseZenButton from "../widgets/close_zen_button.js";
|
||||
|
||||
const MOBILE_CSS = `
|
||||
<style>
|
||||
@@ -174,7 +175,8 @@ export default class MobileLayout {
|
||||
.id("mobile-bottom-bar")
|
||||
.child(new TabRowWidget().css("height", "40px"))
|
||||
.child(new FlexContainer("row").class("horizontal").css("height", "53px").child(new LauncherContainer(true)).child(new GlobalMenuWidget(true)).id("launcher-pane"))
|
||||
);
|
||||
)
|
||||
.child(new CloseZenButton());
|
||||
applyModals(rootContainer);
|
||||
return rootContainer;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ export interface Suggestion {
|
||||
commandShortcut?: string;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
container?: HTMLElement;
|
||||
export interface Options {
|
||||
container?: HTMLElement | null;
|
||||
fastSearch?: boolean;
|
||||
allowCreatingNotes?: boolean;
|
||||
allowJumpToSearchNotes?: boolean;
|
||||
@@ -82,12 +82,12 @@ async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void
|
||||
// Check if we're in command mode
|
||||
if (options.isCommandPalette && term.startsWith(">")) {
|
||||
const commandQuery = term.substring(1).trim();
|
||||
|
||||
|
||||
// Get commands (all if no query, filtered if query provided)
|
||||
const commands = commandQuery.length === 0
|
||||
const commands = commandQuery.length === 0
|
||||
? commandRegistry.getAllCommands()
|
||||
: commandRegistry.searchCommands(commandQuery);
|
||||
|
||||
|
||||
// Convert commands to suggestions
|
||||
const commandSuggestions: Suggestion[] = commands.map(cmd => ({
|
||||
action: "command",
|
||||
@@ -99,7 +99,7 @@ async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void
|
||||
commandShortcut: cmd.shortcut,
|
||||
icon: cmd.icon
|
||||
}));
|
||||
|
||||
|
||||
cb(commandSuggestions);
|
||||
return;
|
||||
}
|
||||
@@ -452,6 +452,21 @@ function init() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function which triggers the display of recent notes in the autocomplete input and focuses it.
|
||||
*
|
||||
* @param inputElement - The input element to trigger recent notes on.
|
||||
*/
|
||||
export function triggerRecentNotes(inputElement: HTMLInputElement | null | undefined) {
|
||||
if (!inputElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $el = $(inputElement);
|
||||
showRecentNotes($el);
|
||||
$el.trigger("focus").trigger("select");
|
||||
}
|
||||
|
||||
export default {
|
||||
autocompleteSourceForCKEditor,
|
||||
initNoteAutocomplete,
|
||||
|
||||
@@ -109,8 +109,6 @@ async function createNote(parentNotePath: string | undefined, options: CreateNot
|
||||
|
||||
async function chooseNoteType() {
|
||||
return new Promise<ChooseNoteTypeResponse>((res) => {
|
||||
// TODO: Remove ignore after callback for chooseNoteType is defined in app_context.ts
|
||||
//@ts-ignore
|
||||
appContext.triggerCommand("chooseNoteType", { callback: res });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -320,8 +320,3 @@ h6 {
|
||||
page-break-after: avoid;
|
||||
break-after: avoid;
|
||||
}
|
||||
|
||||
figure.table {
|
||||
/* Workaround for https://github.com/ckeditor/ckeditor5/issues/18903. Remove once official fix is released */
|
||||
display: table !important;
|
||||
}
|
||||
@@ -642,6 +642,10 @@ table.promoted-attributes-in-tooltip th {
|
||||
z-index: calc(var(--ck-z-panel) - 1) !important;
|
||||
}
|
||||
|
||||
.tooltip.tooltip-top {
|
||||
z-index: 32767 !important;
|
||||
}
|
||||
|
||||
.tooltip-trigger {
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
@@ -1886,6 +1890,7 @@ body.zen #launcher-container,
|
||||
body.zen #launcher-pane,
|
||||
body.zen #left-pane,
|
||||
body.zen #right-pane,
|
||||
body.zen #mobile-sidebar-wrapper,
|
||||
body.zen .tab-row-container,
|
||||
body.zen .tab-row-widget,
|
||||
body.zen .ribbon-container:not(:has(.classic-toolbar-widget.visible)),
|
||||
@@ -1893,7 +1898,8 @@ body.zen .ribbon-container:has(.classic-toolbar-widget.visible) .ribbon-top-row,
|
||||
body.zen .ribbon-container .ribbon-body:not(:has(.classic-toolbar-widget.visible)),
|
||||
body.zen .note-icon-widget,
|
||||
body.zen .title-row .button-widget,
|
||||
body.zen .floating-buttons-children > *:not(.bx-edit-alt) {
|
||||
body.zen .floating-buttons-children > *:not(.bx-edit-alt),
|
||||
body.zen .action-button {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -1935,6 +1941,10 @@ body.zen .note-title-widget input {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
body.zen #detail-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Content renderer */
|
||||
|
||||
footer.file-footer,
|
||||
@@ -2245,6 +2255,13 @@ footer.webview-footer button {
|
||||
padding: 1px 10px 1px 10px;
|
||||
}
|
||||
|
||||
/* Search result highlighting */
|
||||
.search-result-title b,
|
||||
.search-result-content b {
|
||||
font-weight: 900;
|
||||
color: var(--admonition-warning-accent-color);
|
||||
}
|
||||
|
||||
/* Customized icons */
|
||||
|
||||
.bx-tn-toc::before {
|
||||
|
||||
@@ -233,16 +233,16 @@ div.tn-tool-dialog {
|
||||
|
||||
/* Item title link */
|
||||
|
||||
.recent-changes-content ul li .note-title a {
|
||||
.recent-changes-content ul li a {
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
.recent-changes-content ul li .note-title a:hover {
|
||||
.recent-changes-content ul li a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Item title for deleted notes */
|
||||
.recent-changes-content ul li.deleted-note .note-title > .note-title {
|
||||
.recent-changes-content ul li.deleted-note .note-title {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Sobre Trilium Notes",
|
||||
"close": "Tanca",
|
||||
"homepage": "Pàgina principal:"
|
||||
},
|
||||
"add_link": {
|
||||
"note": "Nota",
|
||||
"close": "Tanca"
|
||||
"note": "Nota"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"close": "Tanca",
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Desa"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"close": "Tanca",
|
||||
"labels": "Etiquetes",
|
||||
"relations": "Relacions",
|
||||
"notes": "Notes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"clone_to": {
|
||||
"close": "Tanca"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmació",
|
||||
"close": "Tanca",
|
||||
"cancel": "Cancel·la",
|
||||
"ok": "OK"
|
||||
},
|
||||
@@ -39,53 +31,34 @@
|
||||
"export": "Exporta"
|
||||
},
|
||||
"help": {
|
||||
"close": "Tanca",
|
||||
"troubleshooting": "Solució de problemes",
|
||||
"other": "Altres"
|
||||
},
|
||||
"import": {
|
||||
"close": "Tanca",
|
||||
"options": "Opcions",
|
||||
"import": "Importa"
|
||||
},
|
||||
"include_note": {
|
||||
"close": "Tanca",
|
||||
"label_note": "Nota"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "Tanca",
|
||||
"okButton": "OK"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"close": "Tanca"
|
||||
},
|
||||
"markdown_import": {
|
||||
"close": "Tanca"
|
||||
},
|
||||
"move_to": {
|
||||
"close": "Tanca"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"close": "Tanca",
|
||||
"templates": "Plantilles:"
|
||||
},
|
||||
"password_not_set": {
|
||||
"close": "Tanca"
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Sol·licitud",
|
||||
"close": "Tanca",
|
||||
"defaultTitle": "Sol·licitud"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Tanca"
|
||||
},
|
||||
"recent_changes": {
|
||||
"close": "Tanca",
|
||||
"undelete_link": "recuperar"
|
||||
},
|
||||
"revisions": {
|
||||
"close": "Tanca",
|
||||
"restore_button": "Restaura",
|
||||
"delete_button": "Suprimeix",
|
||||
"download_button": "Descarrega",
|
||||
@@ -93,14 +66,12 @@
|
||||
"preview": "Vista prèvia:"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"close": "Tanca",
|
||||
"title": "títol",
|
||||
"ascending": "ascendent",
|
||||
"descending": "descendent",
|
||||
"folders": "Carpetes"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"close": "Tanca",
|
||||
"options": "Opcions",
|
||||
"upload": "Puja"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Über Trilium Notes",
|
||||
"close": "Schließen",
|
||||
"homepage": "Startseite:",
|
||||
"app_version": "App-Version:",
|
||||
"db_version": "DB-Version:",
|
||||
@@ -28,25 +27,22 @@
|
||||
"add_link": {
|
||||
"add_link": "Link hinzufügen",
|
||||
"help_on_links": "Hilfe zu Links",
|
||||
"close": "Schließen",
|
||||
"note": "Notiz",
|
||||
"search_note": "Suche nach einer Notiz anhand ihres Namens",
|
||||
"link_title_mirrors": "Der Linktitel spiegelt den aktuellen Titel der Notiz wider",
|
||||
"link_title_arbitrary": "Der Linktitel kann beliebig geändert werden",
|
||||
"link_title": "Linktitel",
|
||||
"button_add_link": "Link hinzufügen <kbd>Eingabetaste</kbd>"
|
||||
"button_add_link": "Link hinzufügen"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Zweigpräfix bearbeiten",
|
||||
"help_on_tree_prefix": "Hilfe zum Baumpräfix",
|
||||
"close": "Schließen",
|
||||
"prefix": "Präfix: ",
|
||||
"save": "Speichern",
|
||||
"branch_prefix_saved": "Zweigpräfix wurde gespeichert."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Massenaktionen",
|
||||
"close": "Schließen",
|
||||
"affected_notes": "Betroffene Notizen",
|
||||
"include_descendants": "Unternotizen der ausgewählten Notizen einbeziehen",
|
||||
"available_actions": "Verfügbare Aktionen",
|
||||
@@ -61,20 +57,18 @@
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Notizen klonen nach...",
|
||||
"close": "Schließen",
|
||||
"help_on_links": "Hilfe zu Links",
|
||||
"notes_to_clone": "Notizen zum Klonen",
|
||||
"target_parent_note": "Ziel-Übergeordnetenotiz",
|
||||
"search_for_note_by_its_name": "Suche nach einer Notiz anhand ihres Namens",
|
||||
"cloned_note_prefix_title": "Die geklonte Notiz wird im Notizbaum mit dem angegebenen Präfix angezeigt",
|
||||
"prefix_optional": "Präfix (optional)",
|
||||
"clone_to_selected_note": "Auf ausgewählte Notiz klonen <kbd>Eingabe</kbd>",
|
||||
"clone_to_selected_note": "Auf ausgewählte Notiz klonen",
|
||||
"no_path_to_clone_to": "Kein Pfad zum Klonen.",
|
||||
"note_cloned": "Die Notiz \"{{clonedTitle}}\" wurde in \"{{targetTitle}}\" hinein geklont"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Bestätigung",
|
||||
"close": "Schließen",
|
||||
"cancel": "Abbrechen",
|
||||
"ok": "OK",
|
||||
"are_you_sure_remove_note": "Bist du sicher, dass du \"{{title}}\" von der Beziehungskarte entfernen möchten? ",
|
||||
@@ -87,9 +81,9 @@
|
||||
"delete_all_clones_description": "auch alle Klone löschen (kann bei letzte Änderungen rückgängig gemacht werden)",
|
||||
"erase_notes_description": "Beim normalen (vorläufigen) Löschen werden die Notizen nur als gelöscht markiert und sie können innerhalb eines bestimmten Zeitraums (im Dialogfeld „Letzte Änderungen“) wiederhergestellt werden. Wenn du diese Option aktivierst, werden die Notizen sofort gelöscht und es ist nicht möglich, die Notizen wiederherzustellen.",
|
||||
"erase_notes_warning": "Notizen dauerhaft löschen (kann nicht rückgängig gemacht werden), einschließlich aller Klone. Dadurch wird ein Neuladen der Anwendung erzwungen.",
|
||||
"notes_to_be_deleted": "Folgende Notizen werden gelöscht (<span class=\"deleted-notes-count\"></span>)",
|
||||
"notes_to_be_deleted": "Folgende Notizen werden gelöscht ({{notesCount}})",
|
||||
"no_note_to_delete": "Es werden keine Notizen gelöscht (nur Klone).",
|
||||
"broken_relations_to_be_deleted": "Folgende Beziehungen werden gelöst und gelöscht (<span class=\"broke-relations-count\"></span>)",
|
||||
"broken_relations_to_be_deleted": "Folgende Beziehungen werden gelöst und gelöscht ({{ relationCount}})",
|
||||
"cancel": "Abbrechen",
|
||||
"ok": "OK",
|
||||
"deleted_relation_text": "Notiz {{- note}} (soll gelöscht werden) wird von Beziehung {{- relation}} ausgehend von {{- source}} referenziert."
|
||||
@@ -113,20 +107,18 @@
|
||||
"format_pdf": "PDF - für Ausdrucke oder Teilen."
|
||||
},
|
||||
"help": {
|
||||
"fullDocumentation": "Hilfe (gesamte Dokumentation ist <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a> verfügbar)",
|
||||
"close": "Schließen",
|
||||
"noteNavigation": "Notiz Navigation",
|
||||
"goUpDown": "<kbd>Pfeil Hoch</kbd>, <kbd>Pfeil Runter</kbd> - In der Liste der Notizen nach oben/unten gehen",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - Knoten reduzieren/erweitern",
|
||||
"goUpDown": "In der Liste der Notizen nach oben/unten gehen",
|
||||
"collapseExpand": "Knoten reduzieren/erweitern",
|
||||
"notSet": "nicht eingestellt",
|
||||
"goBackForwards": "in der Historie zurück/vorwärts gehen",
|
||||
"showJumpToNoteDialog": "zeige <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Springe zu\" dialog</a>",
|
||||
"scrollToActiveNote": "Scrolle zur aktiven Notiz",
|
||||
"jumpToParentNote": "<kbd>Backspace</kbd> - Zur übergeordneten Notiz springen",
|
||||
"jumpToParentNote": "Zur übergeordneten Notiz springen",
|
||||
"collapseWholeTree": "Reduziere den gesamten Notizbaum",
|
||||
"collapseSubTree": "Teilbaum einklappen",
|
||||
"tabShortcuts": "Tab-Tastenkürzel",
|
||||
"newTabNoteLink": "<kbd>Strg+Klick</kbd> - (oder mittlerer Mausklick) auf den Notizlink öffnet die Notiz in einem neuen Tab",
|
||||
"newTabNoteLink": "auf den Notizlink öffnet die Notiz in einem neuen Tab",
|
||||
"onlyInDesktop": "Nur im Desktop (Electron Build)",
|
||||
"openEmptyTab": "Leeren Tab öffnen",
|
||||
"closeActiveTab": "Aktiven Tab schließen",
|
||||
@@ -141,14 +133,14 @@
|
||||
"moveNoteUpHierarchy": "Verschiebe die Notiz in der Hierarchie nach oben",
|
||||
"multiSelectNote": "Mehrfachauswahl von Notizen oben/unten",
|
||||
"selectAllNotes": "Wähle alle Notizen in der aktuellen Ebene aus",
|
||||
"selectNote": "<kbd>Umschalt+Klick</kbd> - Notiz auswählen",
|
||||
"selectNote": "Notiz auswählen",
|
||||
"copyNotes": "Kopiere aktive Notiz (oder aktuelle Auswahl) in den Zwischenspeicher (wird genutzt für <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">Klonen</a>)",
|
||||
"cutNotes": "Aktuelle Notiz (oder aktuelle Auswahl) in die Zwischenablage ausschneiden (wird zum Verschieben von Notizen verwendet)",
|
||||
"pasteNotes": "Notiz(en) als Unternotiz in die aktive Notiz einfügen (entweder verschieben oder klonen, je nachdem, ob sie kopiert oder in die Zwischenablag e ausgeschnitten wurde)",
|
||||
"deleteNotes": "Notiz / Unterbaum löschen",
|
||||
"editingNotes": "Notizen bearbeiten",
|
||||
"editNoteTitle": "Im Baumbereich wird vom Baumbereich zum Notiztitel gewechselt. Beim Druck auf Eingabe im Notiztitel, wechselt der Fokus zum Texteditor. <kbd>Strg+.</kbd> wechselt vom Editor zurück zum Baumbereich.",
|
||||
"createEditLink": "<kbd>Strg+K</kbd> - Externen Link erstellen/bearbeiten",
|
||||
"createEditLink": "Externen Link erstellen/bearbeiten",
|
||||
"createInternalLink": "Internen Link erstellen",
|
||||
"followLink": "Folge dem Link unter dem Cursor",
|
||||
"insertDateTime": "Gebe das aktuelle Datum und die aktuelle Uhrzeit an der Einfügemarke ein",
|
||||
@@ -164,11 +156,12 @@
|
||||
"showSQLConsole": "SQL-Konsole anzeigen",
|
||||
"other": "Andere",
|
||||
"quickSearch": "Fokus auf schnelle Sucheingabe",
|
||||
"inPageSearch": "Auf-der-Seite-Suche"
|
||||
"inPageSearch": "Auf-der-Seite-Suche",
|
||||
"newTabWithActivationNoteLink": "auf einen Notiz-Link öffnet und aktiviert die Notiz in einem neuen Tab",
|
||||
"title": "Spickzettel"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "In Notiz importieren",
|
||||
"close": "Schließen",
|
||||
"chooseImportFile": "Wähle Importdatei aus",
|
||||
"importDescription": "Der Inhalt der ausgewählten Datei(en) wird als untergeordnete Notiz(en) importiert",
|
||||
"options": "Optionen",
|
||||
@@ -195,14 +188,13 @@
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Notiz beifügen",
|
||||
"close": "Schließen",
|
||||
"label_note": "Notiz",
|
||||
"placeholder_search": "Suche nach einer Notiz anhand ihres Namens",
|
||||
"box_size_prompt": "Kartongröße des beigelegten Zettels:",
|
||||
"box_size_small": "klein (~ 10 Zeilen)",
|
||||
"box_size_medium": "mittel (~ 30 Zeilen)",
|
||||
"box_size_full": "vollständig (Feld zeigt vollständigen Text)",
|
||||
"button_include": "Notiz beifügen <kbd>Eingabetaste</kbd>"
|
||||
"button_include": "Notiz beifügen"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Infonachricht",
|
||||
@@ -210,42 +202,35 @@
|
||||
"okButton": "OK"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"close": "Schließen",
|
||||
"search_button": "Suche im Volltext: <kbd>Strg+Eingabetaste</kbd>"
|
||||
"search_button": "Suche im Volltext"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Markdown-Import",
|
||||
"close": "Schließen",
|
||||
"modal_body_text": "Aufgrund der Browser-Sandbox ist es nicht möglich, die Zwischenablage direkt aus JavaScript zu lesen. Bitte füge den zu importierenden Markdown in den Textbereich unten ein und klicke auf die Schaltfläche „Importieren“.",
|
||||
"import_button": "Importieren Strg+Eingabe",
|
||||
"import_button": "Importieren",
|
||||
"import_success": "Markdown-Inhalt wurde in das Dokument importiert."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Notizen verschieben nach ...",
|
||||
"close": "Schließen",
|
||||
"notes_to_move": "Notizen zum Verschieben",
|
||||
"target_parent_note": "Ziel-Elternnotiz",
|
||||
"search_placeholder": "Suche nach einer Notiz anhand ihres Namens",
|
||||
"move_button": "Zur ausgewählten Notiz wechseln <kbd>Eingabetaste</kbd>",
|
||||
"move_button": "Zur ausgewählten Notiz wechseln",
|
||||
"error_no_path": "Kein Weg, auf den man sich bewegen kann.",
|
||||
"move_success_message": "Ausgewählte Notizen wurden verschoben"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"modal_title": "Wähle den Notiztyp aus",
|
||||
"close": "Schließen",
|
||||
"modal_body": "Wähle den Notiztyp / die Vorlage der neuen Notiz:",
|
||||
"templates": "Vorlagen:"
|
||||
"templates": "Vorlagen"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "Das Passwort ist nicht festgelegt",
|
||||
"close": "Schließen",
|
||||
"body1": "Geschützte Notizen werden mit einem Benutzerpasswort verschlüsselt, es wurde jedoch noch kein Passwort festgelegt.",
|
||||
"body2": "Um Notizen verschlüsseln zu können, klicke <a class=\"open-password-options-button\" href=\"javascript:\">hier</a> um das Optionsmenu zu öffnen und ein Passwort zu setzen."
|
||||
"body1": "Geschützte Notizen werden mit einem Benutzerpasswort verschlüsselt, es wurde jedoch noch kein Passwort festgelegt."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Prompt",
|
||||
"close": "Schließen",
|
||||
"ok": "OK <kbd>Eingabe</kbd>",
|
||||
"ok": "OK",
|
||||
"defaultTitle": "Prompt"
|
||||
},
|
||||
"protected_session_password": {
|
||||
@@ -253,12 +238,11 @@
|
||||
"help_title": "Hilfe zu geschützten Notizen",
|
||||
"close_label": "Schließen",
|
||||
"form_label": "Um mit der angeforderten Aktion fortzufahren, musst du eine geschützte Sitzung starten, indem du ein Passwort eingibst:",
|
||||
"start_button": "Geschützte Sitzung starten <kbd>enter</kbd>"
|
||||
"start_button": "Geschützte Sitzung starten"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Aktuelle Änderungen",
|
||||
"erase_notes_button": "Jetzt gelöschte Notizen löschen",
|
||||
"close": "Schließen",
|
||||
"deleted_notes_message": "Gelöschte Notizen wurden gelöscht.",
|
||||
"no_changes_message": "Noch keine Änderungen...",
|
||||
"undelete_link": "Wiederherstellen",
|
||||
@@ -269,7 +253,6 @@
|
||||
"delete_all_revisions": "Lösche alle Revisionen dieser Notiz",
|
||||
"delete_all_button": "Alle Revisionen löschen",
|
||||
"help_title": "Hilfe zu Notizrevisionen",
|
||||
"close": "Schließen",
|
||||
"revision_last_edited": "Diese Revision wurde zuletzt am {{date}} bearbeitet",
|
||||
"confirm_delete_all": "Möchtest du alle Revisionen dieser Notiz löschen?",
|
||||
"no_revisions": "Für diese Notiz gibt es noch keine Revisionen...",
|
||||
@@ -289,7 +272,6 @@
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Unternotizen sortieren nach...",
|
||||
"close": "Schließen",
|
||||
"sorting_criteria": "Sortierkriterien",
|
||||
"title": "Titel",
|
||||
"date_created": "Erstellungsdatum",
|
||||
@@ -303,13 +285,12 @@
|
||||
"sort_with_respect_to_different_character_sorting": "Sortierung im Hinblick auf unterschiedliche Sortier- und Sortierregeln für Zeichen in verschiedenen Sprachen oder Regionen.",
|
||||
"natural_sort_language": "Natürliche Sortiersprache",
|
||||
"the_language_code_for_natural_sort": "Der Sprachcode für die natürliche Sortierung, z. B. \"de-DE\" für Deutsch.",
|
||||
"sort": "Sortieren <kbd>Eingabetaste</kbd>"
|
||||
"sort": "Sortieren"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Lade Anhänge zur Notiz hoch",
|
||||
"close": "Schließen",
|
||||
"choose_files": "Wähle Dateien aus",
|
||||
"files_will_be_uploaded": "Dateien werden als Anhänge in hochgeladen",
|
||||
"files_will_be_uploaded": "Dateien werden als Anhänge in hochgeladen {{noteTitle}}",
|
||||
"options": "Optionen",
|
||||
"shrink_images": "Bilder verkleinern",
|
||||
"upload": "Hochladen",
|
||||
@@ -1098,12 +1079,9 @@
|
||||
"title": "Thema",
|
||||
"theme_label": "Thema",
|
||||
"override_theme_fonts_label": "Theme-Schriftarten überschreiben",
|
||||
"auto_theme": "Auto",
|
||||
"light_theme": "Hell",
|
||||
"dark_theme": "Dunkel",
|
||||
"triliumnext": "TriliumNext Beta (Systemfarbschema folgend)",
|
||||
"triliumnext-light": "TriliumNext Beta (Hell)",
|
||||
"triliumnext-dark": "TriliumNext Beta (Dunkel)",
|
||||
"triliumnext": "Trilium (Systemfarbschema folgend)",
|
||||
"triliumnext-light": "Trilium (Hell)",
|
||||
"triliumnext-dark": "Trilium (Dunkel)",
|
||||
"layout": "Layout",
|
||||
"layout-vertical-title": "Vertikal",
|
||||
"layout-horizontal-title": "Horizontal",
|
||||
@@ -1650,5 +1628,8 @@
|
||||
},
|
||||
"time_selector": {
|
||||
"invalid_input": "Die eingegebene Zeit ist keine valide Zahl."
|
||||
},
|
||||
"modal": {
|
||||
"close": "Schließen"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Πληροφορίες για το Trilium Notes",
|
||||
"close": "Κλείσιμο",
|
||||
"homepage": "Αρχική Σελίδα:",
|
||||
"app_version": "Έκδοση εφαρμογής:",
|
||||
"db_version": "Έκδοση βάσης δεδομένων:",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "About Trilium Notes",
|
||||
"close": "Close",
|
||||
"homepage": "Homepage:",
|
||||
"app_version": "App version:",
|
||||
"db_version": "DB version:",
|
||||
@@ -28,25 +27,22 @@
|
||||
"add_link": {
|
||||
"add_link": "Add link",
|
||||
"help_on_links": "Help on links",
|
||||
"close": "Close",
|
||||
"note": "Note",
|
||||
"search_note": "search for note by its name",
|
||||
"link_title_mirrors": "link title mirrors the note's current title",
|
||||
"link_title_arbitrary": "link title can be changed arbitrarily",
|
||||
"link_title": "Link title",
|
||||
"button_add_link": "Add link <kbd>enter</kbd>"
|
||||
"button_add_link": "Add link"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Edit branch prefix",
|
||||
"help_on_tree_prefix": "Help on Tree prefix",
|
||||
"close": "Close",
|
||||
"prefix": "Prefix: ",
|
||||
"save": "Save",
|
||||
"branch_prefix_saved": "Branch prefix has been saved."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Bulk actions",
|
||||
"close": "Close",
|
||||
"affected_notes": "Affected notes",
|
||||
"include_descendants": "Include descendants of the selected notes",
|
||||
"available_actions": "Available actions",
|
||||
@@ -61,20 +57,18 @@
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Clone notes to...",
|
||||
"close": "Close",
|
||||
"help_on_links": "Help on links",
|
||||
"notes_to_clone": "Notes to clone",
|
||||
"target_parent_note": "Target parent note",
|
||||
"search_for_note_by_its_name": "search for note by its name",
|
||||
"cloned_note_prefix_title": "Cloned note will be shown in note tree with given prefix",
|
||||
"prefix_optional": "Prefix (optional)",
|
||||
"clone_to_selected_note": "Clone to selected note <kbd>enter</kbd>",
|
||||
"clone_to_selected_note": "Clone to selected note",
|
||||
"no_path_to_clone_to": "No path to clone to.",
|
||||
"note_cloned": "Note \"{{clonedTitle}}\" has been cloned into \"{{targetTitle}}\""
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmation",
|
||||
"close": "Close",
|
||||
"cancel": "Cancel",
|
||||
"ok": "OK",
|
||||
"are_you_sure_remove_note": "Are you sure you want to remove the note \"{{title}}\" from relation map? ",
|
||||
@@ -87,9 +81,9 @@
|
||||
"delete_all_clones_description": "Delete also all clones (can be undone in recent changes)",
|
||||
"erase_notes_description": "Normal (soft) deletion only marks the notes as deleted and they can be undeleted (in recent changes dialog) within a period of time. Checking this option will erase the notes immediately and it won't be possible to undelete the notes.",
|
||||
"erase_notes_warning": "Erase notes permanently (can't be undone), including all clones. This will force application reload.",
|
||||
"notes_to_be_deleted": "Following notes will be deleted ({{- noteCount}})",
|
||||
"notes_to_be_deleted": "Following notes will be deleted ({{notesCount}})",
|
||||
"no_note_to_delete": "No note will be deleted (only clones).",
|
||||
"broken_relations_to_be_deleted": "Following relations will be broken and deleted ({{- relationCount}})",
|
||||
"broken_relations_to_be_deleted": "Following relations will be broken and deleted ({{ relationCount}})",
|
||||
"cancel": "Cancel",
|
||||
"ok": "OK",
|
||||
"deleted_relation_text": "Note {{- note}} (to be deleted) is referenced by relation {{- relation}} originating from {{- source}}."
|
||||
@@ -113,21 +107,20 @@
|
||||
"format_pdf": "PDF - for printing or sharing purposes."
|
||||
},
|
||||
"help": {
|
||||
"fullDocumentation": "Help (full documentation is available <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
|
||||
"close": "Close",
|
||||
"title": "Cheatsheet",
|
||||
"noteNavigation": "Note navigation",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - go up/down in the list of notes",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - collapse/expand node",
|
||||
"goUpDown": "go up/down in the list of notes",
|
||||
"collapseExpand": "collapse/expand node",
|
||||
"notSet": "not set",
|
||||
"goBackForwards": "go back / forwards in the history",
|
||||
"showJumpToNoteDialog": "show <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Jump to\" dialog</a>",
|
||||
"scrollToActiveNote": "scroll to active note",
|
||||
"jumpToParentNote": "<kbd>Backspace</kbd> - jump to parent note",
|
||||
"jumpToParentNote": "jump to parent note",
|
||||
"collapseWholeTree": "collapse whole note tree",
|
||||
"collapseSubTree": "collapse sub-tree",
|
||||
"tabShortcuts": "Tab shortcuts",
|
||||
"newTabNoteLink": "<kbd>Ctrl+click</kbd> - (or <kbd>middle mouse click</kbd>) on note link opens note in a new tab",
|
||||
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+click</kbd> - (or <kbd>Shift+middle mouse click</kbd>) on note link opens and activates the note in a new tab",
|
||||
"newTabNoteLink": "on note link opens note in a new tab",
|
||||
"newTabWithActivationNoteLink": "on note link opens and activates the note in a new tab",
|
||||
"onlyInDesktop": "Only in desktop (Electron build)",
|
||||
"openEmptyTab": "open empty tab",
|
||||
"closeActiveTab": "close active tab",
|
||||
@@ -142,14 +135,14 @@
|
||||
"moveNoteUpHierarchy": "move note up in the hierarchy",
|
||||
"multiSelectNote": "multi-select note above/below",
|
||||
"selectAllNotes": "select all notes in the current level",
|
||||
"selectNote": "<kbd>Shift+click</kbd> - select note",
|
||||
"selectNote": "select note",
|
||||
"copyNotes": "copy active note (or current selection) into clipboard (used for <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">cloning</a>)",
|
||||
"cutNotes": "cut current note (or current selection) into clipboard (used for moving notes)",
|
||||
"pasteNotes": "paste note(s) as sub-note into active note (which is either move or clone depending on whether it was copied or cut into clipboard)",
|
||||
"deleteNotes": "delete note / sub-tree",
|
||||
"editingNotes": "Editing notes",
|
||||
"editNoteTitle": "in tree pane will switch from tree pane into note title. Enter from note title will switch focus to text editor. <kbd>Ctrl+.</kbd> will switch back from editor to tree pane.",
|
||||
"createEditLink": "<kbd>Ctrl+K</kbd> - create / edit external link",
|
||||
"createEditLink": "create / edit external link",
|
||||
"createInternalLink": "create internal link",
|
||||
"followLink": "follow link under cursor",
|
||||
"insertDateTime": "insert current date and time at caret position",
|
||||
@@ -169,7 +162,6 @@
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Import into note",
|
||||
"close": "Close",
|
||||
"chooseImportFile": "Choose import file",
|
||||
"importDescription": "Content of the selected file(s) will be imported as child note(s) into",
|
||||
"options": "Options",
|
||||
@@ -196,14 +188,13 @@
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Include note",
|
||||
"close": "Close",
|
||||
"label_note": "Note",
|
||||
"placeholder_search": "search for note by its name",
|
||||
"box_size_prompt": "Box size of the included note:",
|
||||
"box_size_small": "small (~ 10 lines)",
|
||||
"box_size_medium": "medium (~ 30 lines)",
|
||||
"box_size_full": "full (box shows complete text)",
|
||||
"button_include": "Include note <kbd>enter</kbd>"
|
||||
"button_include": "Include note"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Info message",
|
||||
@@ -212,23 +203,20 @@
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Search for note by its name or type > for commands...",
|
||||
"close": "Close",
|
||||
"search_button": "Search in full text <kbd>Ctrl+Enter</kbd>"
|
||||
"search_button": "Search in full text"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Markdown import",
|
||||
"close": "Close",
|
||||
"modal_body_text": "Because of browser sandbox it's not possible to directly read clipboard from JavaScript. Please paste the Markdown to import to textarea below and click on Import button",
|
||||
"import_button": "Import Ctrl+Enter",
|
||||
"import_button": "Import",
|
||||
"import_success": "Markdown content has been imported into the document."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Move notes to ...",
|
||||
"close": "Close",
|
||||
"notes_to_move": "Notes to move",
|
||||
"target_parent_note": "Target parent note",
|
||||
"search_placeholder": "search for note by its name",
|
||||
"move_button": "Move to selected note <kbd>enter</kbd>",
|
||||
"move_button": "Move to selected note",
|
||||
"error_no_path": "No path to move to.",
|
||||
"move_success_message": "Selected notes have been moved into "
|
||||
},
|
||||
@@ -236,20 +224,19 @@
|
||||
"change_path_prompt": "Change where to create the new note:",
|
||||
"search_placeholder": "search path by name (default if empty)",
|
||||
"modal_title": "Choose note type",
|
||||
"close": "Close",
|
||||
"modal_body": "Choose note type / template of the new note:",
|
||||
"templates": "Templates:"
|
||||
"templates": "Templates",
|
||||
"builtin_templates": "Built-in Templates"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "Password is not set",
|
||||
"close": "Close",
|
||||
"body1": "Protected notes are encrypted using a user password, but password has not been set yet.",
|
||||
"body2": "To be able to protect notes, click <a class=\"open-password-options-button\" href=\"javascript:\">here</a> to open the Options dialog and set your password."
|
||||
"body2": "To be able to protect notes, click the button below to open the Options dialog and set your password.",
|
||||
"go_to_password_options": "Go to Password options"
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Prompt",
|
||||
"close": "Close",
|
||||
"ok": "OK <kbd>enter</kbd>",
|
||||
"ok": "OK",
|
||||
"defaultTitle": "Prompt"
|
||||
},
|
||||
"protected_session_password": {
|
||||
@@ -257,12 +244,11 @@
|
||||
"help_title": "Help on Protected notes",
|
||||
"close_label": "Close",
|
||||
"form_label": "To proceed with requested action you need to start protected session by entering password:",
|
||||
"start_button": "Start protected session <kbd>enter</kbd>"
|
||||
"start_button": "Start protected session"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Recent changes",
|
||||
"erase_notes_button": "Erase deleted notes now",
|
||||
"close": "Close",
|
||||
"deleted_notes_message": "Deleted notes have been erased.",
|
||||
"no_changes_message": "No changes yet...",
|
||||
"undelete_link": "undelete",
|
||||
@@ -273,7 +259,6 @@
|
||||
"delete_all_revisions": "Delete all revisions of this note",
|
||||
"delete_all_button": "Delete all revisions",
|
||||
"help_title": "Help on Note Revisions",
|
||||
"close": "Close",
|
||||
"revision_last_edited": "This revision was last edited on {{date}}",
|
||||
"confirm_delete_all": "Do you want to delete all revisions of this note?",
|
||||
"no_revisions": "No revisions for this note yet...",
|
||||
@@ -295,7 +280,6 @@
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Sort children by...",
|
||||
"close": "Close",
|
||||
"sorting_criteria": "Sorting criteria",
|
||||
"title": "title",
|
||||
"date_created": "date created",
|
||||
@@ -309,13 +293,12 @@
|
||||
"sort_with_respect_to_different_character_sorting": "sort with respect to different character sorting and collation rules in different languages or regions.",
|
||||
"natural_sort_language": "Natural sort language",
|
||||
"the_language_code_for_natural_sort": "The language code for natural sort, e.g. \"zh-CN\" for Chinese.",
|
||||
"sort": "Sort <kbd>enter</kbd>"
|
||||
"sort": "Sort"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Upload attachments to note",
|
||||
"close": "Close",
|
||||
"choose_files": "Choose files",
|
||||
"files_will_be_uploaded": "Files will be uploaded as attachments into",
|
||||
"files_will_be_uploaded": "Files will be uploaded as attachments into {{noteTitle}}",
|
||||
"options": "Options",
|
||||
"shrink_images": "Shrink images",
|
||||
"upload": "Upload",
|
||||
@@ -1118,12 +1101,12 @@
|
||||
"title": "Application Theme",
|
||||
"theme_label": "Theme",
|
||||
"override_theme_fonts_label": "Override theme fonts",
|
||||
"auto_theme": "Auto",
|
||||
"light_theme": "Light",
|
||||
"dark_theme": "Dark",
|
||||
"triliumnext": "TriliumNext Beta (Follow system color scheme)",
|
||||
"triliumnext-light": "TriliumNext Beta (Light)",
|
||||
"triliumnext-dark": "TriliumNext Beta (Dark)",
|
||||
"auto_theme": "Legacy (Follow system color scheme)",
|
||||
"light_theme": "Legacy (Light)",
|
||||
"dark_theme": "Legacy (Dark)",
|
||||
"triliumnext": "Trilium (Follow system color scheme)",
|
||||
"triliumnext-light": "Trilium (Light)",
|
||||
"triliumnext-dark": "Trilium (Dark)",
|
||||
"layout": "Layout",
|
||||
"layout-vertical-title": "Vertical",
|
||||
"layout-horizontal-title": "Horizontal",
|
||||
@@ -2007,6 +1990,15 @@
|
||||
"open_externally": "Open externally"
|
||||
},
|
||||
"modal": {
|
||||
"close": "Close"
|
||||
"close": "Close",
|
||||
"help_title": "Display more information about this screen"
|
||||
},
|
||||
"call_to_action": {
|
||||
"next_theme_title": "The new Trilium theme is now stable",
|
||||
"next_theme_message": "For a while now, we've been working on a new theme to give the application a more modern look.",
|
||||
"next_theme_button": "Switch to the new Trilium theme",
|
||||
"background_effects_title": "Background effects are now stable",
|
||||
"background_effects_message": "On Windows devices, background effects are now fully stable. The background effects adds a touch of color to the user interface by blurring the background behind it. This technique is also used in other applications such as Windows Explorer.",
|
||||
"background_effects_button": "Enable background effects"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Acerca de Trilium Notes",
|
||||
"close": "Cerrar",
|
||||
"homepage": "Página principal:",
|
||||
"app_version": "Versión de la aplicación:",
|
||||
"db_version": "Versión de base de datos:",
|
||||
@@ -28,25 +27,22 @@
|
||||
"add_link": {
|
||||
"add_link": "Agregar enlace",
|
||||
"help_on_links": "Ayuda sobre enlaces",
|
||||
"close": "Cerrar",
|
||||
"note": "Nota",
|
||||
"search_note": "buscar nota por su nombre",
|
||||
"link_title_mirrors": "el título del enlace replica el título actual de la nota",
|
||||
"link_title_arbitrary": "el título del enlace se puede cambiar arbitrariamente",
|
||||
"link_title": "Título del enlace",
|
||||
"button_add_link": "Agregar enlace <kbd>Enter</kbd>"
|
||||
"button_add_link": "Agregar enlace"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Editar prefijo de rama",
|
||||
"help_on_tree_prefix": "Ayuda sobre el prefijo del árbol",
|
||||
"close": "Cerrar",
|
||||
"prefix": "Prefijo: ",
|
||||
"save": "Guardar",
|
||||
"branch_prefix_saved": "Se ha guardado el prefijo de rama."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Acciones en bloque",
|
||||
"close": "Cerrar",
|
||||
"affected_notes": "Notas afectadas",
|
||||
"include_descendants": "Incluir descendientes de las notas seleccionadas",
|
||||
"available_actions": "Acciones disponibles",
|
||||
@@ -61,20 +57,18 @@
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Clonar notas a...",
|
||||
"close": "Cerrar",
|
||||
"help_on_links": "Ayuda sobre enlaces",
|
||||
"notes_to_clone": "Notas a clonar",
|
||||
"target_parent_note": "Nota padre de destino",
|
||||
"search_for_note_by_its_name": "buscar nota por su nombre",
|
||||
"cloned_note_prefix_title": "La nota clonada se mostrará en el árbol de notas con el prefijo dado",
|
||||
"prefix_optional": "Prefijo (opcional)",
|
||||
"clone_to_selected_note": "Clonar a nota seleccionada <kbd>enter</kbd>",
|
||||
"clone_to_selected_note": "Clonar a nota seleccionada",
|
||||
"no_path_to_clone_to": "No hay ruta para clonar.",
|
||||
"note_cloned": "La nota \"{{clonedTitle}}\" a sido clonada en \"{{targetTitle}}\""
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmación",
|
||||
"close": "Cerrar",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "Aceptar",
|
||||
"are_you_sure_remove_note": "¿Está seguro que desea eliminar la nota \"{{title}}\" del mapa de relaciones? ",
|
||||
@@ -87,9 +81,9 @@
|
||||
"delete_all_clones_description": "Eliminar también todos los clones (se puede deshacer en cambios recientes)",
|
||||
"erase_notes_description": "La eliminación normal (suave) solo marca las notas como eliminadas y se pueden recuperar (en el cuadro de diálogo de cambios recientes) dentro de un periodo de tiempo. Al marcar esta opción se borrarán las notas inmediatamente y no será posible recuperarlas.",
|
||||
"erase_notes_warning": "Eliminar notas permanentemente (no se puede deshacer), incluidos todos los clones. Esto forzará la recarga de la aplicación.",
|
||||
"notes_to_be_deleted": "Las siguientes notas serán eliminadas ({{- noteCount}})",
|
||||
"notes_to_be_deleted": "Las siguientes notas serán eliminadas ({{notesCount}})",
|
||||
"no_note_to_delete": "No se eliminará ninguna nota (solo clones).",
|
||||
"broken_relations_to_be_deleted": "Las siguientes relaciones se romperán y serán eliminadas ({{- relationCount}})",
|
||||
"broken_relations_to_be_deleted": "Las siguientes relaciones se romperán y serán eliminadas ({{ relationCount}})",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "Aceptar",
|
||||
"deleted_relation_text": "Nota {{- note}} (para ser eliminada) está referenciado por la relación {{- relation}} que se origina en {{- source}}."
|
||||
@@ -113,21 +107,19 @@
|
||||
"format_pdf": "PDF - para propósitos de impresión o compartición."
|
||||
},
|
||||
"help": {
|
||||
"fullDocumentation": "Ayuda (la documentación completa está disponible <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
|
||||
"close": "Cerrar",
|
||||
"noteNavigation": "Navegación de notas",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - subir/bajar en la lista de notas",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - colapsar/expandir nodo",
|
||||
"goUpDown": "subir/bajar en la lista de notas",
|
||||
"collapseExpand": "colapsar/expandir nodo",
|
||||
"notSet": "no establecido",
|
||||
"goBackForwards": "retroceder / avanzar en la historia",
|
||||
"showJumpToNoteDialog": "mostrar <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Saltar a\" diálogo</a>",
|
||||
"scrollToActiveNote": "desplazarse hasta la nota activa",
|
||||
"jumpToParentNote": "<kbd>Backspace</kbd> - saltar a la nota padre",
|
||||
"jumpToParentNote": "saltar a la nota padre",
|
||||
"collapseWholeTree": "colapsar todo el árbol de notas",
|
||||
"collapseSubTree": "colapsar subárbol",
|
||||
"tabShortcuts": "Atajos de pestañas",
|
||||
"newTabNoteLink": "<kbd>CTRL+clic</kbd> - (o <kbd>clic central del mouse</kbd>) en el enlace de la nota abre la nota en una nueva pestaña",
|
||||
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+clic</kbd> - (o <kbd>Shift+clic de rueda de ratón</kbd>) en el enlace de la nota abre y activa la nota en una nueva pestaña",
|
||||
"newTabNoteLink": "en el enlace de la nota abre la nota en una nueva pestaña",
|
||||
"newTabWithActivationNoteLink": "en el enlace de la nota abre y activa la nota en una nueva pestaña",
|
||||
"onlyInDesktop": "Solo en escritorio (compilación con Electron)",
|
||||
"openEmptyTab": "abrir pestaña vacía",
|
||||
"closeActiveTab": "cerrar pestaña activa",
|
||||
@@ -142,14 +134,14 @@
|
||||
"moveNoteUpHierarchy": "mover nota hacia arriba en la jerarquía",
|
||||
"multiSelectNote": "selección múltiple de nota hacia arriba/abajo",
|
||||
"selectAllNotes": "seleccionar todas las notas en el nivel actual",
|
||||
"selectNote": "<kbd>Shift+click</kbd> - seleccionar nota",
|
||||
"selectNote": "seleccionar nota",
|
||||
"copyNotes": "copiar nota activa (o selección actual) al portapapeles (usado para <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonar</a>)",
|
||||
"cutNotes": "cortar la nota actual (o la selección actual) en el portapapeles (usado para mover notas)",
|
||||
"pasteNotes": "pegar notas como subnotas en la nota activa (que se puede mover o clonar dependiendo de si se copió o cortó en el portapapeles)",
|
||||
"deleteNotes": "eliminar nota/subárbol",
|
||||
"editingNotes": "Editando notas",
|
||||
"editNoteTitle": "en el panel de árbol cambiará del panel de árbol al título de la nota. Ingresar desde el título de la nota cambiará el foco al editor de texto. <kbd>Ctrl+.</kbd> cambiará de nuevo del editor al panel de árbol.",
|
||||
"createEditLink": "<kbd>Ctrl+K</kbd> - crear/editar enlace externo",
|
||||
"createEditLink": "crear/editar enlace externo",
|
||||
"createInternalLink": "crear enlace interno",
|
||||
"followLink": "siga el enlace debajo del cursor",
|
||||
"insertDateTime": "insertar la fecha y hora actuales en la posición del cursor",
|
||||
@@ -169,7 +161,6 @@
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Importar a nota",
|
||||
"close": "Cerrar",
|
||||
"chooseImportFile": "Elija el archivo de importación",
|
||||
"importDescription": "El contenido de los archivos seleccionados se importará como notas secundarias en",
|
||||
"options": "Opciones",
|
||||
@@ -196,14 +187,13 @@
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Incluir nota",
|
||||
"close": "Cerrar",
|
||||
"label_note": "Nota",
|
||||
"placeholder_search": "buscar nota por su nombre",
|
||||
"box_size_prompt": "Tamaño de caja de la nota incluida:",
|
||||
"box_size_small": "pequeño (~ 10 líneas)",
|
||||
"box_size_medium": "medio (~ 30 líneas)",
|
||||
"box_size_full": "completo (el cuadro muestra el texto completo)",
|
||||
"button_include": "Incluir nota <kbd>Enter</kbd>"
|
||||
"button_include": "Incluir nota"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Mensaje informativo",
|
||||
@@ -211,24 +201,21 @@
|
||||
"okButton": "Aceptar"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"close": "Cerrar",
|
||||
"search_button": "Buscar en texto completo <kbd>Ctrl+Enter</kbd>",
|
||||
"search_button": "Buscar en texto completo",
|
||||
"search_placeholder": "Busque nota por su nombre o escriba > para comandos..."
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Importación de Markdown",
|
||||
"close": "Cerrar",
|
||||
"modal_body_text": "Debido al entorno limitado del navegador, no es posible leer directamente el portapapeles desde JavaScript. Por favor, pegue el código Markdown para importar en el área de texto a continuación y haga clic en el botón Importar",
|
||||
"import_button": "Importar Ctrl+Enter",
|
||||
"import_button": "Importar",
|
||||
"import_success": "El contenido de Markdown se ha importado al documento."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Mover notas a...",
|
||||
"close": "Cerrar",
|
||||
"notes_to_move": "Notas a mover",
|
||||
"target_parent_note": "Nota padre de destino",
|
||||
"search_placeholder": "buscar nota por su nombre",
|
||||
"move_button": "Mover a la nota seleccionada <kbd>enter</kbd>",
|
||||
"move_button": "Mover a la nota seleccionada",
|
||||
"error_no_path": "No hay ruta a donde mover.",
|
||||
"move_success_message": "Las notas seleccionadas se han movido a "
|
||||
},
|
||||
@@ -236,20 +223,16 @@
|
||||
"change_path_prompt": "Cambiar donde se creará la nueva nota:",
|
||||
"search_placeholder": "ruta de búsqueda por nombre (por defecto si está vacío)",
|
||||
"modal_title": "Elija el tipo de nota",
|
||||
"close": "Cerrar",
|
||||
"modal_body": "Elija el tipo de nota/plantilla de la nueva nota:",
|
||||
"templates": "Plantillas:"
|
||||
"templates": "Plantillas"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "La contraseña no está establecida",
|
||||
"close": "Cerrar",
|
||||
"body1": "Las notas protegidas se cifran mediante una contraseña de usuario, pero la contraseña aún no se ha establecido.",
|
||||
"body2": "Para poder proteger notas, dé clic <a class=\"open-password-options-button\" href=\"javascript:\">aquí</a> para abrir el diálogo de Opciones y establecer tu contraseña."
|
||||
"body1": "Las notas protegidas se cifran mediante una contraseña de usuario, pero la contraseña aún no se ha establecido."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Aviso",
|
||||
"close": "Cerrar",
|
||||
"ok": "Aceptar <kbd>enter</kbd>",
|
||||
"ok": "Aceptar",
|
||||
"defaultTitle": "Aviso"
|
||||
},
|
||||
"protected_session_password": {
|
||||
@@ -257,12 +240,11 @@
|
||||
"help_title": "Ayuda sobre notas protegidas",
|
||||
"close_label": "Cerrar",
|
||||
"form_label": "Para continuar con la acción solicitada, debe iniciar en la sesión protegida ingresando la contraseña:",
|
||||
"start_button": "Iniciar sesión protegida <kbd>entrar</kbd>"
|
||||
"start_button": "Iniciar sesión protegida"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Cambios recientes",
|
||||
"erase_notes_button": "Borrar notas eliminadas ahora",
|
||||
"close": "Cerrar",
|
||||
"deleted_notes_message": "Las notas eliminadas han sido borradas.",
|
||||
"no_changes_message": "Aún no hay cambios...",
|
||||
"undelete_link": "recuperar",
|
||||
@@ -273,7 +255,6 @@
|
||||
"delete_all_revisions": "Eliminar todas las revisiones de esta nota",
|
||||
"delete_all_button": "Eliminar todas las revisiones",
|
||||
"help_title": "Ayuda sobre revisiones de notas",
|
||||
"close": "Cerrar",
|
||||
"revision_last_edited": "Esta revisión se editó por última vez en {{date}}",
|
||||
"confirm_delete_all": "¿Quiere eliminar todas las revisiones de esta nota?",
|
||||
"no_revisions": "Aún no hay revisiones para esta nota...",
|
||||
@@ -295,7 +276,6 @@
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Ordenar hijos por...",
|
||||
"close": "Cerrar",
|
||||
"sorting_criteria": "Criterios de ordenamiento",
|
||||
"title": "título",
|
||||
"date_created": "fecha de creación",
|
||||
@@ -309,13 +289,12 @@
|
||||
"sort_with_respect_to_different_character_sorting": "ordenar con respecto a diferentes reglas de ordenamiento y clasificación de caracteres en diferentes idiomas o regiones.",
|
||||
"natural_sort_language": "Idioma de clasificación natural",
|
||||
"the_language_code_for_natural_sort": "El código del idioma para el ordenamiento natural, ej. \"zh-CN\" para Chino.",
|
||||
"sort": "Ordenar <kbd>Enter</kbd>"
|
||||
"sort": "Ordenar"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Cargar archivos adjuntos a nota",
|
||||
"close": "Cerrar",
|
||||
"choose_files": "Elija los archivos",
|
||||
"files_will_be_uploaded": "Los archivos se cargarán como archivos adjuntos en",
|
||||
"files_will_be_uploaded": "Los archivos se cargarán como archivos adjuntos en {{noteTitle}}",
|
||||
"options": "Opciones",
|
||||
"shrink_images": "Reducir imágenes",
|
||||
"upload": "Subir",
|
||||
@@ -1118,12 +1097,9 @@
|
||||
"title": "Tema",
|
||||
"theme_label": "Tema",
|
||||
"override_theme_fonts_label": "Sobreescribir fuentes de tema",
|
||||
"auto_theme": "Automático",
|
||||
"light_theme": "Claro",
|
||||
"dark_theme": "Oscuro",
|
||||
"triliumnext": "TriliumNext Beta (Sigue el esquema de color del sistema)",
|
||||
"triliumnext-light": "TriliumNext Beta (Claro)",
|
||||
"triliumnext-dark": "TriliumNext Beta (Oscuro)",
|
||||
"triliumnext": "Trilium (Sigue el esquema de color del sistema)",
|
||||
"triliumnext-light": "Trilium (Claro)",
|
||||
"triliumnext-dark": "Trilium (Oscuro)",
|
||||
"layout": "Disposición",
|
||||
"layout-vertical-title": "Vertical",
|
||||
"layout-horizontal-title": "Horizontal",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"about": {
|
||||
"close": "Chiudi",
|
||||
"app_version": "Versione dell'app:",
|
||||
"db_version": "Versione DB:",
|
||||
"sync_version": "Versione Sync:",
|
||||
@@ -27,7 +26,6 @@
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Aggiungi un collegamento",
|
||||
"close": "Chiudi",
|
||||
"note": "Nota",
|
||||
"search_note": "cerca una nota per nome",
|
||||
"link_title_mirrors": "il titolo del collegamento rispecchia il titolo della nota corrente",
|
||||
@@ -39,14 +37,12 @@
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Modifica il prefisso del ramo",
|
||||
"help_on_tree_prefix": "Aiuto sui prefissi dell'Albero",
|
||||
"close": "Chiudi",
|
||||
"prefix": "Prefisso: ",
|
||||
"save": "Salva",
|
||||
"branch_prefix_saved": "Il prefisso del ramo è stato salvato."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Azioni massive",
|
||||
"close": "Chiudi",
|
||||
"affected_notes": "Note influenzate",
|
||||
"include_descendants": "Includi i discendenti della nota selezionata",
|
||||
"available_actions": "Azioni disponibili",
|
||||
@@ -61,7 +57,6 @@
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Clona note in...",
|
||||
"close": "Chiudi",
|
||||
"help_on_links": "Aiuto sui collegamenti",
|
||||
"notes_to_clone": "Note da clonare",
|
||||
"target_parent_note": "Nodo padre obiettivo",
|
||||
@@ -73,7 +68,6 @@
|
||||
"note_cloned": "La nota \"{{clonedTitle}}\" è stata clonata in \"{{targetTitle}}\""
|
||||
},
|
||||
"confirm": {
|
||||
"close": "Chiudi",
|
||||
"cancel": "Annulla",
|
||||
"ok": "OK",
|
||||
"confirmation": "Conferma",
|
||||
@@ -106,47 +100,19 @@
|
||||
"choose_export_type": "Scegli prima il tipo di esportazione, per favore",
|
||||
"export_in_progress": "Esportazione in corso: {{progressCount}}",
|
||||
"export_finished_successfully": "Esportazione terminata con successo.",
|
||||
"format_pdf": "PDF- allo scopo di stampa o esportazione."
|
||||
},
|
||||
"help": {
|
||||
"close": "Chiudi",
|
||||
"fullDocumentation": "Aiuto (la documentazione completa è disponibile <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)"
|
||||
},
|
||||
"import": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"include_note": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"markdown_import": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"move_to": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"close": "Chiudi"
|
||||
"format_pdf": "PDF- allo scopo di stampa o esportazione.",
|
||||
"export_type_subtree": "Questa nota e tutti i suoi discendenti",
|
||||
"format_html": "HTML - raccomandato in quanto mantiene tutti i formati",
|
||||
"format_html_zip": "HTML in archivio ZIP - questo è raccomandato in quanto conserva tutta la formattazione.",
|
||||
"format_markdown": "MArkdown - questo conserva la maggior parte della formattazione."
|
||||
},
|
||||
"password_not_set": {
|
||||
"close": "Chiudi",
|
||||
"body1": "Le note protette sono crittografate utilizzando una password utente, ma la password non è stata ancora impostata.",
|
||||
"body2": "Per proteggere le note, fare clic su <a class=\"open-password-options-button\" href=\"javascript:\">qui</a> per aprire la finestra di dialogo Opzioni e impostare la password."
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Chiudi"
|
||||
},
|
||||
"prompt": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"recent_changes": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"revisions": {
|
||||
"close": "Chiudi"
|
||||
},
|
||||
"abstract_bulk_action": {
|
||||
"remove_this_search_action": "Rimuovi questa azione di ricerca"
|
||||
},
|
||||
|
||||
@@ -1,23 +1,866 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Trilium Notesについて",
|
||||
"close": "閉じる",
|
||||
"homepage": "ホームページ:",
|
||||
"app_version": "アプリのヴァージョン:",
|
||||
"db_version": "データベースのヴァージョン:",
|
||||
"sync_version": "同期のヴァージョン:",
|
||||
"build_date": "Build の日時:",
|
||||
"build_revision": "Build のヴァージョン:",
|
||||
"data_directory": "データの場所:"
|
||||
"about": {
|
||||
"title": "Trilium Notesについて",
|
||||
"homepage": "ホームページ:",
|
||||
"app_version": "アプリのバージョン:",
|
||||
"db_version": "データベースのバージョン:",
|
||||
"sync_version": "同期のバージョン:",
|
||||
"build_date": "Build の日時:",
|
||||
"build_revision": "Build のバージョン:",
|
||||
"data_directory": "データの場所:"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "致命的なエラー",
|
||||
"message": "致命的なエラーのせいでアプリをスタートできません:\n\n{{message}}\n\nおそらくスクリプトが予期しないバグを含んでいると思われます。アプリをセーフモードでスタートしてみて下さい。"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "致命的なエラー",
|
||||
"message": "致命的なエラーのせいでアプリをスタートできません:\n\n{{message}}\n\nおそらくスクリプトが予期しないバグを含んでいると思われます。アプリをセーフモードでスタートしてみて下さい。"
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "ウィジェットを初期化できませんでした",
|
||||
"message-custom": "ノートID”{{id}}”, ノートタイトル “{{title}}” のカスタムウィジェットを初期化できませんでした:\n\n{{message}}"
|
||||
}
|
||||
"widget-error": {
|
||||
"title": "ウィジェットを初期化できませんでした",
|
||||
"message-custom": "ノートID”{{id}}”, ノートタイトル “{{title}}” のカスタムウィジェットを初期化できませんでした:\n\n{{message}}",
|
||||
"message-unknown": "不明なウィジェットが初期化できませんでした。理由は以下の通りです:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "カスタムスクリプトの読み込みに失敗しました",
|
||||
"message": "ノートID”{{id}}”, ノートタイトル “{{title}}” のスクリプトを実行できませんでした。理由は以下の通りです:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "リンクを追加",
|
||||
"note": "ノート",
|
||||
"link_title": "リンクタイトル",
|
||||
"button_add_link": "リンクを追加",
|
||||
"help_on_links": "リンクに関するヘルプ",
|
||||
"search_note": "ノート名で検索",
|
||||
"link_title_mirrors": "リンクタイトルはノートタイトルの変更を反映します",
|
||||
"link_title_arbitrary": "リンクタイトルは自由に変更可能"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"save": "保存"
|
||||
},
|
||||
"global_menu": {
|
||||
"menu": "メニュー",
|
||||
"options": "オプション",
|
||||
"open_new_window": "新しいウィンドウを開く",
|
||||
"zoom": "ズーム",
|
||||
"toggle_fullscreen": "フルスクリーンの切り替え",
|
||||
"reset_zoom_level": "ズームレベルのリセット",
|
||||
"open_dev_tools": "開発者ツールを開く",
|
||||
"open_sql_console": "SQLコンソールを開く",
|
||||
"open_sql_console_history": "SQLコンソールの履歴を開く",
|
||||
"open_search_history": "検索履歴を開く",
|
||||
"show_backend_log": "バックエンドログの表示",
|
||||
"reload_hint": "リロードは、アプリ全体を再起動することなく、視覚的な不具合を解消することができます。",
|
||||
"reload_frontend": "フロントエンドをリロード",
|
||||
"show_hidden_subtree": "隠れたサブツリーを表示",
|
||||
"show_help": "ヘルプを表示",
|
||||
"about": "Trilium Notesについて",
|
||||
"logout": "ログアウト",
|
||||
"show-cheatsheet": "チートシートを表示",
|
||||
"zoom_out": "ズームアウト",
|
||||
"zoom_in": "ズームイン",
|
||||
"advanced": "高度",
|
||||
"toggle-zen-mode": "禅モード"
|
||||
},
|
||||
"left_pane_toggle": {
|
||||
"show_panel": "パネルを表示",
|
||||
"hide_panel": "パネルを隠す"
|
||||
},
|
||||
"move_pane_button": {
|
||||
"move_left": "左に移動",
|
||||
"move_right": "右に移動"
|
||||
},
|
||||
"clone_to": {
|
||||
"notes_to_clone": "クローンするノート",
|
||||
"target_parent_note": "ターゲットの親ノート",
|
||||
"search_for_note_by_its_name": "ノート名で検索",
|
||||
"cloned_note_prefix_title": "クローンされたノートは、指定された接頭辞を付けてノートツリーに表示されます",
|
||||
"prefix_optional": "接頭辞(任意)",
|
||||
"clone_to_selected_note": "選択したノートにクローン",
|
||||
"no_path_to_clone_to": "クローン先のパスが存在しません。",
|
||||
"note_cloned": "ノート \"{{clonedTitle}}\" は \"{{targetTitle}}\" にクローンされました",
|
||||
"clone_notes_to": "ノートをクローンして...",
|
||||
"help_on_links": "ヘルプへのリンク"
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_all_clones_description": "すべてのクローンも削除する(最近の変更では元に戻すことができる)",
|
||||
"erase_notes_description": "通常の(ソフト)削除では、ノートは削除されたものとしてマークされ、一定期間内に(最近の変更で)削除を取り消すことができます。このオプションをオンにすると、ノートは即座に削除され、削除を取り消すことはできません。",
|
||||
"erase_notes_warning": "すべてのクローンを含め、ノートを完全に消去します(元に戻せません)。これにより、アプリケーションは強制的にリロードされます。",
|
||||
"notes_to_be_deleted": "以下のノートが削除されます ({{notesCount}})",
|
||||
"no_note_to_delete": "ノートは削除されません(クローンのみ)。",
|
||||
"cancel": "キャンセル",
|
||||
"ok": "OK",
|
||||
"close": "閉じる"
|
||||
},
|
||||
"calendar": {
|
||||
"mon": "月",
|
||||
"tue": "火",
|
||||
"wed": "水",
|
||||
"thu": "木",
|
||||
"fri": "金",
|
||||
"sat": "土",
|
||||
"sun": "日",
|
||||
"january": "1月",
|
||||
"febuary": "2月",
|
||||
"march": "3月",
|
||||
"april": "4月",
|
||||
"may": "5月",
|
||||
"june": "6月",
|
||||
"july": "7月",
|
||||
"august": "8月",
|
||||
"september": "9月",
|
||||
"october": "10月",
|
||||
"november": "11月",
|
||||
"december": "12月"
|
||||
},
|
||||
"note_icon": {
|
||||
"change_note_icon": "ノートアイコンの変更",
|
||||
"category": "カテゴリー:",
|
||||
"search": "検索:",
|
||||
"reset-default": "アイコンをデフォルトに戻す"
|
||||
},
|
||||
"basic_properties": {
|
||||
"note_type": "ノートタイプ",
|
||||
"editable": "編集可能",
|
||||
"basic_properties": "基本プロパティ",
|
||||
"language": "言語"
|
||||
},
|
||||
"i18n": {
|
||||
"title": "ローカライゼーション",
|
||||
"language": "言語",
|
||||
"first-day-of-the-week": "週の最初",
|
||||
"sunday": "日曜日",
|
||||
"monday": "月曜日",
|
||||
"first-week-of-the-year": "年の最初の週",
|
||||
"first-week-contains-first-day": "最初の週には、元日が含まれる",
|
||||
"first-week-contains-first-thursday": "最初の週には、その年の最初の木曜日が含まれる",
|
||||
"first-week-has-minimum-days": "最初の週は最低日数",
|
||||
"min-days-in-first-week": "最初の週の最低日数",
|
||||
"first-week-info": "最初の週は、その年の最初の木曜日を含む週を指し、<a href=\"https://en.wikipedia.org/wiki/ISO_week_date#First_week\">ISO 8601</a>規格に基づいています。",
|
||||
"first-week-warning": "最初の週のオプションを変更すると、既存のウィークノートと重複する可能性があり、既存のウィークノートはそれに応じて更新されません。",
|
||||
"formatting-locale": "日付と数値のフォーマット"
|
||||
},
|
||||
"tab_row": {
|
||||
"close_tab": "タブを閉じる",
|
||||
"add_new_tab": "新しいタブ",
|
||||
"close": "閉じる",
|
||||
"close_other_tabs": "他のタブを閉じる",
|
||||
"close_right_tabs": "右側のタブをすべて閉じる",
|
||||
"close_all_tabs": "すべてのタブを閉じる",
|
||||
"reopen_last_tab": "最後に閉じたタブを開く",
|
||||
"move_tab_to_new_window": "このタブを新しいウィンドウに移動する",
|
||||
"copy_tab_to_new_window": "このタブを新しいウィンドウにコピーする"
|
||||
},
|
||||
"tasks": {
|
||||
"due": {
|
||||
"today": "今日",
|
||||
"tomorrow": "明日",
|
||||
"yesterday": "昨日"
|
||||
}
|
||||
},
|
||||
"classic_editor_toolbar": {
|
||||
"title": "書式設定"
|
||||
},
|
||||
"search_definition": {
|
||||
"add_search_option": "検索オプションを追加:",
|
||||
"search_string": "文字列検索",
|
||||
"search_script": "スクリプト検索",
|
||||
"fast_search": "高速検索",
|
||||
"fast_search_description": "高速検索オプションは、ノートの全文検索を無効にし、大規模データベースでの検索を高速化します。",
|
||||
"include_archived": "アーカイブを含む",
|
||||
"include_archived_notes_description": "アーカイブされたノートはデフォルトで検索結果から除外されますが、このオプションを使用すると含まれるようになります。",
|
||||
"order_by": "並べ替え",
|
||||
"limit": "リミット",
|
||||
"limit_description": "検索結果の数を制限する",
|
||||
"debug": "デバッグ",
|
||||
"debug_description": "デバッグは複雑なクエリのデバッグを支援するために、追加のデバッグ情報をコンソールに出力します",
|
||||
"action": "アクション",
|
||||
"search_button": "検索 <kbd>Enter</kbd>",
|
||||
"search_execute": "検索とアクションの実行",
|
||||
"save_to_note": "ノートに保存",
|
||||
"search_parameters": "検索パラメータ",
|
||||
"unknown_search_option": "不明な検索オプション {{searchOptionName}}",
|
||||
"search_note_saved": "検索ノートが {{- notePathTitle}} に保存されました",
|
||||
"actions_executed": "アクションが実行されました。"
|
||||
},
|
||||
"shortcuts": {
|
||||
"multiple_shortcuts": "同じアクションに対して複数のショートカットを設定する場合、カンマで区切ることができます。",
|
||||
"electron_documentation": "使用可能な修飾キーとキーコードについては、 <a href=\"https://www.electronjs.org/docs/latest/api/accelerator\">Electronのドキュメント</a>を参照してください。",
|
||||
"type_text_to_filter": "テキストを入力してショートカットを絞り込む...",
|
||||
"action_name": "アクション名",
|
||||
"shortcuts": "ショートカット",
|
||||
"default_shortcuts": "デフォルトのショートカットキー",
|
||||
"description": "説明",
|
||||
"reload_app": "リロードして変更を適用する",
|
||||
"set_all_to_default": "すべてのショートカットをデフォルトに戻す",
|
||||
"confirm_reset": "キーボードショートカットをすべてデフォルトにリセットしますか?",
|
||||
"keyboard_shortcuts": "キーボードショートカット"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "確認",
|
||||
"cancel": "キャンセル",
|
||||
"ok": "OK"
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "ノートをエクスポート",
|
||||
"close": "閉じる",
|
||||
"export_type_subtree": "このノートとすべての子孫",
|
||||
"format_html": "HTML - すべての書式が保たれるため、おすすめ",
|
||||
"format_html_zip": "HTML ZIPアーカイブ - すべての書式が保たれるため、推奨されます。",
|
||||
"format_markdown": "Markdown - ほとんどの書式が維持される。",
|
||||
"format_opml": "OPML - テキストのみのアウトライン交換フォーマットです。書式設定、画像、ファイルは含まれません。",
|
||||
"opml_version_1": "OPML v1.0 - プレーンテキストのみ",
|
||||
"opml_version_2": "OPML v2.0 - HTMLが許可されています",
|
||||
"export_type_single": "このノートのみで、子孫ノートは含まない",
|
||||
"export": "エクスポート",
|
||||
"choose_export_type": "最初にエクスポートタイプを選択してください",
|
||||
"export_status": "エクスポート状況",
|
||||
"export_in_progress": "エクスポート処理中: {{progressCount}}",
|
||||
"export_finished_successfully": "エクスポートが正常に完了しました。",
|
||||
"format_pdf": "PDF - 印刷または共有目的に。"
|
||||
},
|
||||
"help": {
|
||||
"title": "チートシート",
|
||||
"noteNavigation": "ノートナビゲーション",
|
||||
"collapseExpand": "ノードの格納/展開",
|
||||
"goBackForwards": "履歴を戻る/進む",
|
||||
"scrollToActiveNote": "アクティブノートまでスクロール",
|
||||
"jumpToParentNote": "親ノートへ移動",
|
||||
"collapseWholeTree": "すべてのノートツリーを格納",
|
||||
"collapseSubTree": "サブツリーを格納",
|
||||
"tabShortcuts": "タブショートカット",
|
||||
"newTabNoteLink": "ノートのリンクをクリックすると、新しいタブで開く",
|
||||
"newTabWithActivationNoteLink": "ノートのリンクをクリックすると、新しいタブで開き、アクティブにします",
|
||||
"onlyInDesktop": "デスクトップ版(Electronビルド)のみ",
|
||||
"openEmptyTab": "空のタブを開く",
|
||||
"closeActiveTab": "アクティブなタブを閉じる",
|
||||
"activateNextTab": "次のタブに移動",
|
||||
"activatePreviousTab": "前のタブに移動",
|
||||
"creatingNotes": "ノートの作成",
|
||||
"createNoteAfter": "アクティブなノートの後ろに新しいノートを作成",
|
||||
"createNoteInto": "アクティブなノートに新しいサブノートを作成",
|
||||
"movingCloningNotes": "ノートの移動/クローン",
|
||||
"moveNoteUpHierarchy": "階層内でノートを上下に移動",
|
||||
"multiSelectNote": "複数選択に上/下のノートを追加",
|
||||
"selectAllNotes": "現在のレベルのノートをすべて選択",
|
||||
"selectNote": "ノートを選択",
|
||||
"copyNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにコピーする(<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">クローン</a>に使用)",
|
||||
"cutNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにカットする(ノートの移動に使用)",
|
||||
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたかカットされたかに よって、移動またはクローンになる)",
|
||||
"deleteNotes": "ノート/サブツリーを削除",
|
||||
"editingNotes": "ノート編集",
|
||||
"editNoteTitle": "押下するとツリーペインからタイトルの編集に移ります。タイトルの編集からEnterキーを押すと、本文の編集に移動します。<kbd>Ctrl+.</kbd> で本文の編集からツリーペインに戻ります。",
|
||||
"createEditLink": "外部リンクの作成/編集",
|
||||
"createInternalLink": "内部リンクの作成",
|
||||
"followLink": "カーソル下のリンクをたどる",
|
||||
"insertDateTime": "カーソル位置に現在の日時を挿入",
|
||||
"jumpToTreePane": "ツリーペインにジャンプし、アクティブなノートまでスクロール",
|
||||
"markdownAutoformat": "Markdownライクな自動フォーマット",
|
||||
"headings": "<code>##</code>, <code>###</code>, <code>####</code> など。その後にスペースで見出しになる",
|
||||
"bulletList": "<code>*</code> または <code>-</code> その後にスペースで箇条書きになる",
|
||||
"numberedList": "<code>1.</code> または <code>1)</code> その後にスペースで番号付きリストになる",
|
||||
"blockQuote": "行の先頭に <code>></code> その後にスペースで引用になる",
|
||||
"troubleshooting": "トラブルシューティング",
|
||||
"reloadFrontend": "Triliumのフロントエンドをリロード",
|
||||
"showDevTools": "開発者ツールを表示",
|
||||
"showSQLConsole": "SQLコンソールを表示",
|
||||
"other": "その他",
|
||||
"quickSearch": "クイックサーチにフォーカス",
|
||||
"inPageSearch": "ページ内検索"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "ノートにインポート",
|
||||
"chooseImportFile": "インポートするファイルを選択",
|
||||
"importDescription": "選択されたファイルの内容は、子ノートとしてインポートされます",
|
||||
"options": "オプション",
|
||||
"safeImportTooltip": "Triliumの <code>.zip</code> 形式のエクスポートファイルには、有害な動作を含む実行可能スクリプトが含まれている可能性があります。セーフインポートは、インポートされたすべてのスクリプトの自動実行を無効にします。インポートするファイルの内容を完全に信頼できる場合のみ、「セーフインポート」のチェックを外してください。",
|
||||
"safeImport": "セーフインポート",
|
||||
"explodeArchivesTooltip": "これがチェックされている場合、Triliumは<code>.zip</code>、<code>.enex</code>、<code>.opml</code>ファイルを読み込み、それらのアーカイブからノートを作成します。チェックされていない場合、Triliumはアーカイブ自体をノートに添付します。",
|
||||
"shrinkImagesTooltip": "<p>これをチェックすると、Triliumはインポートされた画像を、拡大縮小や最適化によって縮小しようとします。これにより、画像の品質が損なわれる可能性があります。チェックを外すと、画像は変更されずにインポートされます。</p><p>これは、メタデータ付きの<code>.zip</code>インポートには適用されません。これらのファイルは既に最適化されていると考えられるためです。</p>",
|
||||
"shrinkImages": "画像を縮小",
|
||||
"textImportedAsText": "メタデータから判断できない場合は、HTML、Markdown、TXTをテキストノートとしてインポート",
|
||||
"codeImportedAsCode": "メタデータから判断できない場合は、コードファイル(例: <code>.json</code>)をコードノートとしてインポート",
|
||||
"replaceUnderscoresWithSpaces": "インポートされたノート名のアンダーバーをスペースに置換する",
|
||||
"import": "インポート",
|
||||
"failed": "インポートに失敗しました: {{message}}.",
|
||||
"html_import_tags": {
|
||||
"title": "HTMLインポートタグ",
|
||||
"description": "インポート時に保持するHTMLタグを設定します。このリストにないタグはインポート時に削除されます。一部のタグ('script'など)は、セキュリティ上の懸念から常に削除されます。",
|
||||
"placeholder": "HTMLタグを1行に1つ入力",
|
||||
"reset_button": "リストをデフォルトにリセット"
|
||||
},
|
||||
"import-status": "インポート状況",
|
||||
"in-progress": "インポート中: {{progress}}",
|
||||
"successful": "インポートは正常に終了しました。"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "パスワードが設定されていない",
|
||||
"body1": "保護されたノートはユーザーのパスワードを使用して暗号化されますが、パスワードはまだ設定されていません。",
|
||||
"body2": "ノートを保護するには、下のボタンをクリックしてオプションダイアログを開き、パスワードを設定してください。",
|
||||
"go_to_password_options": "パスワードのオプションへ"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "最近の変更",
|
||||
"erase_notes_button": "削除したメモを今すぐ消去する",
|
||||
"deleted_notes_message": "削除されたメモは完全に消去されました。",
|
||||
"no_changes_message": "変更はまだありません...",
|
||||
"undelete_link": "削除を取り消す",
|
||||
"confirm_undelete": "このノートとサブノートを復元しますか?"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "子ノートの並び替え...",
|
||||
"sorting_criteria": "ソート基準",
|
||||
"title": "タイトル",
|
||||
"date_created": "作成日",
|
||||
"date_modified": "更新日",
|
||||
"sorting_direction": "ソート方向",
|
||||
"ascending": "昇順",
|
||||
"descending": "降順",
|
||||
"folders": "フォルダ",
|
||||
"sort_folders_at_top": "フォルダーを一番上にソートする",
|
||||
"natural_sort": "自然順",
|
||||
"sort_with_respect_to_different_character_sorting": "言語や地域によって異なる文字の並べ替えや照合順序の規則に従ってソートする。",
|
||||
"sort": "ソート",
|
||||
"natural_sort_language": "自然順言語",
|
||||
"the_language_code_for_natural_sort": "自然順の言語コード。例えば、中国語の場合は \"zh-CN\"。"
|
||||
},
|
||||
"close_pane_button": {
|
||||
"close_this_pane": "ペインを閉じる"
|
||||
},
|
||||
"create_pane_button": {
|
||||
"create_new_split": "新しく分割する"
|
||||
},
|
||||
"edit_button": {
|
||||
"edit_this_note": "このノートを編集"
|
||||
},
|
||||
"show_toc_widget_button": {
|
||||
"show_toc": "目次を表示"
|
||||
},
|
||||
"show_highlights_list_widget_button": {
|
||||
"show_highlights_list": "ハイライト一覧を表示"
|
||||
},
|
||||
"relation_map_buttons": {
|
||||
"zoom_out_title": "ズームアウト",
|
||||
"zoom_in_title": "ズームイン"
|
||||
},
|
||||
"tree-context-menu": {
|
||||
"advanced": "高度",
|
||||
"open-in-a-new-tab": "新しいタブで開く <kbd>Ctrl+Click</kbd>",
|
||||
"open-in-a-new-split": "新しく分割して開く",
|
||||
"insert-note-after": "ノートを後ろに挿入",
|
||||
"insert-child-note": "子ノートを挿入",
|
||||
"delete": "削除",
|
||||
"search-in-subtree": "サブツリー内を検索",
|
||||
"expand-subtree": "サブツリーを展開",
|
||||
"collapse-subtree": "サブツリーを折りたたむ",
|
||||
"sort-by": "並べ替え...",
|
||||
"recent-changes-in-subtree": "サブツリー内の最近の変更",
|
||||
"copy-note-path-to-clipboard": "ノートのパスをクリップボードにコピー",
|
||||
"protect-subtree": "サブツリーを保護",
|
||||
"unprotect-subtree": "サブツリーの保護を解除",
|
||||
"copy-clone": "コピー/クローン",
|
||||
"clone-to": "クローンして...",
|
||||
"cut": "カット",
|
||||
"move-to": "移動して...",
|
||||
"paste-into": "貼り付け",
|
||||
"paste-after": "後ろに貼り付け",
|
||||
"duplicate": "複製",
|
||||
"export": "エクスポート",
|
||||
"import-into-note": "ノートにインポート",
|
||||
"apply-bulk-actions": "一括操作の適用",
|
||||
"converted-to-attachments": "{{count}}ノートが添付ファイルに変換されました。",
|
||||
"convert-to-attachment": "添付ファイルに変換",
|
||||
"convert-to-attachment-confirm": "選択したノートを親ノートの添付ファイルに変換しますか?",
|
||||
"open-in-popup": "クイックエディット"
|
||||
},
|
||||
"zen_mode": {
|
||||
"button_exit": "禅モードを退出"
|
||||
},
|
||||
"sync_status": {
|
||||
"unknown": "<p>同期状況は、次回の同期が開始されるとわかるようになります。</p><p>クリックして今すぐ同期を開始する。</p>",
|
||||
"connected_with_changes": "<p>同期サーバーに接続されました。<br>まだ同期されていない未処理の変更がいくつかあります。</p><p>クリックして同期を開始。</p>",
|
||||
"connected_no_changes": "<p>同期サーバーに接続されました。<br>すべての変更はすでに同期されています。</p><p>クリックして同期を開始。</p>",
|
||||
"disconnected_with_changes": "<p>同期サーバーへの接続の確立に失敗しました。<br>まだ同期されていない未処理の変更がいくつかあります。</p><p>クリックして同期を開始。</p>",
|
||||
"disconnected_no_changes": "<p>同期サーバーへの接続確立に失敗しました。<br>既知の変更はすべて同期されました。</p><p>クリックして同期を開始。</p>",
|
||||
"in_progress": "サーバーと同期中です。"
|
||||
},
|
||||
"note_actions": {
|
||||
"re_render_note": "ノートを再描画",
|
||||
"search_in_note": "ノート内検索",
|
||||
"note_source": "ノートのソース",
|
||||
"open_note_externally": "外部でノートを開く",
|
||||
"open_note_externally_title": "ファイルを外部アプリケーションで開き、変更を監視します。その後、変更されたバージョンをTriliumにアップロードできるようになります。",
|
||||
"open_note_custom": "プログラムからノートを開く",
|
||||
"import_files": "ファイルをインポート",
|
||||
"export_note": "ノートをエクスポート",
|
||||
"delete_note": "ノートを削除する",
|
||||
"print_note": "ノートを印刷",
|
||||
"print_pdf": "PDFとしてエクスポート..."
|
||||
},
|
||||
"command_palette": {
|
||||
"export_note_title": "ノートをエクスポート",
|
||||
"search_subtree_title": "サブツリー内を検索"
|
||||
},
|
||||
"delete_note": {
|
||||
"delete_note": "ノートを削除する"
|
||||
},
|
||||
"board_view": {
|
||||
"delete-note": "ノートを削除する"
|
||||
},
|
||||
"code_buttons": {
|
||||
"execute_button_title": "スクリプトを実行",
|
||||
"trilium_api_docs_button_title": "Trilium APIのドキュメントを開く",
|
||||
"save_to_note_button_title": "ノートに保存",
|
||||
"opening_api_docs_message": "APIドキュメントを開いています...",
|
||||
"sql_console_saved_message": "SQLコンソールが {{note_path}} に保存されました"
|
||||
},
|
||||
"execute_script": {
|
||||
"execute_script": "スクリプトを実行"
|
||||
},
|
||||
"script_executor": {
|
||||
"execute_script": "スクリプトを実行",
|
||||
"query": "クエリ",
|
||||
"script": "スクリプト",
|
||||
"execute_query": "クエリを実行"
|
||||
},
|
||||
"hide_floating_buttons_button": {
|
||||
"button_title": "ボタンを非表示"
|
||||
},
|
||||
"show_floating_buttons_button": {
|
||||
"button_title": "ボタンを表示"
|
||||
},
|
||||
"svg_export_button": {
|
||||
"button_title": "図をSVGとしてエクスポート"
|
||||
},
|
||||
"book_properties": {
|
||||
"grid": "グリッド",
|
||||
"list": "リスト",
|
||||
"collapse_all_notes": "すべてのノートを格納",
|
||||
"expand_all_children": "すべての子を展開",
|
||||
"collapse": "格納",
|
||||
"expand": "展開",
|
||||
"book_properties": "コレクションプロパティ",
|
||||
"invalid_view_type": "無効なビュータイプ '{{type}}'",
|
||||
"view_type": "ビュータイプ",
|
||||
"calendar": "カレンダー",
|
||||
"table": "テーブル",
|
||||
"geo-map": "ジオマップ",
|
||||
"board": "ボード"
|
||||
},
|
||||
"note_types": {
|
||||
"geo-map": "ジオマップ",
|
||||
"file": "ファイル",
|
||||
"image": "画像",
|
||||
"text": "テキスト",
|
||||
"code": "コード",
|
||||
"saved-search": "検索の保存",
|
||||
"relation-map": "関係マップ",
|
||||
"note-map": "ノートマップ",
|
||||
"render-note": "レンダリングノート",
|
||||
"book": "コレクション",
|
||||
"mermaid-diagram": "Mermaidダイアグラム",
|
||||
"canvas": "キャンバス",
|
||||
"web-view": "Web ビュー",
|
||||
"mind-map": "マインドマップ",
|
||||
"launcher": "ランチャー",
|
||||
"doc": "ドキュメント",
|
||||
"widget": "ウィジェット",
|
||||
"confirm-change": "ノートの内容が空ではない場合、ノートタイプを変更することは推奨されません。続行しますか?",
|
||||
"beta-feature": "Beta",
|
||||
"ai-chat": "AI チャット",
|
||||
"task-list": "タスクリスト",
|
||||
"new-feature": "新しい",
|
||||
"collections": "コレクション"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "この日の編集されたメモはまだありません...",
|
||||
"title": "編集されたノート",
|
||||
"deleted": "(削除済み)"
|
||||
},
|
||||
"file_properties": {
|
||||
"note_id": "ノート ID",
|
||||
"file_type": "ファイルタイプ",
|
||||
"file_size": "ファイルサイズ",
|
||||
"download": "ダウンロード",
|
||||
"open": "開く",
|
||||
"title": "ファイル"
|
||||
},
|
||||
"note_info_widget": {
|
||||
"note_id": "ノート ID",
|
||||
"created": "作成日時",
|
||||
"modified": "更新日時",
|
||||
"type": "タイプ",
|
||||
"note_size": "ノートサイズ",
|
||||
"calculate": "計算",
|
||||
"subtree_size": "(サブツリーサイズ: {{size}}、ノード数: {{count}})",
|
||||
"title": "ノート情報"
|
||||
},
|
||||
"image_properties": {
|
||||
"file_type": "ファイルタイプ",
|
||||
"file_size": "ファイルサイズ",
|
||||
"download": "ダウンロード",
|
||||
"open": "開く",
|
||||
"title": "画像"
|
||||
},
|
||||
"revisions": {
|
||||
"download_button": "ダウンロード",
|
||||
"delete_button": "削除"
|
||||
},
|
||||
"attachments_actions": {
|
||||
"download": "ダウンロード"
|
||||
},
|
||||
"etapi": {
|
||||
"created": "作成日時",
|
||||
"title": "ETAPI",
|
||||
"description": "ETAPI は、Trilium インスタンスに UI なしでプログラム的にアクセスするための REST API です。",
|
||||
"see_more": "詳細は{{- link_to_wiki}}と{{- link_to_openapi_spec}}または{{- link_to_swagger_ui }}を参照してください。",
|
||||
"wiki": "wiki",
|
||||
"openapi_spec": "ETAPI OpenAPIの仕様",
|
||||
"swagger_ui": "ETAPI Swagger UI",
|
||||
"create_token": "新しくETAPIトークンを作成",
|
||||
"existing_tokens": "既存のトークン",
|
||||
"no_tokens_yet": "トークンはまだありません。上のボタンをクリックして作成してください。",
|
||||
"token_name": "トークン名",
|
||||
"actions": "アクション",
|
||||
"new_token_title": "新しいETAPIトークン",
|
||||
"new_token_message": "新しいトークンの名前を入力",
|
||||
"rename_token_message": "新しいトークンの名前を入力",
|
||||
"default_token_name": "新しいトークン",
|
||||
"error_empty_name": "トークン名は空にできません",
|
||||
"token_created_title": "ETAPIトークン作成",
|
||||
"token_created_message": "作成されたトークンをクリップボードにコピーします。Trilium はトークンをハッシュ化して保存するため、これがトークンを見る最後の機会となります。",
|
||||
"rename_token": "トークン名を変更",
|
||||
"delete_token": "このトークンを削除/無効にする",
|
||||
"rename_token_title": "トークン名の変更",
|
||||
"delete_token_confirmation": "本当にETAPIトークン\"{{name}}\"を削除しますか?"
|
||||
},
|
||||
"note_paths": {
|
||||
"title": "ノートパス",
|
||||
"clone_button": "ノートを新しい場所にクローン...",
|
||||
"intro_placed": "このノートは以下のパスに置かれる:",
|
||||
"intro_not_placed": "このノートはまだノートツリーに配置されていません。",
|
||||
"archived": "アーカイブされた",
|
||||
"search": "検索"
|
||||
},
|
||||
"note_properties": {
|
||||
"info": "情報"
|
||||
},
|
||||
"similar_notes": {
|
||||
"title": "類似ノート",
|
||||
"no_similar_notes_found": "類似したノートが見つかりません。"
|
||||
},
|
||||
"abstract_search_option": {
|
||||
"remove_this_search_option": "この検索オプションを削除"
|
||||
},
|
||||
"debug": {
|
||||
"debug": "デバッグ",
|
||||
"debug_info": "デバッグは、複雑なクエリのデバッグを支援するために、追加のデバッグ情報をコンソールに表示します。",
|
||||
"access_info": "デバッグ情報にアクセスするには、クエリを実行し、左上隅にある \"バックエンドログを表示 \"をクリックしてください。"
|
||||
},
|
||||
"fast_search": {
|
||||
"fast_search": "高速検索",
|
||||
"description": "高速検索オプションは、ノートの全文検索を無効にし、大規模データベースでの検索を高速化します。"
|
||||
},
|
||||
"include_archived_notes": {
|
||||
"include_archived_notes": "アーカイブされたノートを含む"
|
||||
},
|
||||
"limit": {
|
||||
"limit": "リミット",
|
||||
"take_first_x_results": "最初からX個の結果のみを取得。"
|
||||
},
|
||||
"order_by": {
|
||||
"order_by": "並べ替え",
|
||||
"relevancy": "関連性(デフォルト)",
|
||||
"title": "タイトル",
|
||||
"date_created": "作成日",
|
||||
"date_modified": "最終更新日",
|
||||
"content_size": "ノート内容のサイズ",
|
||||
"children_count": "子ノートの数",
|
||||
"parent_count": "クローンの数",
|
||||
"random": "ランダムな順番",
|
||||
"asc": "昇順(デフォルト)",
|
||||
"desc": "降順"
|
||||
},
|
||||
"table_view": {
|
||||
"sort-column-descending": "降順",
|
||||
"sort-column-ascending": "昇順"
|
||||
},
|
||||
"search_script": {
|
||||
"title": "検索スクリプト:",
|
||||
"placeholder": "ノート名で検索"
|
||||
},
|
||||
"include_note": {
|
||||
"placeholder_search": "ノート名で検索",
|
||||
"dialog_title": "埋め込みノート",
|
||||
"box_size_prompt": "埋め込みノート枠のサイズ:",
|
||||
"button_include": "埋め込みノート"
|
||||
},
|
||||
"ancestor": {
|
||||
"placeholder": "ノート名で検索"
|
||||
},
|
||||
"move_to": {
|
||||
"search_placeholder": "ノート名で検索"
|
||||
},
|
||||
"web_view": {
|
||||
"web_view": "Web ビュー",
|
||||
"embed_websites": "Web ビュータイプでは、ウェブサイトをTriliumに埋め込むことができます。",
|
||||
"create_label": "まず始めに、埋め込みたいURLアドレスのラベルを作成してください。例: #webViewSrc=\"https://www.google.com\""
|
||||
},
|
||||
"backend_log": {
|
||||
"refresh": "リフレッシュ"
|
||||
},
|
||||
"sync": {
|
||||
"title": "同期"
|
||||
},
|
||||
"fonts": {
|
||||
"fonts": "フォント",
|
||||
"main_font": "メインフォント",
|
||||
"font_family": "フォントファミリー",
|
||||
"size": "サイズ",
|
||||
"note_tree_font": "ノートツリーフォント",
|
||||
"note_detail_font": "ノート詳細フォント",
|
||||
"monospace_font": "等幅(コード)フォント",
|
||||
"note_tree_and_detail_font_sizing": "ツリーと詳細のフォントサイズは、メインのフォントサイズに対して相対的であることに注意してください。",
|
||||
"not_all_fonts_available": "リストされているすべてのフォントが、お使いのシステムで利用できるとは限りません。",
|
||||
"apply_font_changes": "フォントの変更を適用するには、クリックしてください",
|
||||
"reload_frontend": "フロントエンドをリロード",
|
||||
"generic-fonts": "一般的なフォント",
|
||||
"sans-serif-system-fonts": "サンセリフのシステムフォント",
|
||||
"serif-system-fonts": "セリフのシステムフォント",
|
||||
"monospace-system-fonts": "等幅のシステムフォント",
|
||||
"handwriting-system-fonts": "手書きのシステムフォント",
|
||||
"serif": "セリフ",
|
||||
"sans-serif": "サンセリフ",
|
||||
"monospace": "等幅",
|
||||
"system-default": "システムのデフォルト"
|
||||
},
|
||||
"max_content_width": {
|
||||
"reload_button": "フロントエンドをリロード"
|
||||
},
|
||||
"theme": {
|
||||
"title": "アプリのテーマ",
|
||||
"theme_label": "テーマ",
|
||||
"override_theme_fonts_label": "テーマのフォントを上書き",
|
||||
"auto_theme": "レガシー(システムの配色に従う)",
|
||||
"light_theme": "レガシー(ライト)",
|
||||
"dark_theme": "レガシー(ダーク)",
|
||||
"triliumnext": "Trilium(システムの配色に従う)",
|
||||
"triliumnext-light": "Trilium(ライト)",
|
||||
"triliumnext-dark": "Trilium(ダーク)",
|
||||
"layout": "レイアウト",
|
||||
"layout-vertical-title": "垂直",
|
||||
"layout-horizontal-title": "水平",
|
||||
"layout-vertical-description": "ランチャーバーは左側(デフォルト)",
|
||||
"layout-horizontal-description": "ランチャーバーはタブバーの下にあり、タブバーは全幅に。"
|
||||
},
|
||||
"vim_key_bindings": {
|
||||
"use_vim_keybindings_in_code_notes": "Vimキーバインド",
|
||||
"enable_vim_keybindings": "Vimキーバインドをコードノートで有効にします(exモードはありません)"
|
||||
},
|
||||
"wrap_lines": {
|
||||
"wrap_lines_in_code_notes": "コードノートで行を折り返す",
|
||||
"enable_line_wrap": "行の折り返しを有効にする(変更を適用にするにはフロントエンドのリロードが必要な場合があります)"
|
||||
},
|
||||
"images": {
|
||||
"images_section_title": "画像",
|
||||
"download_images_automatically": "画像を自動的にダウンロードしてオフラインで使用可能にする。",
|
||||
"download_images_description": "貼り付けられたHTMLにはオンライン画像への参照が含まれていることがありますが、Triliumはそれらの参照を見つけて画像をダウンロードし、オフラインで利用できるようにします。",
|
||||
"enable_image_compression": "画像の圧縮を有効にする",
|
||||
"max_image_dimensions": "画像の最大幅/高さ(この設定を超えると画像はリサイズされます)。",
|
||||
"max_image_dimensions_unit": "ピクセル",
|
||||
"jpeg_quality_description": "JPEGの品質(10 - 最低品質、100 - 最高品質、50 - 80を推奨)"
|
||||
},
|
||||
"search_engine": {
|
||||
"title": "検索エンジン",
|
||||
"custom_search_engine_info": "カスタム検索エンジンは、名前とURLの両方を設定する必要があります。どちらも設定されていない場合、DuckDuckGoがデフォルトの検索エンジンとして使用されます。",
|
||||
"predefined_templates_label": "定義済みの検索エンジンのテンプレート",
|
||||
"bing": "Bing",
|
||||
"baidu": "Baidu",
|
||||
"duckduckgo": "DuckDuckGo",
|
||||
"google": "Google",
|
||||
"custom_name_label": "カスタム検索エンジンの名前",
|
||||
"custom_name_placeholder": "カスタム検索エンジンの名前",
|
||||
"custom_url_label": "カスタム検索エンジンのURLには、検索語句のプレースホルダーとして {keyword} を含める必要があります。",
|
||||
"custom_url_placeholder": "カスタム検索エンジンのurl",
|
||||
"save_button": "保存"
|
||||
},
|
||||
"tray": {
|
||||
"title": "システムトレイ",
|
||||
"enable_tray": "トレイを有効にする (この変更を適用にするには、Triliumを再起動する必要があります)"
|
||||
},
|
||||
"heading_style": {
|
||||
"title": "見出しのスタイル",
|
||||
"plain": "プレーン",
|
||||
"underline": "下線",
|
||||
"markdown": "Markdownスタイル"
|
||||
},
|
||||
"highlights_list": {
|
||||
"title": "ハイライトリスト",
|
||||
"description": "右のパネルに表示されるハイライトリストをカスタマイズできます:",
|
||||
"bold": "太字",
|
||||
"italic": "イタリック体",
|
||||
"underline": "下線",
|
||||
"color": "カラーテキスト",
|
||||
"bg_color": "背景色付きテキスト",
|
||||
"visibility_title": "ハイライトリスト表示",
|
||||
"visibility_description": "#hideHighlightWidget ラベルを追加することで、ノートごとにハイライトウィジェットを非表示にできます。",
|
||||
"shortcut_info": "オプション -> ショートカット('右ペイン切り替え')で、右ペイン(ハイライトを含む)を素早く切り替えるキーボードショートカットを設定できます。"
|
||||
},
|
||||
"table_of_contents": {
|
||||
"title": "目次",
|
||||
"description": "ノートに定義された数以上の見出しがある場合、テキストノートに目次が表示されます。この数はカスタマイズできます:",
|
||||
"unit": "見出し",
|
||||
"disable_info": "このオプションに非常に大きな数値を設定することで、目次を効果的に無効にすることもできる。",
|
||||
"shortcut_info": "オプション -> ショートカット('右ペイン切り替え')で、右ペイン(目次を含む)を素早く切り替えるキーボードショートカットを設定できます。"
|
||||
},
|
||||
"toc": {
|
||||
"table_of_contents": "目次"
|
||||
},
|
||||
"text_auto_read_only_size": {
|
||||
"title": "自動読み取り専用のサイズ",
|
||||
"description": "自動読み取り専用のノートサイズは、ノートが読み取り専用モード(パフォーマンス上の理由)で表示されるようになるサイズです。",
|
||||
"label": "自動読み取り専用のサイズ(テキストノート)",
|
||||
"unit": "文字"
|
||||
},
|
||||
"code_auto_read_only_size": {
|
||||
"title": "自動読み取り専用のサイズ",
|
||||
"description": "自動読み取り専用のノートサイズは、ノートが読み取り専用モード(パフォーマンス上の理由)で表示されるようになるサイズです。",
|
||||
"unit": "文字"
|
||||
},
|
||||
"custom_date_time_format": {
|
||||
"title": "日付/時刻フォーマットのカスタム",
|
||||
"description": "<kbd></kbd>またはツールバーから挿入される日付と時刻のフォーマットをカスタマイズする。 利用可能なトークンについては <a href=\"https://day.js.org/docs/en/display/format\" target=\"_blank\" rel=\"noopener noreferrer\">Day.js ドキュメント</a> を参照してください。",
|
||||
"format_string": "文字列形式:",
|
||||
"formatted_time": "日付/時刻形式:"
|
||||
},
|
||||
"backup": {
|
||||
"automatic_backup": "自動バックアップ",
|
||||
"automatic_backup_description": "Triliumは自動的にデータベースをバックアップすることができます:",
|
||||
"enable_daily_backup": "毎日バックアップ",
|
||||
"enable_weekly_backup": "毎週バックアップ",
|
||||
"enable_monthly_backup": "毎月バックアップ",
|
||||
"backup_recommendation": "バックアップはオンが推奨されますが、大規模なデータベースや低速なストレージデバイスの場合、アプリの起動を遅くする可能性があります。",
|
||||
"backup_now": "今すぐバックアップ",
|
||||
"backup_database_now": "今すぐデータベースをバックアップ",
|
||||
"existing_backups": "既存のバックアップ",
|
||||
"date-and-time": "日時",
|
||||
"path": "パス",
|
||||
"database_backed_up_to": "データベースは{{backupFilePath}}にバックアップされました",
|
||||
"no_backup_yet": "バックアップがありません"
|
||||
},
|
||||
"password": {
|
||||
"wiki": "wiki",
|
||||
"heading": "パスワード",
|
||||
"alert_message": "新しいパスワードは大切に保管してください。パスワードはウェブインターフェースへのログインや、保護されたノートの暗号化に使用されます。パスワードを忘れると、保護されたノートはすべて永久に失われます。",
|
||||
"reset_link": "リセットするにはここをクリック。",
|
||||
"old_password": "旧パスワード",
|
||||
"new_password": "新パスワード",
|
||||
"new_password_confirmation": "新パスワードの確認",
|
||||
"change_password": "パスワードの変更",
|
||||
"change_password_heading": "パスワードの変更",
|
||||
"protected_session_timeout": "保護されたセッションのタイムアウト",
|
||||
"protected_session_timeout_description": "保護されたセッションのタイムアウトは、保護されたセッションがブラウザのメモリから消去される時間です。これは、保護されたノートとの最後のやり取りから測定されます。参照",
|
||||
"for_more_info": "詳細はこちら。",
|
||||
"protected_session_timeout_label": "保護されたセッションのタイムアウト:",
|
||||
"reset_confirmation": "パスワードをリセットすると、保護されているすべてのノートにアクセスできなくなります。本当にパスワードをリセットしますか?",
|
||||
"reset_success_message": "パスワードがリセットされました。新しいパスワードを設定してください",
|
||||
"set_password_heading": "パスワードの設定",
|
||||
"set_password": "パスワードの設定",
|
||||
"password_mismatch": "新しいパスワードが同じではありません。",
|
||||
"password_changed_success": "パスワードが変更されました。OKを押すとTriliumがリロードされます。"
|
||||
},
|
||||
"spellcheck": {
|
||||
"title": "スペルチェック",
|
||||
"description": "これらのオプションはデスクトップビルドにのみ適用され、ブラウザはそれぞれのネイティブスペルチェックを使用します。",
|
||||
"enable": "スペルチェックを有効",
|
||||
"language_code_label": "言語コード",
|
||||
"language_code_placeholder": "例えば \"en-US\", \"de-AT\"",
|
||||
"multiple_languages_info": "複数の言語はカンマで区切ることができます。例: \"en-US, de-DE, cs\"。 ",
|
||||
"available_language_codes_label": "使用可能な言語コード:",
|
||||
"restart-required": "スペルチェックオプションの変更は、アプリケーションの再起動後に有効になります。"
|
||||
},
|
||||
"sync_2": {
|
||||
"config_title": "同期設定",
|
||||
"server_address": "サーバーインスタンスのアドレス",
|
||||
"timeout": "同期タイムアウト",
|
||||
"timeout_unit": "ミリ秒",
|
||||
"proxy_label": "同期プロキシサーバー(任意)",
|
||||
"note": "注",
|
||||
"note_description": "プロキシ設定を空白のままにすると、システムプロキシが使用されます(デスクトップ/electronビルドにのみ適用されます)。",
|
||||
"special_value_description": "もう一つの特別な値は <code>noproxy</code> で、これはシステムプロキシさえも無視して、 <code>NODE_TLS_REJECT_UNAUTHORIZED</code> を尊重するように強制します。",
|
||||
"save": "保存",
|
||||
"help": "ヘルプ",
|
||||
"test_title": "同期のテスト",
|
||||
"test_description": "これは同期サーバとの接続とハンドシェイクをテストします。同期サーバーが初期化されていない場合、ローカルドキュメントと同期するように設定します。",
|
||||
"test_button": "同期試行",
|
||||
"handshake_failed": "同期サーバーのハンドシェイクに失敗しました。エラー: {{message}}"
|
||||
},
|
||||
"api_log": {
|
||||
"close": "閉じる"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "閉じる"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "閉じる"
|
||||
},
|
||||
"modal": {
|
||||
"close": "閉じる"
|
||||
},
|
||||
"bookmark_switch": {
|
||||
"bookmark": "ブックマーク",
|
||||
"bookmark_this_note": "このノートを左サイドパネルにブックマークする",
|
||||
"remove_bookmark": "ブックマークを削除"
|
||||
},
|
||||
"attribute_detail": {
|
||||
"delete": "削除"
|
||||
},
|
||||
"link_context_menu": {
|
||||
"open_note_in_popup": "クイックエディット"
|
||||
},
|
||||
"note_tooltip": {
|
||||
"quick-edit": "クイックエディット"
|
||||
},
|
||||
"protect_note": {
|
||||
"toggle-on": "ノートを保護",
|
||||
"toggle-off": "ノートの保護を解除",
|
||||
"toggle-on-hint": "ノートは保護されていません。クリックして保護してください",
|
||||
"toggle-off-hint": "ノートは保護されています。クリックして保護を解除してください"
|
||||
},
|
||||
"shared_switch": {
|
||||
"shared": "共有",
|
||||
"toggle-on-title": "ノートを共有",
|
||||
"toggle-off-title": "ノートの共有を解除",
|
||||
"shared-branch": "このノートは共有ノートとしてのみ存在し、共有を解除すると削除されます。続行してこのノートを削除しますか?",
|
||||
"inherited": "このノートは、親から継承された共有方法のため、ここでは共有解除できません。"
|
||||
},
|
||||
"template_switch": {
|
||||
"template": "テンプレート",
|
||||
"toggle-on-hint": "ノートをテンプレート化する"
|
||||
},
|
||||
"open-help-page": "ヘルプページを開く",
|
||||
"shared_info": {
|
||||
"shared_publicly": "このノートは一般公開されています",
|
||||
"shared_locally": "このノートはローカルで共有されています",
|
||||
"help_link": "ヘルプについては、<a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>をご覧ください。"
|
||||
},
|
||||
"highlights_list_2": {
|
||||
"title": "ハイライトリスト",
|
||||
"options": "オプション"
|
||||
},
|
||||
"quick-search": {
|
||||
"placeholder": "クイックサーチ",
|
||||
"searching": "検索中...",
|
||||
"no-results": "結果は見つかりませんでした",
|
||||
"more-results": "... および {{number}} 件の他の結果。",
|
||||
"show-in-full-search": "検索結果をすべて表示"
|
||||
},
|
||||
"note_tree": {
|
||||
"collapse-title": "ノートツリーを折りたたむ",
|
||||
"scroll-active-title": "アクティブノートまでスクロール",
|
||||
"tree-settings-title": "ツリーの設定",
|
||||
"hide-archived-notes": "アーカイブノートを隠す",
|
||||
"automatically-collapse-notes": "ノートを自動的に折りたたむ",
|
||||
"automatically-collapse-notes-title": "一定期間使用されないと、ツリーを整理するためにノートは折りたたまれます。",
|
||||
"save-changes": "変更を保存して適用"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,416 +1,414 @@
|
||||
{
|
||||
"code_block": {
|
||||
"theme_none": "Sem destaque de sintaxe",
|
||||
"theme_group_light": "Temas claros",
|
||||
"theme_group_dark": "Temas escuros"
|
||||
"code_block": {
|
||||
"theme_none": "Sem destaque de sintaxe",
|
||||
"theme_group_light": "Temas claros",
|
||||
"theme_group_dark": "Temas escuros"
|
||||
},
|
||||
"about": {
|
||||
"title": "Sobre o Trilium Notes",
|
||||
"homepage": "Página inicial:",
|
||||
"app_version": "Versão do App:",
|
||||
"db_version": "Versão do db:",
|
||||
"sync_version": "Versão de sincronização:",
|
||||
"build_date": "Data de compilação:",
|
||||
"build_revision": "Revisão da compilação:",
|
||||
"data_directory": "Diretório de dados:"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Erro crítico",
|
||||
"message": "Ocorreu um erro crítico que impede a inicialização do aplicativo cliente:\n\n{{message}}\n\nIsso provavelmente foi causado por um script que falhou de maneira inesperada. Tente iniciar o aplicativo no modo seguro e resolva o problema."
|
||||
},
|
||||
"about": {
|
||||
"title": "Sobre o Trilium Notes",
|
||||
"close": "Fechar",
|
||||
"homepage": "Página inicial:",
|
||||
"app_version": "Versão do App:",
|
||||
"db_version": "Versão do db:",
|
||||
"sync_version": "Versão de sincronização:",
|
||||
"build_date": "Data de compilação:",
|
||||
"build_revision": "Revisão da compilação:",
|
||||
"data_directory": "Diretório de dados:"
|
||||
"widget-error": {
|
||||
"title": "Falha ao inicializar um widget",
|
||||
"message-custom": "O widget personalizado da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser inicializado devido a:\n\n{{message}}",
|
||||
"message-unknown": "Widget desconhecido não pôde ser inicializado devido a:\n\n{{message}}"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Erro crítico",
|
||||
"message": "Ocorreu um erro crítico que impede a inicialização do aplicativo cliente:\n\n{{message}}\n\nIsso provavelmente foi causado por um script que falhou de maneira inesperada. Tente iniciar o aplicativo no modo seguro e resolva o problema."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Falha ao inicializar um widget",
|
||||
"message-custom": "O widget personalizado da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser inicializado devido a:\n\n{{message}}",
|
||||
"message-unknown": "Widget desconhecido não pôde ser inicializado devido a:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Falha para carregar o script customizado",
|
||||
"message": "O script da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser executado devido a:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Adicionar link",
|
||||
"help_on_links": "Ajuda sobre links",
|
||||
"close": "Fechar",
|
||||
"note": "Nota",
|
||||
"search_note": "pesquisar nota pelo nome",
|
||||
"link_title_mirrors": "o título do link reflete o título atual da nota",
|
||||
"link_title_arbitrary": "o título do link pode ser alterado livremente",
|
||||
"link_title": "Titulo do link",
|
||||
"button_add_link": "Adicionar link <kbd>enter</kbd>"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"close": "Fechar",
|
||||
"prefix": "Prefixo: ",
|
||||
"save": "Salvar",
|
||||
"edit_branch_prefix": "Editar Prefixo do Branch",
|
||||
"help_on_tree_prefix": "Ajuda sobre o prefixo da árvore de notas",
|
||||
"branch_prefix_saved": "O prefixo de ramificação foi salvo."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Ações em massa",
|
||||
"close": "Fechar",
|
||||
"affected_notes": "Notas Afetadas",
|
||||
"include_descendants": "Incluir notas filhas das notas selecionadas",
|
||||
"available_actions": "Ações disponíveis",
|
||||
"chosen_actions": "Ações selecionadas",
|
||||
"execute_bulk_actions": "Executar ações em massa",
|
||||
"bulk_actions_executed": "As ações em massa foram concluídas com sucesso.",
|
||||
"none_yet": "Nenhuma até agora... adicione uma ação clicando em uma das disponíveis acima.",
|
||||
"labels": "Etiquetas",
|
||||
"relations": "Relações",
|
||||
"notes": "Notas",
|
||||
"other": "Outros"
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Clonar notas para...",
|
||||
"close": "Fechar",
|
||||
"help_on_links": "Ajuda sobre links",
|
||||
"notes_to_clone": "Notas para clonar",
|
||||
"search_for_note_by_its_name": "pesquisar nota pelo nome",
|
||||
"cloned_note_prefix_title": "A nota clonada aparecerá na árvore de notas com o prefixo fornecido",
|
||||
"prefix_optional": "Prefixo (opcional)",
|
||||
"no_path_to_clone_to": "Nenhum caminho para clonar.",
|
||||
"target_parent_note": "Nota pai-alvo",
|
||||
"clone_to_selected_note": "Clonar para a nota selecionada <kbd>enter</kbd>",
|
||||
"note_cloned": "A nota \"{{clonedTitle}}\" foi clonada para \"{{targetTitle}}\""
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} nota enfileirada para indexação",
|
||||
"n_notes_queued_1": "{{ count }} notas enfileiradas para indexação",
|
||||
"n_notes_queued_2": "{{ count }} notas enfileiradas para indexação",
|
||||
"notes_indexed_0": "{{ count }} nota indexada",
|
||||
"notes_indexed_1": "{{ count }} notas indexadas",
|
||||
"notes_indexed_2": "{{ count }} notas indexadas"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmação",
|
||||
"close": "Fechar",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "OK",
|
||||
"are_you_sure_remove_note": "Tem certeza de que deseja remover a nota '{{title}}' do mapa de relações? ",
|
||||
"if_you_dont_check": "Se você não marcar isso, a nota será removida apenas do mapa de relações.",
|
||||
"also_delete_note": "Também excluir a nota"
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_notes_preview": "Excluir pré-visualização de notas",
|
||||
"close": "Fechar",
|
||||
"delete_all_clones_description": "Excluir também todos os clones (pode ser desfeito em alterações recentes)",
|
||||
"erase_notes_description": "A exclusão normal (suave) apenas marca as notas como excluídas, permitindo que sejam recuperadas (no diálogo de alterações recentes) dentro de um período de tempo. Se esta opção for marcada, as notas serão apagadas imediatamente e não será possível restaurá-las.",
|
||||
"erase_notes_warning": "Apagar notas permanentemente (não pode ser desfeito), incluindo todos os clones. Isso forçará o recarregamento do aplicativo.",
|
||||
"notes_to_be_deleted": "As seguintes notas serão excluídas ({{- noteCount}})",
|
||||
"no_note_to_delete": "Nenhuma nota será excluída (apenas os clones).",
|
||||
"broken_relations_to_be_deleted": "As seguintes relações serão quebradas e excluídas ({{- relationCount}})",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "OK",
|
||||
"deleted_relation_text": "A nota {{- note}} (a ser excluída) está referenciada pela relação {{- relation}} originada de {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "Exportar nota",
|
||||
"close": "Fechar",
|
||||
"export_type_subtree": "Esta nota e todos os seus descendentes",
|
||||
"format_html": "HTML – recomendado, pois mantém toda a formatação",
|
||||
"format_html_zip": "HTML em arquivo ZIP – recomendado, pois isso preserva toda a formatação.",
|
||||
"format_markdown": "Markdown – isso preserva a maior parte da formatação.",
|
||||
"format_opml": "OPML - formato de intercâmbio de outliners apenas para texto. Formatação, imagens e arquivos não estão incluídos.",
|
||||
"opml_version_1": "OPML v1.0 – apenas texto simples",
|
||||
"opml_version_2": "OPML v2.0 – permite também HTML",
|
||||
"export_type_single": "Apenas esta nota, sem seus descendentes",
|
||||
"export": "Exportar",
|
||||
"choose_export_type": "Por favor, escolha primeiro o tipo de exportação",
|
||||
"export_status": "Status da exportação",
|
||||
"export_in_progress": "Exportação em andamento: {{progressCount}}",
|
||||
"export_finished_successfully": "Exportação concluída com sucesso.",
|
||||
"format_pdf": "PDF – para impressão ou compartilhamento."
|
||||
},
|
||||
"help": {
|
||||
"fullDocumentation": "Ajuda (a documentação completa está disponível <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
|
||||
"close": "Fechar",
|
||||
"noteNavigation": "Navegação de notas",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> – subir/descer na lista de notas",
|
||||
"collapseExpand": "<kbd>ESQUERDA</kbd>, <kbd>DIREITA</kbd> – recolher/expandir nó",
|
||||
"notSet": "não definido",
|
||||
"goBackForwards": "voltar / avançar no histórico",
|
||||
"showJumpToNoteDialog": "mostrar diálogo <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Ir para\"</a>",
|
||||
"scrollToActiveNote": "rolar até a nota atual",
|
||||
"jumpToParentNote": "<kbd>Backspace</kbd> – ir para a nota pai",
|
||||
"collapseWholeTree": "recolher toda a árvore de notas",
|
||||
"collapseSubTree": "recolher subárvore",
|
||||
"tabShortcuts": "Atalhos de abas",
|
||||
"newTabNoteLink": "<kbd>Ctrl+clique</kbd> – (ou <kbd>clique com o botão do meio do mouse</kbd>) em um link de nota abre a nota em uma nova aba",
|
||||
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+clique</kbd> – (ou <kbd>Shift+clique com o botão do meio do mouse</kbd>) em um link de nota abre e ativa a nota em uma nova aba",
|
||||
"onlyInDesktop": "Apenas na versão para desktop (compilação Electron)",
|
||||
"openEmptyTab": "abrir aba vazia",
|
||||
"closeActiveTab": "fechar aba ativa",
|
||||
"activateNextTab": "ativar próxima aba",
|
||||
"activatePreviousTab": "ativar aba anterior",
|
||||
"creatingNotes": "Criando notas",
|
||||
"createNoteAfter": "criar nova nota após a nota atual",
|
||||
"createNoteInto": "criar nova subnota dentro da nota atual",
|
||||
"editBranchPrefix": "editar <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefixo</a> do clone da nota ativa",
|
||||
"movingCloningNotes": "Movendo / clonando notas",
|
||||
"moveNoteUpDown": "mover nota para cima/baixo na lista de notas",
|
||||
"moveNoteUpHierarchy": "mover nota para cima na hierarquia",
|
||||
"multiSelectNote": "selecionar múltiplas notas acima/abaixo",
|
||||
"selectAllNotes": "selecionar todas as notas no nível atual",
|
||||
"selectNote": "<kbd>Shift+clique</kbd> - selecionar nota",
|
||||
"copyNotes": "copiar nota ativa (ou seleção atual) para a área de transferência (usado para <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonar</a>)",
|
||||
"cutNotes": "recortar nota atual (ou seleção atual) para a área de transferência (usado para mover notas)",
|
||||
"pasteNotes": "colar nota(s) como subnota dentro da nota ativa (o que pode ser mover ou clonar dependendo se foi copiado ou recortado para a área de transferência)",
|
||||
"deleteNotes": "excluir nota / subárvore",
|
||||
"editingNotes": "Edição de notas",
|
||||
"editNoteTitle": "no painel de árvore, a navegação mudará do painel de árvore para o título da nota. Pressionar Enter no título da nota mudará o foco para o editor de texto. <kbd>Ctrl+.</kbd> mudará o foco de volta do editor para o painel de árvore.",
|
||||
"createEditLink": "<kbd>Ctrl+K</kbd> - criar / editar link externo",
|
||||
"createInternalLink": "criar link interno",
|
||||
"followLink": "seguir link sob o cursor",
|
||||
"insertDateTime": "inserir data e hora atual na posição do cursor",
|
||||
"jumpToTreePane": "ir para a árvore de notas e rolar até a nota ativa",
|
||||
"markdownAutoformat": "Autoformatação estilo Markdown",
|
||||
"headings": "<code>##</code>, <code>###</code>, <code>####</code> etc. seguidos de espaço para títulos",
|
||||
"bulletList": "<code>*</code> ou <code>-</code> seguidos de espaço para lista com marcadores",
|
||||
"numberedList": "<code>1.</code> ou <code>1)</code> seguidos de espaço para lista numerada",
|
||||
"blockQuote": "comece uma linha com <code>></code> seguido de espaço para citação em bloco",
|
||||
"troubleshooting": "Solução de problemas",
|
||||
"reloadFrontend": "recarregar o frontend do Trilium",
|
||||
"showDevTools": "mostrar ferramentas de desenvolvedor",
|
||||
"showSQLConsole": "mostrar console SQL",
|
||||
"other": "Outros",
|
||||
"quickSearch": "focar no campo de pesquisa rápida",
|
||||
"inPageSearch": "pesquisa na página"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Importar para a nota",
|
||||
"close": "Fechar",
|
||||
"chooseImportFile": "Escolher arquivo para importar",
|
||||
"importDescription": "O conteúdo do(s) arquivo(s) selecionado(s) será importado como nota(s) filha(s) em",
|
||||
"options": "Opções",
|
||||
"safeImportTooltip": "Arquivos de exportação Trilium<code> .zip</code> podem conter scripts executáveis que podem apresentar comportamentos prejudiciais. A importação segura desativará a execução automática de todos os scripts importados. Desmarque “Importação segura” apenas se o arquivo de importação contiver scripts executáveis e você confiar totalmente no conteúdo do arquivo importado.",
|
||||
"safeImport": "Importação segura",
|
||||
"explodeArchivesTooltip": "Se esta opção estiver marcada, o Trilium irá ler arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code> e criar notas a partir dos arquivos contidos nesses arquivos compactados. Se estiver desmarcada, o Trilium irá anexar os próprios arquivos compactados à nota.",
|
||||
"explodeArchives": "Ler conteúdos de arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code>.",
|
||||
"shrinkImagesTooltip": "<p>Se você marcar esta opção, o Trilium tentará reduzir o tamanho das imagens importadas por meio de escala e otimização, o que pode afetar a qualidade visual das imagens. Se desmarcada, as imagens serão importadas sem alterações.</p><p>Isso não se aplica a importações de arquivos <code>.zip</code> com metadados, pois presume-se que esses arquivos já estejam otimizados.</p>",
|
||||
"shrinkImages": "Reduzir imagens",
|
||||
"textImportedAsText": "Importar arquivos HTML, Markdown e TXT como notas de texto caso não esteja claro pelos metadados",
|
||||
"codeImportedAsCode": "Importar arquivos de código reconhecidos (por exemplo, <code>.json</code>) como notas de código caso não esteja claro pelos metadados",
|
||||
"replaceUnderscoresWithSpaces": "Substituir sublinhados por espaços nos nomes das notas importadas",
|
||||
"import": "Importar",
|
||||
"failed": "Falha na importação: {{message}}.",
|
||||
"html_import_tags": {
|
||||
"title": "Tags de importação HTML",
|
||||
"description": "Configurar quais tags HTML devem ser preservadas ao importar notas. As tags que não estiverem nesta lista serão removidas durante a importação. Algumas tags (como 'script') são sempre removidas por motivos de segurança.",
|
||||
"placeholder": "Digite as tags HTML, uma por linha",
|
||||
"reset_button": "Redefinir para lista padrão"
|
||||
},
|
||||
"import-status": "Status da importação",
|
||||
"in-progress": "Importação em andamento: {{progress}}",
|
||||
"successful": "Importação concluída com sucesso."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Incluir nota",
|
||||
"close": "Fechar",
|
||||
"label_note": "Nota",
|
||||
"placeholder_search": "pesquisar nota pelo nome",
|
||||
"box_size_prompt": "Dimensão da caixa da nota incluída:",
|
||||
"box_size_small": "pequeno (~ 10 linhas)",
|
||||
"box_size_medium": "médio (~ 30 linhas)",
|
||||
"box_size_full": "completo (a caixa exibe o texto completo)",
|
||||
"button_include": "Incluir nota <kbd>enter</kbd>"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Mensagem informativa",
|
||||
"closeButton": "Fechar",
|
||||
"okButton": "OK"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Pesquise uma nota pelo nome ou digite > para comandos...",
|
||||
"close": "Fechar",
|
||||
"search_button": "Pesquisar em texto completo <kbd>Ctrl+Enter</kbd>"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Importar Markdown",
|
||||
"close": "Fechar",
|
||||
"modal_body_text": "Por motivos de segurança (sandbox do navegador), o JavaScript não pode acessar diretamente a área de transferência. Por favor, cole o conteúdo Markdown na área de texto abaixo e clique em Importar",
|
||||
"import_button": "Importar Ctrl+Enter",
|
||||
"import_success": "O conteúdo Markdown foi importado para o documento."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Mover notas para...",
|
||||
"close": "Fechar",
|
||||
"notes_to_move": "Notas para mover",
|
||||
"target_parent_note": "Nota pai-alvo",
|
||||
"search_placeholder": "pesquisar nota pelo nome",
|
||||
"move_button": "Mover para a nota selecionada <kbd>enter</kbd>",
|
||||
"error_no_path": "Nenhum caminho para mover.",
|
||||
"move_success_message": "As notas selecionadas foram movidas para "
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"change_path_prompt": "Alterar onde criar a nova nota:",
|
||||
"search_placeholder": "buscar caminho pelo nome (valor padrão se não for preenchido)",
|
||||
"modal_title": "Escolher tipo de nota",
|
||||
"close": "Fechar",
|
||||
"modal_body": "Escolha o tipo/modelo da nova nota:",
|
||||
"templates": "Modelos:"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "A senha não está definida",
|
||||
"close": "Fechar",
|
||||
"body1": "Notas protegidas são criptografadas usando uma senha do usuário, mas a senha ainda não foi definida.",
|
||||
"body2": "Para poder proteger notas, clique <a class=\"open-password-options-button\" href=\"javascript:\">aqui</a> para abrir a caixa de diálogo de Opções e definir sua senha."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Prompt",
|
||||
"close": "Fechar",
|
||||
"ok": "OK <kbd>enter</kbd>",
|
||||
"defaultTitle": "Prompt"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"modal_title": "Sessão Protegida",
|
||||
"help_title": "Ajuda sobre notas protegidas",
|
||||
"close_label": "Fechar",
|
||||
"form_label": "Para prosseguir com a ação solicitada, você precisa iniciar uma sessão protegida digitando a senha:",
|
||||
"start_button": "Iniciar sessão protegida <kbd>enter</kbd>"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Alterações recentes",
|
||||
"erase_notes_button": "Remover permanentemente as notas excluídas agora",
|
||||
"close": "Fechar",
|
||||
"deleted_notes_message": "As notas excluídas foram removidas permanentemente.",
|
||||
"no_changes_message": "Nenhuma alteração ainda...",
|
||||
"undelete_link": "Restaurar",
|
||||
"confirm_undelete": "Você deseja restaurar esta nota e suas subnotas?"
|
||||
},
|
||||
"revisions": {
|
||||
"note_revisions": "Versões da nota",
|
||||
"delete_all_revisions": "Excluir todas as versões desta nota",
|
||||
"delete_all_button": "Excluir todas as versões",
|
||||
"help_title": "Ajuda sobre as versões da nota",
|
||||
"close": "Fechar",
|
||||
"revision_last_edited": "Esta versão foi editada pela última vez em {{date}}",
|
||||
"confirm_delete_all": "Você quer excluir todas as versões desta nota?",
|
||||
"no_revisions": "Ainda não há versões para esta nota...",
|
||||
"restore_button": "Recuperar",
|
||||
"confirm_restore": "Deseja restaurar esta versão? Isso irá substituir o título e o conteúdo atuais da nota por esta versão.",
|
||||
"delete_button": "Excluir",
|
||||
"confirm_delete": "Deseja excluir esta versão?",
|
||||
"revisions_deleted": "As versões da nota foram removidas.",
|
||||
"revision_restored": "A versão da nota foi restaurada.",
|
||||
"revision_deleted": "A versão da nota foi excluída.",
|
||||
"snapshot_interval": "Intervalo de captura das versões da nota: {{seconds}}s.",
|
||||
"maximum_revisions": "Limite de capturas das versões da nota: {{number}}.",
|
||||
"settings": "Configurações de versões da nota",
|
||||
"download_button": "Download",
|
||||
"mime": "MIME: ",
|
||||
"file_size": "Tamanho do arquivo:",
|
||||
"preview": "Visualizar:",
|
||||
"preview_not_available": "A visualização não está disponível para este tipo de nota."
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Ordenar notas filhas por...",
|
||||
"close": "Fechar",
|
||||
"sorting_criteria": "Critérios de ordenação",
|
||||
"title": "título",
|
||||
"date_created": "data de criação",
|
||||
"date_modified": "data de modificação",
|
||||
"sorting_direction": "Direção de ordenação",
|
||||
"ascending": "crescente",
|
||||
"descending": "decrescente",
|
||||
"folders": "Pastas",
|
||||
"sort_folders_at_top": "colocar pastas no topo",
|
||||
"natural_sort": "Ordenação Natural",
|
||||
"sort_with_respect_to_different_character_sorting": "classificar de acordo com diferentes regras de ordenação de caracteres e colação em diferentes idiomas ou regiões.",
|
||||
"natural_sort_language": "Linguagem da ordenação natural",
|
||||
"the_language_code_for_natural_sort": "O código do idioma para ordenação natural, por exemplo, \"zh-CN\" para chinês.",
|
||||
"sort": "Ordenar <kbd>enter</kbd>"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Enviar anexos para a nota",
|
||||
"close": "Fechar",
|
||||
"choose_files": "Escolher arquivos",
|
||||
"files_will_be_uploaded": "Os arquivos serão enviados como anexos para",
|
||||
"options": "Opções",
|
||||
"shrink_images": "Reduzir imagens",
|
||||
"upload": "Enviar",
|
||||
"tooltip": "Se você marcar esta opção, o Trilium tentará reduzir as imagens enviadas redimensionando e otimizando, o que pode afetar a qualidade visual percebida. Se desmarcada, as imagens serão enviadas sem alterações."
|
||||
},
|
||||
"attribute_detail": {
|
||||
"attr_detail_title": "Título Detalhado do Atributo",
|
||||
"close_button_title": "Cancelar alterações e fechar",
|
||||
"attr_is_owned_by": "O atributo pertence a",
|
||||
"attr_name_title": "O nome do atributo pode ser composto apenas por caracteres alfanuméricos, dois-pontos e sublinhado",
|
||||
"name": "Nome",
|
||||
"value": "Valor",
|
||||
"target_note_title": "Relação é uma conexão nomeada entre a nota de origem e a nota de destino.",
|
||||
"target_note": "Nota de destino",
|
||||
"promoted_title": "O atributo promovido é exibido de forma destacada na nota.",
|
||||
"promoted": "Promovido",
|
||||
"promoted_alias_title": "O nome a ser exibido na interface de atributos promovidos.",
|
||||
"promoted_alias": "Alias",
|
||||
"multiplicity_title": "Multiplicidade define quantos atributos com o mesmo nome podem ser criados — no máximo 1 ou mais de 1.",
|
||||
"multiplicity": "Multiplicidade",
|
||||
"single_value": "Valor único",
|
||||
"multi_value": "Valor múltiplo",
|
||||
"label_type_title": "O tipo do rótulo ajudará o Trilium a escolher a interface adequada para inserir o valor do rótulo.",
|
||||
"label_type": "Tipo",
|
||||
"text": "Texto",
|
||||
"number": "Número",
|
||||
"boolean": "Booleano",
|
||||
"date": "Data",
|
||||
"date_time": "Data e Hora",
|
||||
"time": "Hora",
|
||||
"url": "URL",
|
||||
"precision_title": "Qual número de dígitos após o ponto decimal deve estar disponível na interface de configuração de valor.",
|
||||
"precision": "Precisão",
|
||||
"digits": "dígitos",
|
||||
"inverse_relation_title": "Configuração opcional para definir a qual relação esta é oposta. Exemplo: Pai - Filho são relações inversas entre si.",
|
||||
"inverse_relation": "Relação inversa",
|
||||
"inheritable_title": "O atributo herdável será transmitido para todos os descendentes deste ramo.",
|
||||
"inheritable": "Herdável",
|
||||
"save_and_close": "Salvar e fechar <kbd>Ctrl+Enter</kbd>",
|
||||
"delete": "Excluir",
|
||||
"related_notes_title": "Outras notas com este rótulo",
|
||||
"more_notes": "Mais notas",
|
||||
"label": "Detalhe do rótulo",
|
||||
"label_definition": "Detalhe da definição do rótulo",
|
||||
"relation": "Detalhe da relação",
|
||||
"relation_definition": "Detalhe da definição da relação",
|
||||
"disable_versioning": "desativa a versão automática. Útil, por exemplo, para notas grandes, mas sem importância – como grandes bibliotecas JS usadas para scripts",
|
||||
"calendar_root": "marca a nota que deve ser usada como raiz para notas diárias. Apenas uma deve ser marcada assim.",
|
||||
"archived": "notas com este rótulo não serão exibidas por padrão nos resultados de busca (também nos diálogos Ir para, Adicionar link, etc).",
|
||||
"exclude_from_export": "notas (junto com sua subárvore) não serão incluídas em nenhuma exportação de notas",
|
||||
"run": "define em quais eventos o script deve ser executado. Os valores possíveis são:\n<ul>\n<li>frontendStartup - quando o frontend do Trilium inicia (ou é atualizado), mas não no celular.</li>\n<li>mobileStartup - quando o frontend do Trilium inicia (ou é atualizado), no celular.</li>\n<li>backendStartup - quando o backend do Trilium inicia</li>\n<li>hourly - executa uma vez por hora. Você pode usar o rótulo adicional <code>runAtHour</code> para especificar em qual hora.</li>\n<li>daily - executa uma vez por dia</li>\n</ul>",
|
||||
"run_on_instance": "Define em qual instância do Trilium isso deve ser executado. Por padrão, todas as instâncias.",
|
||||
"run_at_hour": "Em qual hora isso deve ser executado. Deve ser usado junto com <code>#run=hourly</code>. Pode ser definido várias vezes para executar mais de uma vez ao dia.",
|
||||
"disable_inclusion": "scripts com este rótulo não serão incluídos na execução do script pai.",
|
||||
"sorted": "mantém as notas filhas ordenadas alfabeticamente pelo título",
|
||||
"sort_direction": "ASC (padrão) ou DESC",
|
||||
"sort_folders_first": "Pastas (notas com filhos) devem ser ordenadas no topo",
|
||||
"top": "mantenha a nota fornecida no topo em seu pai (aplica-se apenas a pais ordenados)",
|
||||
"hide_promoted_attributes": "Ocultar atributos promovidos nesta nota",
|
||||
"read_only": "o editor está em modo somente leitura. Funciona apenas para notas de texto e código.",
|
||||
"auto_read_only_disabled": "notas de texto/código podem ser automaticamente configuradas para modo de leitura quando são muito grandes. Você pode desabilitar esse comportamento por nota adicionando este rótulo à nota",
|
||||
"app_css": "marca notas CSS que são carregadas no aplicativo Trilium e, portanto, podem ser usadas para modificar a aparência do Trilium.",
|
||||
"app_theme": "marca notas CSS que são temas completos do Trilium e, portanto, estão disponíveis nas opções do Trilium.",
|
||||
"app_theme_base": "defina como \"next\", \"next-light\" ou \"next-dark\" para usar o tema TriliumNext correspondente (auto, claro ou escuro) como base para um tema personalizado, em vez do tema legado.",
|
||||
"css_class": "o valor deste rótulo é então adicionado como classe CSS ao nó que representa a nota específica na árvore. Isso pode ser útil para temas avançados. Pode ser usado em notas de modelo.",
|
||||
"icon_class": "o valor deste rótulo é adicionado como uma classe CSS ao ícone na árvore, o que pode ajudar a distinguir visualmente as notas na árvore. Um exemplo pode ser bx bx-home – os ícones são retirados do boxicons. Pode ser usado em notas de modelo.",
|
||||
"page_size": "número de itens por página na listagem de notas",
|
||||
"custom_request_handler": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
|
||||
"custom_resource_provider": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
|
||||
"widget": "marca esta nota como um widget personalizado que será adicionado à árvore de componentes do Trilium",
|
||||
"workspace": "marca esta nota como um espaço de trabalho, o que permite fácil hoisting",
|
||||
"workspace_icon_class": "define a classe CSS do ícone box que será usada na aba quando esta nota for hoisted",
|
||||
"workspace_tab_background_color": "cor CSS usada na aba da nota quando esta nota é hoisted",
|
||||
"workspace_calendar_root": "Define a raiz do calendário por espaço de trabalho",
|
||||
"workspace_template": "Esta nota aparecerá na seleção de modelos disponíveis ao criar uma nova nota, mas apenas quando estiver destacada em um espaço de trabalho que contenha este modelo",
|
||||
"search_home": "novas notas de pesquisa serão criadas como filhas desta nota",
|
||||
"workspace_search_home": "novas notas de pesquisa serão criadas como filhas desta nota quando ela for destacada para algum ancestral desta nota de área de trabalho",
|
||||
"inbox": "localização padrão da caixa de entrada para novas notas – quando você cria uma nota usando o botão \"nova nota\" na barra lateral, as notas serão criadas como notas filhas na nota marcada com o rótulo <code>#inbox</code>.",
|
||||
"workspace_inbox": "local padrão da caixa de entrada para novas notas quando esta nota for destacada para algum ancestral desta nota de área de trabalho",
|
||||
"sql_console_home": "localização padrão das notas do console SQL",
|
||||
"bookmark_folder": "nota com este rótulo aparecerá nos favoritos como uma pasta (permitindo acesso aos seus filhos)",
|
||||
"share_hidden_from_tree": "esta nota está oculta na árvore de navegação à esquerda, mas ainda pode ser acessada via sua URL",
|
||||
"share_external_link": "a nota funcionará como um link para um site externo na árvore de compartilhamento"
|
||||
"bundle-error": {
|
||||
"title": "Falha para carregar o script customizado",
|
||||
"message": "O script da nota com ID \"{{id}}\", intitulada \"{{title}}\", não pôde ser executado devido a:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Adicionar link",
|
||||
"help_on_links": "Ajuda sobre links",
|
||||
"note": "Nota",
|
||||
"search_note": "pesquisar nota pelo nome",
|
||||
"link_title_mirrors": "o título do link reflete o título atual da nota",
|
||||
"link_title_arbitrary": "o título do link pode ser alterado livremente",
|
||||
"link_title": "Titulo do link",
|
||||
"button_add_link": "Adicionar link"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"prefix": "Prefixo: ",
|
||||
"save": "Salvar",
|
||||
"edit_branch_prefix": "Editar Prefixo do Branch",
|
||||
"help_on_tree_prefix": "Ajuda sobre o prefixo da árvore de notas",
|
||||
"branch_prefix_saved": "O prefixo de ramificação foi salvo."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Ações em massa",
|
||||
"affected_notes": "Notas Afetadas",
|
||||
"include_descendants": "Incluir notas filhas das notas selecionadas",
|
||||
"available_actions": "Ações disponíveis",
|
||||
"chosen_actions": "Ações selecionadas",
|
||||
"execute_bulk_actions": "Executar ações em massa",
|
||||
"bulk_actions_executed": "As ações em massa foram concluídas com sucesso.",
|
||||
"none_yet": "Nenhuma até agora... adicione uma ação clicando em uma das disponíveis acima.",
|
||||
"labels": "Etiquetas",
|
||||
"relations": "Relações",
|
||||
"notes": "Notas",
|
||||
"other": "Outros"
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Clonar notas para...",
|
||||
"help_on_links": "Ajuda sobre links",
|
||||
"notes_to_clone": "Notas para clonar",
|
||||
"search_for_note_by_its_name": "pesquisar nota pelo nome",
|
||||
"cloned_note_prefix_title": "A nota clonada aparecerá na árvore de notas com o prefixo fornecido",
|
||||
"prefix_optional": "Prefixo (opcional)",
|
||||
"no_path_to_clone_to": "Nenhum caminho para clonar.",
|
||||
"target_parent_note": "Nota pai-alvo",
|
||||
"clone_to_selected_note": "Clonar para a nota selecionada",
|
||||
"note_cloned": "A nota \"{{clonedTitle}}\" foi clonada para \"{{targetTitle}}\""
|
||||
},
|
||||
"ai_llm": {
|
||||
"n_notes_queued_0": "{{ count }} nota enfileirada para indexação",
|
||||
"n_notes_queued_1": "{{ count }} notas enfileiradas para indexação",
|
||||
"n_notes_queued_2": "{{ count }} notas enfileiradas para indexação",
|
||||
"notes_indexed_0": "{{ count }} nota indexada",
|
||||
"notes_indexed_1": "{{ count }} notas indexadas",
|
||||
"notes_indexed_2": "{{ count }} notas indexadas"
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Confirmação",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "OK",
|
||||
"are_you_sure_remove_note": "Tem certeza de que deseja remover a nota '{{title}}' do mapa de relações? ",
|
||||
"if_you_dont_check": "Se você não marcar isso, a nota será removida apenas do mapa de relações.",
|
||||
"also_delete_note": "Também excluir a nota"
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_notes_preview": "Excluir pré-visualização de notas",
|
||||
"close": "Fechar",
|
||||
"delete_all_clones_description": "Excluir também todos os clones (pode ser desfeito em alterações recentes)",
|
||||
"erase_notes_description": "A exclusão normal (suave) apenas marca as notas como excluídas, permitindo que sejam recuperadas (no diálogo de alterações recentes) dentro de um período de tempo. Se esta opção for marcada, as notas serão apagadas imediatamente e não será possível restaurá-las.",
|
||||
"erase_notes_warning": "Apagar notas permanentemente (não pode ser desfeito), incluindo todos os clones. Isso forçará o recarregamento do aplicativo.",
|
||||
"notes_to_be_deleted": "As seguintes notas serão excluídas ({{notesCount}})",
|
||||
"no_note_to_delete": "Nenhuma nota será excluída (apenas os clones).",
|
||||
"broken_relations_to_be_deleted": "As seguintes relações serão quebradas e excluídas ({{ relationCount}})",
|
||||
"cancel": "Cancelar",
|
||||
"ok": "OK",
|
||||
"deleted_relation_text": "A nota {{- note}} (a ser excluída) está referenciada pela relação {{- relation}} originada de {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "Exportar nota",
|
||||
"close": "Fechar",
|
||||
"export_type_subtree": "Esta nota e todos os seus descendentes",
|
||||
"format_html": "HTML – recomendado, pois mantém toda a formatação",
|
||||
"format_html_zip": "HTML em arquivo ZIP – recomendado, pois isso preserva toda a formatação.",
|
||||
"format_markdown": "Markdown – isso preserva a maior parte da formatação.",
|
||||
"format_opml": "OPML - formato de intercâmbio de outliners apenas para texto. Formatação, imagens e arquivos não estão incluídos.",
|
||||
"opml_version_1": "OPML v1.0 – apenas texto simples",
|
||||
"opml_version_2": "OPML v2.0 – permite também HTML",
|
||||
"export_type_single": "Apenas esta nota, sem seus descendentes",
|
||||
"export": "Exportar",
|
||||
"choose_export_type": "Por favor, escolha primeiro o tipo de exportação",
|
||||
"export_status": "Status da exportação",
|
||||
"export_in_progress": "Exportação em andamento: {{progressCount}}",
|
||||
"export_finished_successfully": "Exportação concluída com sucesso.",
|
||||
"format_pdf": "PDF – para impressão ou compartilhamento."
|
||||
},
|
||||
"help": {
|
||||
"noteNavigation": "Navegação de notas",
|
||||
"goUpDown": "subir/descer na lista de notas",
|
||||
"collapseExpand": "recolher/expandir nó",
|
||||
"notSet": "não definido",
|
||||
"goBackForwards": "voltar / avançar no histórico",
|
||||
"showJumpToNoteDialog": "mostrar diálogo <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Ir para\"</a>",
|
||||
"scrollToActiveNote": "rolar até a nota atual",
|
||||
"jumpToParentNote": "ir para a nota pai",
|
||||
"collapseWholeTree": "recolher toda a árvore de notas",
|
||||
"collapseSubTree": "recolher subárvore",
|
||||
"tabShortcuts": "Atalhos de abas",
|
||||
"newTabNoteLink": "em um link de nota abre a nota em uma nova aba",
|
||||
"newTabWithActivationNoteLink": "em um link de nota abre e ativa a nota em uma nova aba",
|
||||
"onlyInDesktop": "Apenas na versão para desktop (compilação Electron)",
|
||||
"openEmptyTab": "abrir aba vazia",
|
||||
"closeActiveTab": "fechar aba ativa",
|
||||
"activateNextTab": "ativar próxima aba",
|
||||
"activatePreviousTab": "ativar aba anterior",
|
||||
"creatingNotes": "Criando notas",
|
||||
"createNoteAfter": "criar nova nota após a nota atual",
|
||||
"createNoteInto": "criar nova subnota dentro da nota atual",
|
||||
"editBranchPrefix": "editar <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefixo</a> do clone da nota ativa",
|
||||
"movingCloningNotes": "Movendo / clonando notas",
|
||||
"moveNoteUpDown": "mover nota para cima/baixo na lista de notas",
|
||||
"moveNoteUpHierarchy": "mover nota para cima na hierarquia",
|
||||
"multiSelectNote": "selecionar múltiplas notas acima/abaixo",
|
||||
"selectAllNotes": "selecionar todas as notas no nível atual",
|
||||
"selectNote": "selecionar nota",
|
||||
"copyNotes": "copiar nota ativa (ou seleção atual) para a área de transferência (usado para <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">clonar</a>)",
|
||||
"cutNotes": "recortar nota atual (ou seleção atual) para a área de transferência (usado para mover notas)",
|
||||
"pasteNotes": "colar nota(s) como subnota dentro da nota ativa (o que pode ser mover ou clonar dependendo se foi copiado ou recortado para a área de transferência)",
|
||||
"deleteNotes": "excluir nota / subárvore",
|
||||
"editingNotes": "Edição de notas",
|
||||
"editNoteTitle": "no painel de árvore, a navegação mudará do painel de árvore para o título da nota. Pressionar Enter no título da nota mudará o foco para o editor de texto. <kbd>Ctrl+.</kbd> mudará o foco de volta do editor para o painel de árvore.",
|
||||
"createEditLink": "criar / editar link externo",
|
||||
"createInternalLink": "criar link interno",
|
||||
"followLink": "seguir link sob o cursor",
|
||||
"insertDateTime": "inserir data e hora atual na posição do cursor",
|
||||
"jumpToTreePane": "ir para a árvore de notas e rolar até a nota ativa",
|
||||
"markdownAutoformat": "Autoformatação estilo Markdown",
|
||||
"headings": "<code>##</code>, <code>###</code>, <code>####</code> etc. seguidos de espaço para títulos",
|
||||
"bulletList": "<code>*</code> ou <code>-</code> seguidos de espaço para lista com marcadores",
|
||||
"numberedList": "<code>1.</code> ou <code>1)</code> seguidos de espaço para lista numerada",
|
||||
"blockQuote": "comece uma linha com <code>></code> seguido de espaço para citação em bloco",
|
||||
"troubleshooting": "Solução de problemas",
|
||||
"reloadFrontend": "recarregar o frontend do Trilium",
|
||||
"showDevTools": "mostrar ferramentas de desenvolvedor",
|
||||
"showSQLConsole": "mostrar console SQL",
|
||||
"other": "Outros",
|
||||
"quickSearch": "focar no campo de pesquisa rápida",
|
||||
"inPageSearch": "pesquisa na página",
|
||||
"title": "Folha de Dicas"
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Importar para a nota",
|
||||
"chooseImportFile": "Escolher arquivo para importar",
|
||||
"importDescription": "O conteúdo do(s) arquivo(s) selecionado(s) será importado como nota(s) filha(s) em",
|
||||
"options": "Opções",
|
||||
"safeImportTooltip": "Arquivos de exportação Trilium<code> .zip</code> podem conter scripts executáveis que podem apresentar comportamentos prejudiciais. A importação segura desativará a execução automática de todos os scripts importados. Desmarque “Importação segura” apenas se o arquivo de importação contiver scripts executáveis e você confiar totalmente no conteúdo do arquivo importado.",
|
||||
"safeImport": "Importação segura",
|
||||
"explodeArchivesTooltip": "Se esta opção estiver marcada, o Trilium irá ler arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code> e criar notas a partir dos arquivos contidos nesses arquivos compactados. Se estiver desmarcada, o Trilium irá anexar os próprios arquivos compactados à nota.",
|
||||
"explodeArchives": "Ler conteúdos de arquivos <code>.zip</code>, <code>.enex</code> e <code>.opml</code>.",
|
||||
"shrinkImagesTooltip": "<p>Se você marcar esta opção, o Trilium tentará reduzir o tamanho das imagens importadas por meio de escala e otimização, o que pode afetar a qualidade visual das imagens. Se desmarcada, as imagens serão importadas sem alterações.</p><p>Isso não se aplica a importações de arquivos <code>.zip</code> com metadados, pois presume-se que esses arquivos já estejam otimizados.</p>",
|
||||
"shrinkImages": "Reduzir imagens",
|
||||
"textImportedAsText": "Importar arquivos HTML, Markdown e TXT como notas de texto caso não esteja claro pelos metadados",
|
||||
"codeImportedAsCode": "Importar arquivos de código reconhecidos (por exemplo, <code>.json</code>) como notas de código caso não esteja claro pelos metadados",
|
||||
"replaceUnderscoresWithSpaces": "Substituir sublinhados por espaços nos nomes das notas importadas",
|
||||
"import": "Importar",
|
||||
"failed": "Falha na importação: {{message}}.",
|
||||
"html_import_tags": {
|
||||
"title": "Tags de importação HTML",
|
||||
"description": "Configurar quais tags HTML devem ser preservadas ao importar notas. As tags que não estiverem nesta lista serão removidas durante a importação. Algumas tags (como 'script') são sempre removidas por motivos de segurança.",
|
||||
"placeholder": "Digite as tags HTML, uma por linha",
|
||||
"reset_button": "Redefinir para lista padrão"
|
||||
},
|
||||
"import-status": "Status da importação",
|
||||
"in-progress": "Importação em andamento: {{progress}}",
|
||||
"successful": "Importação concluída com sucesso."
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Incluir nota",
|
||||
"label_note": "Nota",
|
||||
"placeholder_search": "pesquisar nota pelo nome",
|
||||
"box_size_prompt": "Dimensão da caixa da nota incluída:",
|
||||
"box_size_small": "pequeno (~ 10 linhas)",
|
||||
"box_size_medium": "médio (~ 30 linhas)",
|
||||
"box_size_full": "completo (a caixa exibe o texto completo)",
|
||||
"button_include": "Incluir nota"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Mensagem informativa",
|
||||
"closeButton": "Fechar",
|
||||
"okButton": "OK"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Pesquise uma nota pelo nome ou digite > para comandos...",
|
||||
"search_button": "Pesquisar em texto completo"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Importar Markdown",
|
||||
"modal_body_text": "Por motivos de segurança (sandbox do navegador), o JavaScript não pode acessar diretamente a área de transferência. Por favor, cole o conteúdo Markdown na área de texto abaixo e clique em Importar",
|
||||
"import_button": "Importar",
|
||||
"import_success": "O conteúdo Markdown foi importado para o documento."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Mover notas para...",
|
||||
"notes_to_move": "Notas para mover",
|
||||
"target_parent_note": "Nota pai-alvo",
|
||||
"search_placeholder": "pesquisar nota pelo nome",
|
||||
"move_button": "Mover para a nota selecionada",
|
||||
"error_no_path": "Nenhum caminho para mover.",
|
||||
"move_success_message": "As notas selecionadas foram movidas para "
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"change_path_prompt": "Alterar onde criar a nova nota:",
|
||||
"search_placeholder": "buscar caminho pelo nome (valor padrão se não for preenchido)",
|
||||
"modal_title": "Escolher tipo de nota",
|
||||
"modal_body": "Escolha o tipo/modelo da nova nota:",
|
||||
"templates": "Modelos",
|
||||
"builtin_templates": "Modelos Incorporados"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "A senha não está definida",
|
||||
"body1": "Notas protegidas são criptografadas usando uma senha do usuário, mas a senha ainda não foi definida.",
|
||||
"body2": "Para poder proteger notas, clique no botão abaixo para abrir a caixa de diálogo de Opções e definir sua senha.",
|
||||
"go_to_password_options": "Ir para opções de Senha"
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Prompt",
|
||||
"ok": "OK",
|
||||
"defaultTitle": "Prompt"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"modal_title": "Sessão Protegida",
|
||||
"help_title": "Ajuda sobre notas protegidas",
|
||||
"close_label": "Fechar",
|
||||
"form_label": "Para prosseguir com a ação solicitada, você precisa iniciar uma sessão protegida digitando a senha:",
|
||||
"start_button": "Iniciar sessão protegida"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Alterações recentes",
|
||||
"erase_notes_button": "Remover permanentemente as notas excluídas agora",
|
||||
"deleted_notes_message": "As notas excluídas foram removidas permanentemente.",
|
||||
"no_changes_message": "Nenhuma alteração ainda...",
|
||||
"undelete_link": "Restaurar",
|
||||
"confirm_undelete": "Você deseja restaurar esta nota e suas subnotas?"
|
||||
},
|
||||
"revisions": {
|
||||
"note_revisions": "Versões da nota",
|
||||
"delete_all_revisions": "Excluir todas as versões desta nota",
|
||||
"delete_all_button": "Excluir todas as versões",
|
||||
"help_title": "Ajuda sobre as versões da nota",
|
||||
"revision_last_edited": "Esta versão foi editada pela última vez em {{date}}",
|
||||
"confirm_delete_all": "Você quer excluir todas as versões desta nota?",
|
||||
"no_revisions": "Ainda não há versões para esta nota...",
|
||||
"restore_button": "Recuperar",
|
||||
"confirm_restore": "Deseja restaurar esta versão? Isso irá substituir o título e o conteúdo atuais da nota por esta versão.",
|
||||
"delete_button": "Excluir",
|
||||
"confirm_delete": "Deseja excluir esta versão?",
|
||||
"revisions_deleted": "As versões da nota foram removidas.",
|
||||
"revision_restored": "A versão da nota foi restaurada.",
|
||||
"revision_deleted": "A versão da nota foi excluída.",
|
||||
"snapshot_interval": "Intervalo de captura das versões da nota: {{seconds}}s.",
|
||||
"maximum_revisions": "Limite de capturas das versões da nota: {{number}}.",
|
||||
"settings": "Configurações de versões da nota",
|
||||
"download_button": "Download",
|
||||
"mime": "MIME: ",
|
||||
"file_size": "Tamanho do arquivo:",
|
||||
"preview": "Visualizar:",
|
||||
"preview_not_available": "A visualização não está disponível para este tipo de nota."
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Ordenar notas filhas por...",
|
||||
"sorting_criteria": "Critérios de ordenação",
|
||||
"title": "título",
|
||||
"date_created": "data de criação",
|
||||
"date_modified": "data de modificação",
|
||||
"sorting_direction": "Direção de ordenação",
|
||||
"ascending": "crescente",
|
||||
"descending": "decrescente",
|
||||
"folders": "Pastas",
|
||||
"sort_folders_at_top": "colocar pastas no topo",
|
||||
"natural_sort": "Ordenação Natural",
|
||||
"sort_with_respect_to_different_character_sorting": "classificar de acordo com diferentes regras de ordenação de caracteres e colação em diferentes idiomas ou regiões.",
|
||||
"natural_sort_language": "Linguagem da ordenação natural",
|
||||
"the_language_code_for_natural_sort": "O código do idioma para ordenação natural, por exemplo, \"zh-CN\" para chinês.",
|
||||
"sort": "Ordenar"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Enviar anexos para a nota",
|
||||
"choose_files": "Escolher arquivos",
|
||||
"files_will_be_uploaded": "Os arquivos serão enviados como anexos para {{noteTitle}}",
|
||||
"options": "Opções",
|
||||
"shrink_images": "Reduzir imagens",
|
||||
"upload": "Enviar",
|
||||
"tooltip": "Se você marcar esta opção, o Trilium tentará reduzir as imagens enviadas redimensionando e otimizando, o que pode afetar a qualidade visual percebida. Se desmarcada, as imagens serão enviadas sem alterações."
|
||||
},
|
||||
"attribute_detail": {
|
||||
"attr_detail_title": "Título Detalhado do Atributo",
|
||||
"close_button_title": "Cancelar alterações e fechar",
|
||||
"attr_is_owned_by": "O atributo pertence a",
|
||||
"attr_name_title": "O nome do atributo pode ser composto apenas por caracteres alfanuméricos, dois-pontos e sublinhado",
|
||||
"name": "Nome",
|
||||
"value": "Valor",
|
||||
"target_note_title": "Relação é uma conexão nomeada entre a nota de origem e a nota de destino.",
|
||||
"target_note": "Nota de destino",
|
||||
"promoted_title": "O atributo promovido é exibido de forma destacada na nota.",
|
||||
"promoted": "Promovido",
|
||||
"promoted_alias_title": "O nome a ser exibido na interface de atributos promovidos.",
|
||||
"promoted_alias": "Alias",
|
||||
"multiplicity_title": "Multiplicidade define quantos atributos com o mesmo nome podem ser criados — no máximo 1 ou mais de 1.",
|
||||
"multiplicity": "Multiplicidade",
|
||||
"single_value": "Valor único",
|
||||
"multi_value": "Valor múltiplo",
|
||||
"label_type_title": "O tipo do rótulo ajudará o Trilium a escolher a interface adequada para inserir o valor do rótulo.",
|
||||
"label_type": "Tipo",
|
||||
"text": "Texto",
|
||||
"number": "Número",
|
||||
"boolean": "Booleano",
|
||||
"date": "Data",
|
||||
"date_time": "Data e Hora",
|
||||
"time": "Hora",
|
||||
"url": "URL",
|
||||
"precision_title": "Qual número de dígitos após o ponto decimal deve estar disponível na interface de configuração de valor.",
|
||||
"precision": "Precisão",
|
||||
"digits": "dígitos",
|
||||
"inverse_relation_title": "Configuração opcional para definir a qual relação esta é oposta. Exemplo: Pai - Filho são relações inversas entre si.",
|
||||
"inverse_relation": "Relação inversa",
|
||||
"inheritable_title": "O atributo herdável será transmitido para todos os descendentes deste ramo.",
|
||||
"inheritable": "Herdável",
|
||||
"save_and_close": "Salvar e fechar <kbd>Ctrl+Enter</kbd>",
|
||||
"delete": "Excluir",
|
||||
"related_notes_title": "Outras notas com este rótulo",
|
||||
"more_notes": "Mais notas",
|
||||
"label": "Detalhe do rótulo",
|
||||
"label_definition": "Detalhe da definição do rótulo",
|
||||
"relation": "Detalhe da relação",
|
||||
"relation_definition": "Detalhe da definição da relação",
|
||||
"disable_versioning": "desativa a versão automática. Útil, por exemplo, para notas grandes, mas sem importância – como grandes bibliotecas JS usadas para scripts",
|
||||
"calendar_root": "marca a nota que deve ser usada como raiz para notas diárias. Apenas uma deve ser marcada assim.",
|
||||
"archived": "notas com este rótulo não serão exibidas por padrão nos resultados de busca (também nos diálogos Ir para, Adicionar link, etc).",
|
||||
"exclude_from_export": "notas (junto com sua subárvore) não serão incluídas em nenhuma exportação de notas",
|
||||
"run": "define em quais eventos o script deve ser executado. Os valores possíveis são:\n<ul>\n<li>frontendStartup - quando o frontend do Trilium inicia (ou é atualizado), mas não no celular.</li>\n<li>mobileStartup - quando o frontend do Trilium inicia (ou é atualizado), no celular.</li>\n<li>backendStartup - quando o backend do Trilium inicia</li>\n<li>hourly - executa uma vez por hora. Você pode usar o rótulo adicional <code>runAtHour</code> para especificar em qual hora.</li>\n<li>daily - executa uma vez por dia</li>\n</ul>",
|
||||
"run_on_instance": "Define em qual instância do Trilium isso deve ser executado. Por padrão, todas as instâncias.",
|
||||
"run_at_hour": "Em qual hora isso deve ser executado. Deve ser usado junto com <code>#run=hourly</code>. Pode ser definido várias vezes para executar mais de uma vez ao dia.",
|
||||
"disable_inclusion": "scripts com este rótulo não serão incluídos na execução do script pai.",
|
||||
"sorted": "mantém as notas filhas ordenadas alfabeticamente pelo título",
|
||||
"sort_direction": "ASC (padrão) ou DESC",
|
||||
"sort_folders_first": "Pastas (notas com filhos) devem ser ordenadas no topo",
|
||||
"top": "mantenha a nota fornecida no topo em seu pai (aplica-se apenas a pais ordenados)",
|
||||
"hide_promoted_attributes": "Ocultar atributos promovidos nesta nota",
|
||||
"read_only": "o editor está em modo somente leitura. Funciona apenas para notas de texto e código.",
|
||||
"auto_read_only_disabled": "notas de texto/código podem ser automaticamente configuradas para modo de leitura quando são muito grandes. Você pode desabilitar esse comportamento por nota adicionando este rótulo à nota",
|
||||
"app_css": "marca notas CSS que são carregadas no aplicativo Trilium e, portanto, podem ser usadas para modificar a aparência do Trilium.",
|
||||
"app_theme": "marca notas CSS que são temas completos do Trilium e, portanto, estão disponíveis nas opções do Trilium.",
|
||||
"app_theme_base": "defina como \"next\", \"next-light\" ou \"next-dark\" para usar o tema TriliumNext correspondente (auto, claro ou escuro) como base para um tema personalizado, em vez do tema legado.",
|
||||
"css_class": "o valor deste rótulo é então adicionado como classe CSS ao nó que representa a nota específica na árvore. Isso pode ser útil para temas avançados. Pode ser usado em notas de modelo.",
|
||||
"icon_class": "o valor deste rótulo é adicionado como uma classe CSS ao ícone na árvore, o que pode ajudar a distinguir visualmente as notas na árvore. Um exemplo pode ser bx bx-home – os ícones são retirados do boxicons. Pode ser usado em notas de modelo.",
|
||||
"page_size": "número de itens por página na listagem de notas",
|
||||
"custom_request_handler": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
|
||||
"custom_resource_provider": "veja <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Manipulador de requisição personalizada</a>",
|
||||
"widget": "marca esta nota como um widget personalizado que será adicionado à árvore de componentes do Trilium",
|
||||
"workspace": "marca esta nota como um espaço de trabalho, o que permite fácil hoisting",
|
||||
"workspace_icon_class": "define a classe CSS do ícone box que será usada na aba quando esta nota for hoisted",
|
||||
"workspace_tab_background_color": "cor CSS usada na aba da nota quando esta nota é hoisted",
|
||||
"workspace_calendar_root": "Define a raiz do calendário por espaço de trabalho",
|
||||
"workspace_template": "Esta nota aparecerá na seleção de modelos disponíveis ao criar uma nova nota, mas apenas quando estiver destacada em um espaço de trabalho que contenha este modelo",
|
||||
"search_home": "novas notas de pesquisa serão criadas como filhas desta nota",
|
||||
"workspace_search_home": "novas notas de pesquisa serão criadas como filhas desta nota quando ela for destacada para algum ancestral desta nota de área de trabalho",
|
||||
"inbox": "localização padrão da caixa de entrada para novas notas – quando você cria uma nota usando o botão \"nova nota\" na barra lateral, as notas serão criadas como notas filhas na nota marcada com o rótulo <code>#inbox</code>.",
|
||||
"workspace_inbox": "local padrão da caixa de entrada para novas notas quando esta nota for destacada para algum ancestral desta nota de área de trabalho",
|
||||
"sql_console_home": "localização padrão das notas do console SQL",
|
||||
"bookmark_folder": "nota com este rótulo aparecerá nos favoritos como uma pasta (permitindo acesso aos seus filhos)",
|
||||
"share_hidden_from_tree": "esta nota está oculta na árvore de navegação à esquerda, mas ainda pode ser acessada via sua URL",
|
||||
"share_external_link": "a nota funcionará como um link para um site externo na árvore de compartilhamento",
|
||||
"share_alias": "defina um alias por meio do qual a nota ficará disponível em https://your_trilium_host/share/[your_alias]",
|
||||
"share_omit_default_css": "o CSS padrão da página de compartilhamento será omitido. Use quando você fizer alterações extensas de estilo.",
|
||||
"share_root": "marca a nota que é servida na raiz de /share.",
|
||||
"share_description": "defina o texto a ser adicionado à meta tag HTML \"description\"",
|
||||
"share_raw": "a nota será servida em seu formato bruto, sem o wrapper HTML",
|
||||
"share_disallow_robot_indexing": "impedirá que robôs indexem esta nota por meio do cabeçalho <code>X-Robots-Tag: noindex</code>",
|
||||
"share_credentials": "exigir credenciais para acessar esta nota compartilhada. O valor deve estar no formato 'usuário:senha'. Não se esqueça de tornar esta configuração herdável para que seja aplicada às notas-filhas/imagens.",
|
||||
"share_index": "notas com este rótulo irão listar todas as raízes das notas compartilhadas",
|
||||
"display_relations": "nomes das relações separados por vírgula que devem ser exibidos. Todas as outras serão ocultadas.",
|
||||
"hide_relations": "nomes das relações separados por vírgula que devem ser ocultados. Todas as outras serão exibidas.",
|
||||
"title_template": "Título padrão das notas criadas como filhas desta nota. O valor é avaliado como uma string JavaScript e pode ser enriquecido com conteúdo dinâmico usando as variáveis injetadas <code>now</code> e <code>parentNote</code>. Exemplos:\n\n<ul>\n <li><code>${parentNote.getLabelValue('authorName')}'s literary works</code></li>\n <li><code>Log for ${now.format('YYYY-MM-DD HH:mm:ss')}</code></li>\n</ul>\n\nVeja a <a href=\"https://triliumnext.github.io/Docs/Wiki/default-note-title.html\">wiki com detalhes</a>, a documentação da API para <a href=\"https://zadam.github.io/trilium/backend_api/Note.html\">parentNote</a> e para <a href=\"https://day.js.org/docs/en/display/format\">now</a> para mais informações.",
|
||||
"template": "Esta nota aparecerá na seleção de modelos disponíveis ao criar uma nova nota",
|
||||
"toc": "<code>#toc</code> ou <code>#toc=show</code> irá forçar a exibição do Sumário, <code>#toc=hide</code> irá forçar que ele fique oculto. Se o rótulo não existir, será considerado o ajuste global",
|
||||
"color": "define a cor da nota na árvore de notas, links etc. Use qualquer valor de cor CSS válido, como 'red' ou #a13d5f",
|
||||
"keyboard_shortcut": "Define um atalho de teclado que irá pular imediatamente para esta nota. Exemplo: 'ctrl+alt+e'. É necessário recarregar o frontend para que a alteração tenha efeito."
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
9
apps/client/src/translations/sl/translation.json
Normal file
9
apps/client/src/translations/sl/translation.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "Podrobnosti Trilium Notes",
|
||||
"homepage": "Domača stran:",
|
||||
"app_version": "Verzija aplikacije:",
|
||||
"db_version": "Verzija DB:",
|
||||
"sync_version": "Verzija Sync:"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"about": {
|
||||
"title": "O Trilium Belеškama",
|
||||
"close": "Zatvori",
|
||||
"homepage": "Početna stranica:",
|
||||
"app_version": "Verzija aplikacije:",
|
||||
"db_version": "Verzija baze podataka:",
|
||||
@@ -28,7 +27,6 @@
|
||||
"add_link": {
|
||||
"add_link": "Dodaj link",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"close": "Zatvori",
|
||||
"note": "Beleška",
|
||||
"search_note": "potražite belešku po njenom imenu",
|
||||
"link_title_mirrors": "naziv linka preslikava trenutan naziv beleške",
|
||||
@@ -39,14 +37,12 @@
|
||||
"branch_prefix": {
|
||||
"edit_branch_prefix": "Izmeni prefiks grane",
|
||||
"help_on_tree_prefix": "Pomoć na prefiksu Drveta",
|
||||
"close": "Zatvori",
|
||||
"prefix": "Prefiks: ",
|
||||
"save": "Sačuvaj",
|
||||
"branch_prefix_saved": "Prefiks grane je sačuvan."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"bulk_actions": "Grupne akcije",
|
||||
"close": "Zatvori",
|
||||
"affected_notes": "Pogođene beleške",
|
||||
"include_descendants": "Obuhvati potomke izabranih beleški",
|
||||
"available_actions": "Dostupne akcije",
|
||||
@@ -61,7 +57,6 @@
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Klonirajte beleške u...",
|
||||
"close": "Zatvori",
|
||||
"help_on_links": "Pomoć na linkovima",
|
||||
"notes_to_clone": "Beleške za kloniranje",
|
||||
"target_parent_note": "Ciljna nadređena beleška",
|
||||
@@ -74,7 +69,6 @@
|
||||
},
|
||||
"confirm": {
|
||||
"confirmation": "Potvrda",
|
||||
"close": "Zatvori",
|
||||
"cancel": "Otkaži",
|
||||
"ok": "U redu",
|
||||
"are_you_sure_remove_note": "Da li ste sigurni da želite da uklonite belešku \"{{title}}\" iz mape odnosa? ",
|
||||
@@ -113,8 +107,6 @@
|
||||
"format_pdf": "PDF - za namene štampanja ili deljenja."
|
||||
},
|
||||
"help": {
|
||||
"fullDocumentation": "Pomoć (puna dokumentacija je dostupna <a class=\"external\" href=\"https://triliumnext.github.io/Docs/\">online</a>)",
|
||||
"close": "Zatvori",
|
||||
"noteNavigation": "Navigacija beleški",
|
||||
"goUpDown": "<kbd>UP</kbd>, <kbd>DOWN</kbd> - kretanje gore/dole u listi sa beleškama",
|
||||
"collapseExpand": "<kbd>LEFT</kbd>, <kbd>RIGHT</kbd> - sakupi/proširi čvor",
|
||||
@@ -122,12 +114,12 @@
|
||||
"goBackForwards": "idi u nazad/napred kroz istoriju",
|
||||
"showJumpToNoteDialog": "prikaži <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"Idi na\" dijalog</a>",
|
||||
"scrollToActiveNote": "skroluj do aktivne beleške",
|
||||
"jumpToParentNote": "<kbd>Backspace</kbd> - idi do nadređene beleške",
|
||||
"jumpToParentNote": "idi do nadređene beleške",
|
||||
"collapseWholeTree": "sakupi celo drvo beleški",
|
||||
"collapseSubTree": "sakupi pod-drvo",
|
||||
"tabShortcuts": "Prečice na karticama",
|
||||
"newTabNoteLink": "<kbd>Ctrl+click</kbd> - (ili <kbd>middle mouse click</kbd>) na link beleške otvara belešku u novoj kartici",
|
||||
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+click</kbd> - (ili <kbd>Shift+middle mouse click</kbd>) na link beleške otvara i aktivira belešku u novoj kartici",
|
||||
"newTabNoteLink": "na link beleške otvara belešku u novoj kartici",
|
||||
"newTabWithActivationNoteLink": "na link beleške otvara i aktivira belešku u novoj kartici",
|
||||
"onlyInDesktop": "Samo na dektop-u (Electron verzija)",
|
||||
"openEmptyTab": "otvori praznu karticu",
|
||||
"closeActiveTab": "zatvori aktivnu karticu",
|
||||
@@ -142,14 +134,14 @@
|
||||
"moveNoteUpHierarchy": "pomeri belešku na gore u hijerarhiji",
|
||||
"multiSelectNote": "višestruki izbor beleški iznad/ispod",
|
||||
"selectAllNotes": "izaberi sve beleške u trenutnom nivou",
|
||||
"selectNote": "<kbd>Shift+click</kbd> - izaberi belešku",
|
||||
"selectNote": "izaberi belešku",
|
||||
"copyNotes": "kopiraj aktivnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">kloniranje</a>)",
|
||||
"cutNotes": "iseci trenutnu belešku (ili trenutni izbor) u privremenu memoriju (koristi se za premeštanje beleški)",
|
||||
"pasteNotes": "nalepi belešku/e kao podbelešku u aktivnoj belešci (koja se ili premešta ili klonira u zavisnosti od toga da li je beleška kopirana ili isečena u privremenu memoriju)",
|
||||
"deleteNotes": "obriši belešku / podstablo",
|
||||
"editingNotes": "Izmena beleški",
|
||||
"editNoteTitle": "u ravni drveta će se prebaciti sa ravni drveta na naslov beleške. Ulaz sa naslova beleške će prebaciti fokus na uređivač teksta. <kbd>Ctrl+.</kbd> će se vratiti sa uređivača na ravan drveta.",
|
||||
"createEditLink": "<kbd>Ctrl+K</kbd> - napravi / izmeni spoljašnji link",
|
||||
"createEditLink": "napravi / izmeni spoljašnji link",
|
||||
"createInternalLink": "napravi unutrašnji link",
|
||||
"followLink": "prati link ispod kursora",
|
||||
"insertDateTime": "ubaci trenutan datum i vreme na poziciju kursora",
|
||||
@@ -169,7 +161,6 @@
|
||||
},
|
||||
"import": {
|
||||
"importIntoNote": "Uvezi u belešku",
|
||||
"close": "Zatvori",
|
||||
"chooseImportFile": "Izaberi datoteku za uvoz",
|
||||
"importDescription": "Sadržaj izabranih datoteka će biti uvezen kao podbeleške u",
|
||||
"options": "Opcije",
|
||||
@@ -196,14 +187,13 @@
|
||||
},
|
||||
"include_note": {
|
||||
"dialog_title": "Uključi belešku",
|
||||
"close": "Zatvori",
|
||||
"label_note": "Beleška",
|
||||
"placeholder_search": "pretraži belešku po njenom imenu",
|
||||
"box_size_prompt": "Veličina kutije priložene beleške:",
|
||||
"box_size_small": "mala (~ 10 redova)",
|
||||
"box_size_medium": "srednja (~ 30 redova)",
|
||||
"box_size_full": "puna (kutija prikazuje ceo tekst)",
|
||||
"button_include": "Uključi belešku <kbd>enter</kbd>"
|
||||
"button_include": "Uključi belešku"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "Informativna poruka",
|
||||
@@ -212,23 +202,20 @@
|
||||
},
|
||||
"jump_to_note": {
|
||||
"search_placeholder": "Pretraži belešku po njenom imenu ili unesi > za komande...",
|
||||
"close": "Zatvori",
|
||||
"search_button": "Pretraga u punom tekstu <kbd>Ctrl+Enter</kbd>"
|
||||
},
|
||||
"markdown_import": {
|
||||
"dialog_title": "Uvoz za Markdown",
|
||||
"close": "Zatvori",
|
||||
"modal_body_text": "Zbog Sandbox-a pretraživača nije moguće direktno učitati privremenu memoriju iz JavaScript-a. Molimo vas da nalepite Markdown za uvoz u tekstualno polje ispod i kliknete na dugme za uvoz",
|
||||
"import_button": "Uvoz Ctrl+Enter",
|
||||
"import_button": "Uvoz",
|
||||
"import_success": "Markdown sadržaj je učitan u dokument."
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Premesti beleške u ...",
|
||||
"close": "Zatvori",
|
||||
"notes_to_move": "Beleške za premeštanje",
|
||||
"target_parent_note": "Ciljana nadbeleška",
|
||||
"search_placeholder": "potraži belešku po njenom imenu",
|
||||
"move_button": "Pređi na izabranu belešku <kbd>enter</kbd>",
|
||||
"move_button": "Pređi na izabranu belešku",
|
||||
"error_no_path": "Nema putanje za premeštanje.",
|
||||
"move_success_message": "Izabrane beleške su premeštene u "
|
||||
},
|
||||
@@ -236,19 +223,16 @@
|
||||
"change_path_prompt": "Promenite gde će se napraviti nova beleška:",
|
||||
"search_placeholder": "pretraži putanju po njenom imenu (podrazumevano ako je prazno)",
|
||||
"modal_title": "Izaberite tip beleške",
|
||||
"close": "Zatvori",
|
||||
"modal_body": "Izaberite tip beleške / šablon za novu belešku:",
|
||||
"templates": "Šabloni:"
|
||||
"templates": "Šabloni"
|
||||
},
|
||||
"password_not_set": {
|
||||
"title": "Lozinka nije podešena",
|
||||
"close": "Zatvori",
|
||||
"body1": "Zaštićene beleške su enkriptovane sa korisničkom lozinkom, ali lozinka još uvek nije podešena.",
|
||||
"body2": "Za biste mogli da sačuvate beleške, kliknite <a class=\"open-password-options-button\" href=\"javascript:\">ovde</a> da otvorite dijalog sa Opcijama i podesite svoju lozinku."
|
||||
},
|
||||
"prompt": {
|
||||
"title": "Upit",
|
||||
"close": "Zatvori",
|
||||
"ok": "U redu <kbd>enter</kbd>",
|
||||
"defaultTitle": "Upit"
|
||||
},
|
||||
@@ -257,12 +241,11 @@
|
||||
"help_title": "Pomoć za Zaštićene beleške",
|
||||
"close_label": "Zatvori",
|
||||
"form_label": "Da biste nastavili sa traženom akcijom moraćete započeti zaštićenu sesiju tako što ćete uneti lozinku:",
|
||||
"start_button": "Započni zaštićenu sesiju <kbd>enter</kbd>"
|
||||
"start_button": "Započni zaštićenu sesiju"
|
||||
},
|
||||
"recent_changes": {
|
||||
"title": "Nedavne promene",
|
||||
"erase_notes_button": "Obriši izabrane beleške odmah",
|
||||
"close": "Zatvori",
|
||||
"deleted_notes_message": "Obrisane beleške su uklonjene.",
|
||||
"no_changes_message": "Još uvek nema izmena...",
|
||||
"undelete_link": "poništi brisanje",
|
||||
@@ -273,7 +256,6 @@
|
||||
"delete_all_revisions": "Obriši sve revizije ove beleške",
|
||||
"delete_all_button": "Obriši sve revizije",
|
||||
"help_title": "Pomoć za Revizije beleški",
|
||||
"close": "Zatvori",
|
||||
"revision_last_edited": "Ova revizija je poslednji put izmenjena {{date}}",
|
||||
"confirm_delete_all": "Da li želite da obrišete sve revizije ove beleške?",
|
||||
"no_revisions": "Još uvek nema revizija za ovu belešku...",
|
||||
@@ -295,7 +277,6 @@
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Sortiranje podbeleški po...",
|
||||
"close": "Zatvori",
|
||||
"sorting_criteria": "Kriterijum za sortiranje",
|
||||
"title": "naslov",
|
||||
"date_created": "datum kreiranja",
|
||||
@@ -309,13 +290,12 @@
|
||||
"sort_with_respect_to_different_character_sorting": "sortiranje sa poštovanjem različitih pravila sortiranja karaktera i kolacija u različitim jezicima ili regionima.",
|
||||
"natural_sort_language": "Jezik za prirodno sortiranje",
|
||||
"the_language_code_for_natural_sort": "Kod jezika za prirodno sortiranje, npr. \"zh-CN\" za Kineski.",
|
||||
"sort": "Sortiraj <kbd>enter</kbd>"
|
||||
"sort": "Sortiraj"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"upload_attachments_to_note": "Otpremite priloge uz belešku",
|
||||
"close": "Zatvori",
|
||||
"choose_files": "Izaberite datoteke",
|
||||
"files_will_be_uploaded": "Datoteke će biti otpremljene kao prilozi u",
|
||||
"files_will_be_uploaded": "Datoteke će biti otpremljene kao prilozi u {{noteTitle}}",
|
||||
"options": "Opcije",
|
||||
"shrink_images": "Smanji slike",
|
||||
"upload": "Otpremi",
|
||||
|
||||
@@ -1,71 +1,26 @@
|
||||
{
|
||||
"about": {
|
||||
"close": "Kapat",
|
||||
"homepage": "Giriş sayfası:",
|
||||
"app_version": "Uygulama versiyonu:",
|
||||
"db_version": "Veritabanı versiyonu:"
|
||||
},
|
||||
"add_link": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"close": "Kapat",
|
||||
"save": "Kaydet"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"clone_to": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"confirm": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"recent_changes": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"delete_notes": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"export": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"help": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"include_note": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"import": {
|
||||
"close": "Kapat",
|
||||
"chooseImportFile": "İçe aktarım dosyası",
|
||||
"importDescription": "Seçilen dosya(lar) alt not olarak içe aktarılacaktır"
|
||||
},
|
||||
"info": {
|
||||
"closeButton": "Kapat"
|
||||
},
|
||||
"jump_to_note": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"markdown_import": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"move_to": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"note_type_chooser": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"password_not_set": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"prompt": {
|
||||
"close": "Kapat"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Kapat"
|
||||
},
|
||||
"revisions": {
|
||||
"close": "Kapat"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
69
apps/client/src/translations/vi/translation.json
Normal file
69
apps/client/src/translations/vi/translation.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"about": {
|
||||
"homepage": "Trang chủ:",
|
||||
"title": "Về Trilium Notes"
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Thêm liên kết",
|
||||
"button_add_link": "Thêm liên kết"
|
||||
},
|
||||
"bulk_actions": {
|
||||
"other": "Khác"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"save": "Lưu"
|
||||
},
|
||||
"confirm": {
|
||||
"ok": "OK",
|
||||
"cancel": "Huỷ"
|
||||
},
|
||||
"delete_notes": {
|
||||
"close": "Đóng",
|
||||
"ok": "OK",
|
||||
"cancel": "Huỷ"
|
||||
},
|
||||
"export": {
|
||||
"close": "Đóng"
|
||||
},
|
||||
"help": {
|
||||
"other": "Khác"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
"title": "Lỗi nghiêm trọng"
|
||||
}
|
||||
},
|
||||
"import": {
|
||||
"options": "Tuỳ chọn"
|
||||
},
|
||||
"info": {
|
||||
"okButton": "OK",
|
||||
"closeButton": "Đóng"
|
||||
},
|
||||
"move_to": {
|
||||
"dialog_title": "Chuyển ghi chép tới..."
|
||||
},
|
||||
"prompt": {
|
||||
"ok": "OK"
|
||||
},
|
||||
"protected_session_password": {
|
||||
"close_label": "Đóng"
|
||||
},
|
||||
"revisions": {
|
||||
"restore_button": "Khôi phục",
|
||||
"delete_button": "Xoá"
|
||||
},
|
||||
"upload_attachments": {
|
||||
"options": "Tuỳ chọn"
|
||||
},
|
||||
"attribute_detail": {
|
||||
"name": "Tên",
|
||||
"value": "Giá trị",
|
||||
"text": "Văn bản",
|
||||
"number": "Số",
|
||||
"delete": "Xoá"
|
||||
},
|
||||
"rename_note": {
|
||||
"rename_note": "Đổi tên ghi chép"
|
||||
}
|
||||
}
|
||||
54
apps/client/src/widgets/bulk_actions/BulkAction.tsx
Normal file
54
apps/client/src/widgets/bulk_actions/BulkAction.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { ComponentChildren } from "preact";
|
||||
import { memo } from "preact/compat";
|
||||
import AbstractBulkAction from "./abstract_bulk_action";
|
||||
|
||||
interface BulkActionProps {
|
||||
label: string | ComponentChildren;
|
||||
children?: ComponentChildren;
|
||||
helpText?: ComponentChildren;
|
||||
bulkAction: AbstractBulkAction;
|
||||
}
|
||||
|
||||
// Define styles as constants to prevent recreation
|
||||
const flexContainerStyle = { display: "flex", alignItems: "center" } as const;
|
||||
const labelStyle = { marginRight: "10px" } as const;
|
||||
const textStyle = { marginRight: "10px", marginLeft: "10px" } as const;
|
||||
|
||||
const BulkAction = memo(({ label, children, helpText, bulkAction }: BulkActionProps) => {
|
||||
return (
|
||||
<tr>
|
||||
<td colSpan={2}>
|
||||
<div style={flexContainerStyle}>
|
||||
<div style={labelStyle} className="text-nowrap">{label}</div>
|
||||
|
||||
{children}
|
||||
</div>
|
||||
</td>
|
||||
<td className="button-column">
|
||||
{helpText && <div className="dropdown help-dropdown">
|
||||
<span className="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div className="dropdown-menu dropdown-menu-right p-4">
|
||||
{helpText}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<span
|
||||
className="bx bx-x icon-action action-conf-del"
|
||||
onClick={() => bulkAction?.deleteAction()}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
|
||||
export default BulkAction;
|
||||
|
||||
export const BulkActionText = memo(({ text }: { text: string }) => {
|
||||
return (
|
||||
<div
|
||||
style={textStyle}
|
||||
className="text-nowrap">
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,10 +1,9 @@
|
||||
import { t } from "../../services/i18n.js";
|
||||
import server from "../../services/server.js";
|
||||
import ws from "../../services/ws.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import type FAttribute from "../../entities/fattribute.js";
|
||||
import { VNode } from "preact";
|
||||
|
||||
interface ActionDefinition {
|
||||
export interface ActionDefinition {
|
||||
script: string;
|
||||
relationName: string;
|
||||
targetNoteId: string;
|
||||
@@ -27,26 +26,9 @@ export default abstract class AbstractBulkAction {
|
||||
this.actionDef = actionDef;
|
||||
}
|
||||
|
||||
render() {
|
||||
try {
|
||||
const $rendered = this.doRender();
|
||||
|
||||
$rendered
|
||||
.find(".action-conf-del")
|
||||
.on("click", () => this.deleteAction())
|
||||
.attr("title", t("abstract_bulk_action.remove_this_search_action"));
|
||||
|
||||
utils.initHelpDropdown($rendered);
|
||||
|
||||
return $rendered;
|
||||
} catch (e: any) {
|
||||
logError(`Failed rendering search action: ${JSON.stringify(this.attribute.dto)} with error: ${e.message} ${e.stack}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// to be overridden
|
||||
abstract doRender(): JQuery<HTMLElement>;
|
||||
abstract doRender(): VNode;
|
||||
|
||||
static get actionName() {
|
||||
return "";
|
||||
}
|
||||
@@ -66,9 +48,6 @@ export default abstract class AbstractBulkAction {
|
||||
|
||||
async deleteAction() {
|
||||
await server.remove(`notes/${this.attribute.noteId}/attributes/${this.attribute.attributeId}`);
|
||||
|
||||
await ws.waitForMaxKnownEntityChangeId();
|
||||
|
||||
//await this.triggerCommand('refreshSearchDefinition');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { t } from "../../services/i18n.js";
|
||||
import SpacedUpdate from "../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "./abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td>
|
||||
${t("execute_script.execute_script")}
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
class="form-control script"
|
||||
placeholder="note.title = note.title + '- suffix';"/>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
${t("execute_script.help_text")}
|
||||
|
||||
${t("execute_script.example_1")}
|
||||
|
||||
<pre>note.title = note.title + ' - suffix';</pre>
|
||||
|
||||
${t("execute_script.example_2")}
|
||||
|
||||
<pre>for (const attr of note.getOwnedAttributes) { attr.markAsDeleted(); }</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class ExecuteScriptBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "executeScript";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("execute_script.execute_script");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
const $script = $action.find(".script");
|
||||
$script.val(this.actionDef.script || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({ script: $script.val() });
|
||||
}, 1000);
|
||||
|
||||
$script.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
50
apps/client/src/widgets/bulk_actions/execute_script.tsx
Normal file
50
apps/client/src/widgets/bulk_actions/execute_script.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import FormTextBox from "../react/FormTextBox.jsx";
|
||||
import AbstractBulkAction, { ActionDefinition } from "./abstract_bulk_action.js";
|
||||
import BulkAction from "./BulkAction.jsx";
|
||||
import { useSpacedUpdate } from "../react/hooks.jsx";
|
||||
|
||||
function ExecuteScriptBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ script, setScript ] = useState(actionDef.script);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ script }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ script ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("execute_script.execute_script")}
|
||||
helpText={<>
|
||||
{t("execute_script.help_text")}
|
||||
|
||||
{t("execute_script.example_1")}
|
||||
|
||||
<pre>note.title = note.title + ' - suffix';</pre>
|
||||
|
||||
{t("execute_script.example_2")}
|
||||
|
||||
<pre>{"for (const attr of note.getOwnedAttributes) { attr.markAsDeleted(); }"}</pre>
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder="note.title = note.title + '- suffix';"
|
||||
currentValue={script} onChange={setScript}
|
||||
/>
|
||||
</BulkAction>
|
||||
);
|
||||
}
|
||||
|
||||
export default class ExecuteScriptBulkAction extends AbstractBulkAction {
|
||||
|
||||
static get actionName() {
|
||||
return "executeScript";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("execute_script.execute_script");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <ExecuteScriptBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("add_label.add_label")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control label-name"
|
||||
placeholder="${t("add_label.label_name_placeholder")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("add_label.label_name_title")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("add_label.to_value")}</div>
|
||||
|
||||
<input type="text" class="form-control label-value" placeholder="${t("add_label.new_value_placeholder")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("add_label.help_text")}</p>
|
||||
|
||||
<ul>
|
||||
<li>${t("add_label.help_text_item1")}</li>
|
||||
<li>${t("add_label.help_text_item2")}</li>
|
||||
</ul>
|
||||
|
||||
${t("add_label.help_text_note")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class AddLabelBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "addLabel";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("add_label.add_label");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $labelName = $action.find(".label-name");
|
||||
$labelName.val(this.actionDef.labelName || "");
|
||||
|
||||
const $labelValue = $action.find(".label-value");
|
||||
$labelValue.val(this.actionDef.labelValue || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
labelName: $labelName.val(),
|
||||
labelValue: $labelValue.val()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$labelValue.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
57
apps/client/src/widgets/bulk_actions/label/add_label.tsx
Normal file
57
apps/client/src/widgets/bulk_actions/label/add_label.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../../services/i18n";
|
||||
import FormTextBox from "../../react/FormTextBox";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction";
|
||||
import { useSpacedUpdate } from "../../react/hooks";
|
||||
|
||||
function AddLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
|
||||
const [ labelValue, setLabelValue ] = useState<string>(actionDef.labelValue ?? "");
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName, labelValue }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName, labelValue]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("add_label.add_label")}
|
||||
helpText={<>
|
||||
<p>{t("add_label.help_text")}</p>
|
||||
|
||||
<ul>
|
||||
<li>{t("add_label.help_text_item1")}</li>
|
||||
<li>{t("add_label.help_text_item2")}</li>
|
||||
</ul>
|
||||
|
||||
{t("add_label.help_text_note")}
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("add_label.label_name_placeholder")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("add_label.label_name_title")}
|
||||
currentValue={labelName} onChange={setLabelName}
|
||||
/>
|
||||
<BulkActionText text={t("add_label.to_value")} />
|
||||
<FormTextBox
|
||||
placeholder={t("add_label.new_value_placeholder")}
|
||||
currentValue={labelValue} onChange={setLabelValue}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class AddLabelBulkAction extends AbstractBulkAction {
|
||||
|
||||
doRender() {
|
||||
return <AddLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />;
|
||||
}
|
||||
|
||||
static get actionName() {
|
||||
return "addLabel";
|
||||
}
|
||||
|
||||
static get actionTitle() {
|
||||
return t("add_label.add_label");
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td>
|
||||
${t("delete_label.delete_label")}
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
class="form-control label-name"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("delete_label.label_name_title")}"
|
||||
placeholder="${t("delete_label.label_name_placeholder")}"/>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class DeleteLabelBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteLabel";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_label.delete_label");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
const $labelName = $action.find(".label-name");
|
||||
$labelName.val(this.actionDef.labelName || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({ labelName: $labelName.val() });
|
||||
}, 1000);
|
||||
|
||||
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
39
apps/client/src/widgets/bulk_actions/label/delete_label.tsx
Normal file
39
apps/client/src/widgets/bulk_actions/label/delete_label.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
import BulkAction from "../BulkAction.jsx";
|
||||
|
||||
function DeleteLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
|
||||
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("delete_label.delete_label")}
|
||||
>
|
||||
<FormTextBox
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("delete_label.label_name_title")}
|
||||
placeholder={t("delete_label.label_name_placeholder")}
|
||||
currentValue={labelName} onChange={setLabelName}
|
||||
/>
|
||||
</BulkAction>
|
||||
);
|
||||
}
|
||||
|
||||
export default class DeleteLabelBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteLabel";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_label.delete_label");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <DeleteLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_label.rename_label_from")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control old-label-name"
|
||||
placeholder="${t("rename_label.old_name_placeholder")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("rename_label.name_title")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("rename_label.to")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control new-label-name"
|
||||
placeholder="${t("rename_label.new_name_placeholder")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("rename_label.name_title")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class RenameLabelBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameLabel";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("rename_label.rename_label");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $oldLabelName = $action.find(".old-label-name");
|
||||
$oldLabelName.val(this.actionDef.oldLabelName || "");
|
||||
|
||||
const $newLabelName = $action.find(".new-label-name");
|
||||
$newLabelName.val(this.actionDef.newLabelName || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
oldLabelName: $oldLabelName.val(),
|
||||
newLabelName: $newLabelName.val()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$oldLabelName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$newLabelName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
49
apps/client/src/widgets/bulk_actions/label/rename_label.tsx
Normal file
49
apps/client/src/widgets/bulk_actions/label/rename_label.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function RenameLabelBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
|
||||
const [ oldLabelName, setOldLabelName ] = useState(actionDef.oldLabelName);
|
||||
const [ newLabelName, setNewLabelName ] = useState(actionDef.newLabelName);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ oldLabelName, newLabelName }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ oldLabelName, newLabelName ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("rename_label.rename_label_from")}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("rename_label.old_name_placeholder")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("rename_label.name_title")}
|
||||
currentValue={oldLabelName} onChange={setOldLabelName}
|
||||
/>
|
||||
|
||||
<BulkActionText text={t("rename_label.to")} />
|
||||
|
||||
<FormTextBox
|
||||
placeholder={t("rename_label.new_name_placeholder")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("rename_label.name_title")}
|
||||
currentValue={newLabelName} onChange={setNewLabelName}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class RenameLabelBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameLabel";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("rename_label.rename_label");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <RenameLabelBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("update_label_value.update_label_value")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control label-name"
|
||||
placeholder="${t("update_label_value.label_name_placeholder")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("update_label_value.label_name_title")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("update_label_value.to_value")}</div>
|
||||
|
||||
<input type="text" class="form-control label-value" placeholder="${t("update_label_value.new_value_placeholder")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("update_label_value.help_text")}</p>
|
||||
|
||||
${t("update_label_value.help_text_note")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class UpdateLabelValueBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "updateLabelValue";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("update_label_value.update_label_value");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $labelName = $action.find(".label-name");
|
||||
$labelName.val(this.actionDef.labelName || "");
|
||||
|
||||
const $labelValue = $action.find(".label-value");
|
||||
$labelValue.val(this.actionDef.labelValue || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
labelName: $labelName.val(),
|
||||
labelValue: $labelValue.val()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$labelName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$labelValue.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
function UpdateLabelValueComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
|
||||
const [ labelName, setLabelName ] = useState<string>(actionDef.labelName ?? "");
|
||||
const [ labelValue, setLabelValue ] = useState<string>(actionDef.labelValue ?? "");
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ labelName, labelValue }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [labelName, labelValue]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("update_label_value.update_label_value")}
|
||||
helpText={<>
|
||||
<p>{t("update_label_value.help_text")}</p>
|
||||
|
||||
{t("update_label_value.help_text_note")}
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("update_label_value.label_name_placeholder")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("update_label_value.label_name_title")}
|
||||
currentValue={labelName} onChange={setLabelName}
|
||||
/>
|
||||
<BulkActionText text={t("update_label_value.to_value")} />
|
||||
<FormTextBox
|
||||
placeholder={t("update_label_value.new_value_placeholder")}
|
||||
currentValue={labelValue} onChange={setLabelValue}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class UpdateLabelValueBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "updateLabelValue";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("update_label_value.update_label_value");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <UpdateLabelValueComponent bulkAction={this} actionDef={this.actionDef} />;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<span class="bx bx-trash"></span>
|
||||
|
||||
${t("delete_note.delete_matched_notes")}
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("delete_note.delete_matched_notes_description")}</p>
|
||||
|
||||
<p>${t("delete_note.undelete_notes_instruction")}</p>
|
||||
|
||||
${t("delete_note.erase_notes_instruction")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class DeleteNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteNote";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_note.delete_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return $(TPL);
|
||||
}
|
||||
}
|
||||
33
apps/client/src/widgets/bulk_actions/note/delete_note.tsx
Normal file
33
apps/client/src/widgets/bulk_actions/note/delete_note.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import BulkAction from "../BulkAction.jsx";
|
||||
import Icon from "../../react/Icon.jsx";
|
||||
|
||||
function DeleteNoteBulkActionComponent({ bulkAction }: { bulkAction: AbstractBulkAction }) {
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={<><Icon icon="bx bx-trash" /> {t("delete_note.delete_matched_notes")}</>}
|
||||
helpText={<>
|
||||
<p>{t("delete_note.delete_matched_notes_description")}</p>
|
||||
|
||||
<p>{t("delete_note.undelete_notes_instruction")}</p>
|
||||
|
||||
{t("delete_note.erase_notes_instruction")}
|
||||
</>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default class DeleteNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteNote";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_note.delete_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <DeleteNoteBulkActionComponent bulkAction={this} />
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<span class="bx bx-trash"></span>
|
||||
${t("delete_revisions.delete_note_revisions")}
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
${t("delete_revisions.all_past_note_revisions")}
|
||||
</div>
|
||||
</div>
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class DeleteRevisionsBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteRevisions";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_revisions.delete_note_revisions");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return $(TPL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import Icon from "../../react/Icon.jsx";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import BulkAction from "../BulkAction.jsx";
|
||||
|
||||
function DeleteRevisionsBulkActionComponent({ bulkAction }: { bulkAction: AbstractBulkAction }) {
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={<><Icon icon="bx bx-trash" /> {t("delete_revisions.delete_note_revisions")}</>}
|
||||
helpText={t("delete_revisions.all_past_note_revisions")}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default class DeleteRevisionsBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteRevisions";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_revisions.delete_note_revisions");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <DeleteRevisionsBulkActionComponent bulkAction={this} />
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import noteAutocompleteService from "../../../services/note_autocomplete.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("move_note.move_note")}</div>
|
||||
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("move_note.to")}</div>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control target-parent-note" placeholder="${t("move_note.target_parent_note")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("move_note.on_all_matched_notes")}:</p>
|
||||
|
||||
<ul style="margin-bottom: 0;">
|
||||
<li>${t("move_note.move_note_new_parent")}</li>
|
||||
<li>${t("move_note.clone_note_new_parent")}</li>
|
||||
<li>${t("move_note.nothing_will_happen")}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class MoveNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "moveNote";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("move_note.move_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $targetParentNote = $action.find(".target-parent-note");
|
||||
noteAutocompleteService.initNoteAutocomplete($targetParentNote);
|
||||
$targetParentNote.setNote(this.actionDef.targetParentNoteId);
|
||||
|
||||
$targetParentNote.on("autocomplete:closed", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
targetParentNoteId: $targetParentNote.getSelectedNoteId()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$targetParentNote.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
50
apps/client/src/widgets/bulk_actions/note/move_note.tsx
Normal file
50
apps/client/src/widgets/bulk_actions/note/move_note.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function MoveNoteBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ targetParentNoteId, setTargetParentNoteId ] = useState<string>();
|
||||
const spacedUpdate = useSpacedUpdate(() => {
|
||||
return bulkAction.saveAction({ targetParentNoteId: targetParentNoteId })
|
||||
});
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ targetParentNoteId ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("move_note.move_note")}
|
||||
helpText={<>
|
||||
<p>{t("move_note.on_all_matched_notes")}:</p>
|
||||
|
||||
<ul style="margin-bottom: 0;">
|
||||
<li>{t("move_note.move_note_new_parent")}</li>
|
||||
<li>{t("move_note.clone_note_new_parent")}</li>
|
||||
<li>{t("move_note.nothing_will_happen")}</li>
|
||||
</ul>
|
||||
</>}
|
||||
>
|
||||
<BulkActionText text={t("move_note.to")} />
|
||||
|
||||
<NoteAutocomplete
|
||||
placeholder={t("move_note.target_parent_note")}
|
||||
noteId={targetParentNoteId} noteIdChanged={setTargetParentNoteId}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class MoveNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "moveNote";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("move_note.move_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <MoveNoteBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_note.rename_note_title_to")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control new-title"
|
||||
placeholder="${t("rename_note.new_note_title")}"
|
||||
title="${t("rename_note.click_help_icon")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("rename_note.evaluated_as_js_string")}</p>
|
||||
|
||||
<ul>
|
||||
<li>${t("rename_note.example_note")}</li>
|
||||
<li>${t("rename_note.example_new_title")}</li>
|
||||
<li>${t("rename_note.example_date_prefix")}</li>
|
||||
</ul>
|
||||
|
||||
${t("rename_note.api_docs")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class RenameNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameNote";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("rename_note.rename_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $newTitle = $action.find(".new-title");
|
||||
$newTitle.val(this.actionDef.newTitle || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
newTitle: $newTitle.val()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$newTitle.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
53
apps/client/src/widgets/bulk_actions/note/rename_note.tsx
Normal file
53
apps/client/src/widgets/bulk_actions/note/rename_note.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import BulkAction from "../BulkAction.jsx";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
import RawHtml from "../../react/RawHtml.jsx";
|
||||
|
||||
function RenameNoteBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition}) {
|
||||
const [ newTitle, setNewTitle ] = useState<string>(actionDef.newTitle ?? "");
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ newTitle }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ newTitle ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("rename_note.rename_note_title_to")}
|
||||
helpText={<>
|
||||
<p>{t("rename_note.evaluated_as_js_string")}</p>
|
||||
|
||||
<ul>
|
||||
<li><RawHtml html={t("rename_note.example_note")} /></li>
|
||||
<li><RawHtml html={t("rename_note.example_new_title")} /></li>
|
||||
<li><RawHtml html={t("rename_note.example_date_prefix")} /></li>
|
||||
</ul>
|
||||
|
||||
<RawHtml html={t("rename_note.api_docs")} />
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("rename_note.new_note_title")}
|
||||
title={("rename_note.click_help_icon")}
|
||||
currentValue={newTitle} onChange={setNewTitle}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class RenameNoteBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameNote";
|
||||
}
|
||||
|
||||
static get actionTitle() {
|
||||
return t("rename_note.rename_note");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <RenameNoteBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import noteAutocompleteService from "../../../services/note_autocomplete.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("add_relation.add_relation")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control relation-name"
|
||||
placeholder="${t("add_relation.relation_name")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
style="flex-shrink: 3"
|
||||
title="${t("add_relation.allowed_characters")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("add_relation.to")}</div>
|
||||
|
||||
<div class="input-group" style="flex-shrink: 2">
|
||||
<input type="text" class="form-control target-note" placeholder="${t("add_relation.target_note")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
${t("add_relation.create_relation_on_all_matched_notes")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class AddRelationBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "addRelation";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("add_relation.add_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $relationName = $action.find(".relation-name");
|
||||
$relationName.val(this.actionDef.relationName || "");
|
||||
|
||||
const $targetNote = $action.find(".target-note");
|
||||
noteAutocompleteService.initNoteAutocomplete($targetNote);
|
||||
$targetNote.setNote(this.actionDef.targetNoteId);
|
||||
|
||||
$targetNote.on("autocomplete:closed", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
relationName: $relationName.val(),
|
||||
targetNoteId: $targetNote.getSelectedNoteId()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$relationName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$targetNote.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import noteAutocompleteService from "../../../services/note_autocomplete.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function AddRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ relationName, setRelationName ] = useState<string>(actionDef.relationName);
|
||||
const [ targetNoteId, setTargetNoteId ] = useState<string>(actionDef.targetNoteId);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ relationName, targetNoteId }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ relationName, targetNoteId ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("add_relation.add_relation")}
|
||||
helpText={t("add_relation.create_relation_on_all_matched_notes")}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("add_relation.relation_name")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
style={{ flexShrink: 3 }}
|
||||
title={t("add_relation.allowed_characters")}
|
||||
currentValue={relationName} onChange={setRelationName}
|
||||
/>
|
||||
|
||||
<BulkActionText text={t("add_relation.to")} />
|
||||
|
||||
<NoteAutocomplete
|
||||
placeholder={t("add_relation.target_note")}
|
||||
noteId={targetNoteId} noteIdChanged={setTargetNoteId}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class AddRelationBulkAction extends AbstractBulkAction {
|
||||
|
||||
static get actionName() {
|
||||
return "addRelation";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("add_relation.add_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <AddRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td>
|
||||
${t("delete_relation.delete_relation")}
|
||||
</td>
|
||||
<td>
|
||||
<div style="display: flex; align-items: center">
|
||||
<input type="text"
|
||||
class="form-control relation-name"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
placeholder="${t("delete_relation.relation_name")}"
|
||||
title="${t("delete_relation.allowed_characters")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class DeleteRelationBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "deleteRelation";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("delete_relation.delete_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
const $relationName = $action.find(".relation-name");
|
||||
$relationName.val(this.actionDef.relationName || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({ relationName: $relationName.val() });
|
||||
}, 1000);
|
||||
|
||||
$relationName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import BulkAction from "../BulkAction.jsx";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function DeleteRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ relationName, setRelationName ] = useState(actionDef.relationName);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ relationName }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ relationName ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("delete_relation.delete_relation")}
|
||||
>
|
||||
<FormTextBox
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
placeholder={t("delete_relation.relation_name")}
|
||||
title={t("delete_relation.allowed_characters")}
|
||||
currentValue={relationName} onChange={setRelationName}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class DeleteRelationBulkAction extends AbstractBulkAction {
|
||||
|
||||
static get actionName() {
|
||||
return "deleteRelation";
|
||||
}
|
||||
|
||||
static get actionTitle() {
|
||||
return t("delete_relation.delete_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <DeleteRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px; flex-shrink: 0;">${t("rename_relation.rename_relation_from")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control old-relation-name"
|
||||
placeholder="${t("rename_relation.old_name")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("rename_relation.allowed_characters")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("rename_relation.to")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control new-relation-name"
|
||||
placeholder="${t("rename_relation.new_name")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title="${t("rename_relation.allowed_characters")}"/>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class RenameRelationBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameRelation";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("rename_relation.rename_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $oldRelationName = $action.find(".old-relation-name");
|
||||
$oldRelationName.val(this.actionDef.oldRelationName || "");
|
||||
|
||||
const $newRelationName = $action.find(".new-relation-name");
|
||||
$newRelationName.val(this.actionDef.newRelationName || "");
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
oldRelationName: $oldRelationName.val(),
|
||||
newRelationName: $newRelationName.val()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$oldRelationName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$newRelationName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function RenameRelationBulkActionComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ oldRelationName, setOldRelationName ] = useState(actionDef.oldRelationName);
|
||||
const [ newRelationName, setNewRelationName ] = useState(actionDef.newRelationName);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ oldRelationName, newRelationName }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ oldRelationName, newRelationName ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("rename_relation.rename_relation_from")}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("rename_relation.old_name")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("rename_relation.allowed_characters")}
|
||||
currentValue={oldRelationName} onChange={setOldRelationName}
|
||||
/>
|
||||
|
||||
<BulkActionText text={t("rename_relation.to")} />
|
||||
|
||||
<FormTextBox
|
||||
placeholder={t("rename_relation.new_name")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
title={t("rename_relation.allowed_characters")}
|
||||
currentValue={newRelationName} onChange={setNewRelationName}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class RenameRelationBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "renameRelation";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("rename_relation.rename_relation");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <RenameRelationBulkActionComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import SpacedUpdate from "../../../services/spaced_update.js";
|
||||
import AbstractBulkAction from "../abstract_bulk_action.js";
|
||||
import noteAutocompleteService from "../../../services/note_autocomplete.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div style="display: flex; align-items: center">
|
||||
<div style="margin-right: 10px;" class="text-nowrap">${t("update_relation_target.update_relation")}</div>
|
||||
|
||||
<input type="text"
|
||||
class="form-control relation-name"
|
||||
placeholder="${t("update_relation_target.relation_name")}"
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
style="flex-shrink: 3"
|
||||
title="${t("update_relation_target.allowed_characters")}"/>
|
||||
|
||||
<div style="margin-right: 10px; margin-left: 10px;" class="text-nowrap">${t("update_relation_target.to")}</div>
|
||||
|
||||
<div class="input-group" style="flex-shrink: 2">
|
||||
<input type="text" class="form-control target-note" placeholder="${t("update_relation_target.target_note")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>${t("update_relation_target.on_all_matched_notes")}:</p>
|
||||
|
||||
<ul style="margin-bottom: 0;">
|
||||
<li>${t("update_relation_target.change_target_note")}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action action-conf-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class UpdateRelationTargetBulkAction extends AbstractBulkAction {
|
||||
static get actionName() {
|
||||
return "updateRelationTarget";
|
||||
}
|
||||
static get actionTitle() {
|
||||
return t("update_relation_target.update_relation_target");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
const $action = $(TPL);
|
||||
|
||||
const $relationName = $action.find(".relation-name");
|
||||
$relationName.val(this.actionDef.relationName || "");
|
||||
|
||||
const $targetNote = $action.find(".target-note");
|
||||
noteAutocompleteService.initNoteAutocomplete($targetNote);
|
||||
$targetNote.setNote(this.actionDef.targetNoteId);
|
||||
|
||||
$targetNote.on("autocomplete:closed", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
const spacedUpdate = new SpacedUpdate(async () => {
|
||||
await this.saveAction({
|
||||
relationName: $relationName.val(),
|
||||
targetNoteId: $targetNote.getSelectedNoteId()
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
$relationName.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
$targetNote.on("input", () => spacedUpdate.scheduleUpdate());
|
||||
|
||||
return $action;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import AbstractBulkAction, { ActionDefinition } from "../abstract_bulk_action.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import BulkAction, { BulkActionText } from "../BulkAction.jsx";
|
||||
import FormTextBox from "../../react/FormTextBox.jsx";
|
||||
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useSpacedUpdate } from "../../react/hooks.jsx";
|
||||
|
||||
function UpdateRelationTargetComponent({ bulkAction, actionDef }: { bulkAction: AbstractBulkAction, actionDef: ActionDefinition }) {
|
||||
const [ relationName, setRelationName ] = useState(actionDef.relationName);
|
||||
const [ targetNoteId, setTargetNoteId ] = useState(actionDef.targetNoteId);
|
||||
const spacedUpdate = useSpacedUpdate(() => bulkAction.saveAction({ relationName, targetNoteId }));
|
||||
useEffect(() => spacedUpdate.scheduleUpdate(), [ relationName, targetNoteId ]);
|
||||
|
||||
return (
|
||||
<BulkAction
|
||||
bulkAction={bulkAction}
|
||||
label={t("update_relation_target.update_relation")}
|
||||
helpText={<>
|
||||
<p>{t("update_relation_target.on_all_matched_notes")}:</p>
|
||||
|
||||
<ul style="margin-bottom: 0;">
|
||||
<li>{t("update_relation_target.change_target_note")}</li>
|
||||
</ul>
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
placeholder={t("update_relation_target.relation_name")}
|
||||
pattern="[\\p{L}\\p{N}_:]+"
|
||||
style={{ flexShrink: 3 }}
|
||||
title={t("update_relation_target.allowed_characters")}
|
||||
currentValue={relationName} onChange={setRelationName}
|
||||
/>
|
||||
|
||||
<BulkActionText text={t("update_relation_target.to")} />
|
||||
|
||||
<NoteAutocomplete
|
||||
placeholder={t("update_relation_target.target_note")}
|
||||
containerStyle={{ flexShrink: 2 }}
|
||||
noteId={targetNoteId} noteIdChanged={setTargetNoteId}
|
||||
/>
|
||||
</BulkAction>
|
||||
)
|
||||
}
|
||||
|
||||
export default class UpdateRelationTargetBulkAction extends AbstractBulkAction {
|
||||
|
||||
static get actionName() {
|
||||
return "updateRelationTarget";
|
||||
}
|
||||
|
||||
static get actionTitle() {
|
||||
return t("update_relation_target.update_relation_target");
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return <UpdateRelationTargetComponent bulkAction={this} actionDef={this.actionDef} />
|
||||
}
|
||||
|
||||
}
|
||||
@@ -363,7 +363,6 @@ export default class GlobalMenuWidget extends BasicWidget {
|
||||
|
||||
this.$zoomState = this.$widget.find(".zoom-state");
|
||||
this.$toggleZenMode = this.$widget.find('[data-trigger-command="toggleZenMode"');
|
||||
this.$toggleZenMode.toggle(!utils.isMobile());
|
||||
this.$widget.on("show.bs.dropdown", () => this.#onShown());
|
||||
if (this.tooltip) {
|
||||
this.$widget.on("hide.bs.dropdown", () => this.tooltip.enable());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import BasicWidget from "./basic_widget.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const TPL = /*html*/`\
|
||||
<div class="close-zen-container">
|
||||
@@ -28,6 +29,10 @@ const TPL = /*html*/`\
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
body.zen.mobile .close-zen-container {
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
body.zen.electron:not(.platform-darwin):not(.native-titlebar) .close-zen-container {
|
||||
left: calc(env(titlebar-area-width) - var(--zen-button-size) - 2px);
|
||||
right: unset;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { openDialog } from "../../services/dialog.js";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||
import Modal from "../react/Modal.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
@@ -9,59 +8,64 @@ import openService from "../../services/open.js";
|
||||
import { useState } from "preact/hooks";
|
||||
import type { CSSProperties } from "preact/compat";
|
||||
import type { AppInfo } from "@triliumnext/commons";
|
||||
import useTriliumEvent from "../react/hooks.jsx";
|
||||
|
||||
function AboutDialogComponent() {
|
||||
let [appInfo, setAppInfo] = useState<AppInfo | null>(null);
|
||||
|
||||
async function onShown() {
|
||||
const appInfo = await server.get<AppInfo>("app-info");
|
||||
setAppInfo(appInfo);
|
||||
}
|
||||
|
||||
let [shown, setShown] = useState(false);
|
||||
const forceWordBreak: CSSProperties = { wordBreak: "break-all" };
|
||||
|
||||
useTriliumEvent("openAboutDialog", () => setShown(true));
|
||||
|
||||
return (
|
||||
<Modal className="about-dialog" size="lg" title={t("about.title")} onShown={onShown}>
|
||||
{(appInfo !== null) ? (
|
||||
<table className="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("about.homepage")}</th>
|
||||
<td><a className="tn-link external" href="https://github.com/TriliumNext/Trilium" style={forceWordBreak}>https://github.com/TriliumNext/Trilium</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.app_version")}</th>
|
||||
<td className="app-version">{appInfo.appVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.db_version")}</th>
|
||||
<td className="db-version">{appInfo.dbVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.sync_version")}</th>
|
||||
<td className="sync-version">{appInfo.syncVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_date")}</th>
|
||||
<td className="build-date">{formatDateTime(appInfo.buildDate)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_revision")}</th>
|
||||
<td>
|
||||
<a className="tn-link build-revision external" href={`https://github.com/TriliumNext/Trilium/commit/${appInfo.buildRevision}`} target="_blank" style={forceWordBreak}>{appInfo.buildRevision}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.data_directory")}</th>
|
||||
<td className="data-directory">
|
||||
<DirectoryLink directory={appInfo.dataDirectory} style={forceWordBreak} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<div className="loading-spinner"></div>
|
||||
)}
|
||||
<Modal className="about-dialog"
|
||||
size="lg"
|
||||
title={t("about.title")}
|
||||
show={shown}
|
||||
onShown={async () => {
|
||||
const appInfo = await server.get<AppInfo>("app-info");
|
||||
setAppInfo(appInfo);
|
||||
}}
|
||||
onHidden={() => setShown(false)}
|
||||
>
|
||||
<table className="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{t("about.homepage")}</th>
|
||||
<td><a className="tn-link external" href="https://github.com/TriliumNext/Trilium" style={forceWordBreak}>https://github.com/TriliumNext/Trilium</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.app_version")}</th>
|
||||
<td className="app-version">{appInfo?.appVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.db_version")}</th>
|
||||
<td className="db-version">{appInfo?.dbVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.sync_version")}</th>
|
||||
<td className="sync-version">{appInfo?.syncVersion}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_date")}</th>
|
||||
<td className="build-date">
|
||||
{appInfo?.buildDate ? formatDateTime(appInfo.buildDate) : ""}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.build_revision")}</th>
|
||||
<td>
|
||||
{appInfo?.buildRevision && <a className="tn-link build-revision external" href={`https://github.com/TriliumNext/Trilium/commit/${appInfo.buildRevision}`} target="_blank" style={forceWordBreak}>{appInfo.buildRevision}</a>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{t("about.data_directory")}</th>
|
||||
<td className="data-directory">
|
||||
{appInfo?.dataDirectory && (<DirectoryLink directory={appInfo.dataDirectory} style={forceWordBreak} />)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -85,7 +89,4 @@ export default class AboutDialog extends ReactBasicWidget {
|
||||
return <AboutDialogComponent />;
|
||||
}
|
||||
|
||||
async openAboutDialogEvent() {
|
||||
openDialog(this.$widget);
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
import { t } from "../../services/i18n.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
import noteAutocompleteService from "../../services/note_autocomplete.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import type { Suggestion } from "../../services/note_autocomplete.js";
|
||||
import type { default as TextTypeWidget } from "../type_widgets/editable_text.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { openDialog } from "../../services/dialog.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="add-link-dialog modal mx-auto" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" style="max-width: 1000px" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title flex-grow-1">${t("add_link.add_link")}</h5>
|
||||
<button type="button" class="help-button" title="${t("add_link.help_on_links")}" data-help-page="links.html">?</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("add_link.close")}"></button>
|
||||
</div>
|
||||
<form class="add-link-form">
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="add-link-note-autocomplete">${t("add_link.note")}</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input class="add-link-note-autocomplete form-control" placeholder="${t("add_link.search_note")}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="add-link-title-settings">
|
||||
<div class="add-link-title-radios form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="radio" name="link-type" value="reference-link" checked>
|
||||
${t("add_link.link_title_mirrors")}
|
||||
</label>
|
||||
</div>
|
||||
<div class="add-link-title-radios form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="radio" name="link-type" value="hyper-link">
|
||||
${t("add_link.link_title_arbitrary")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="add-link-title-form-group form-group">
|
||||
<br/>
|
||||
<label>
|
||||
${t("add_link.link_title")}
|
||||
|
||||
<input class="link-title form-control" style="width: 100%;">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">${t("add_link.button_add_link")}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class AddLinkDialog extends BasicWidget {
|
||||
private $form!: JQuery<HTMLElement>;
|
||||
private $autoComplete!: JQuery<HTMLElement>;
|
||||
private $linkTitle!: JQuery<HTMLElement>;
|
||||
private $addLinkTitleSettings!: JQuery<HTMLElement>;
|
||||
private $addLinkTitleRadios!: JQuery<HTMLElement>;
|
||||
private $addLinkTitleFormGroup!: JQuery<HTMLElement>;
|
||||
private textTypeWidget: TextTypeWidget | null = null;
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$form = this.$widget.find(".add-link-form");
|
||||
this.$autoComplete = this.$widget.find(".add-link-note-autocomplete");
|
||||
this.$linkTitle = this.$widget.find(".link-title");
|
||||
this.$addLinkTitleSettings = this.$widget.find(".add-link-title-settings");
|
||||
this.$addLinkTitleRadios = this.$widget.find(".add-link-title-radios");
|
||||
this.$addLinkTitleFormGroup = this.$widget.find(".add-link-title-form-group");
|
||||
|
||||
this.$form.on("submit", () => {
|
||||
if (this.$autoComplete.getSelectedNotePath()) {
|
||||
this.$widget.modal("hide");
|
||||
|
||||
const linkTitle = this.getLinkType() === "reference-link" ? null : this.$linkTitle.val() as string;
|
||||
|
||||
this.textTypeWidget?.addLink(this.$autoComplete.getSelectedNotePath()!, linkTitle);
|
||||
} else if (this.$autoComplete.getSelectedExternalLink()) {
|
||||
this.$widget.modal("hide");
|
||||
|
||||
this.textTypeWidget?.addLink(this.$autoComplete.getSelectedExternalLink()!, this.$linkTitle.val() as string, true);
|
||||
} else {
|
||||
logError("No link to add.");
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async showAddLinkDialogEvent({ textTypeWidget, text = "" }: EventData<"showAddLinkDialog">) {
|
||||
this.textTypeWidget = textTypeWidget;
|
||||
|
||||
this.$addLinkTitleSettings.toggle(!this.textTypeWidget.hasSelection());
|
||||
|
||||
this.$addLinkTitleSettings.find("input[type=radio]").on("change", () => this.updateTitleSettingsVisibility());
|
||||
|
||||
// with selection hyperlink is implied
|
||||
if (this.textTypeWidget.hasSelection()) {
|
||||
this.$addLinkTitleSettings.find("input[value='hyper-link']").prop("checked", true);
|
||||
} else {
|
||||
this.$addLinkTitleSettings.find("input[value='reference-link']").prop("checked", true);
|
||||
}
|
||||
|
||||
this.updateTitleSettingsVisibility();
|
||||
|
||||
await openDialog(this.$widget);
|
||||
|
||||
this.$autoComplete.val("");
|
||||
this.$linkTitle.val("");
|
||||
|
||||
const setDefaultLinkTitle = async (noteId: string) => {
|
||||
const noteTitle = await treeService.getNoteTitle(noteId);
|
||||
this.$linkTitle.val(noteTitle);
|
||||
};
|
||||
|
||||
noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, {
|
||||
allowExternalLinks: true,
|
||||
allowCreatingNotes: true
|
||||
});
|
||||
|
||||
this.$autoComplete.on("autocomplete:noteselected", (event: JQuery.Event, suggestion: Suggestion) => {
|
||||
if (!suggestion.notePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.updateTitleSettingsVisibility();
|
||||
|
||||
const noteId = treeService.getNoteIdFromUrl(suggestion.notePath);
|
||||
|
||||
if (noteId) {
|
||||
setDefaultLinkTitle(noteId);
|
||||
}
|
||||
});
|
||||
|
||||
this.$autoComplete.on("autocomplete:externallinkselected", (event: JQuery.Event, suggestion: Suggestion) => {
|
||||
if (!suggestion.externalLink) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.updateTitleSettingsVisibility();
|
||||
|
||||
this.$linkTitle.val(suggestion.externalLink);
|
||||
});
|
||||
|
||||
this.$autoComplete.on("autocomplete:cursorchanged", (event: JQuery.Event, suggestion: Suggestion) => {
|
||||
if (suggestion.externalLink) {
|
||||
this.$linkTitle.val(suggestion.externalLink);
|
||||
} else {
|
||||
const noteId = treeService.getNoteIdFromUrl(suggestion.notePath!);
|
||||
|
||||
if (noteId) {
|
||||
setDefaultLinkTitle(noteId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (text && text.trim()) {
|
||||
noteAutocompleteService.setText(this.$autoComplete, text);
|
||||
} else {
|
||||
noteAutocompleteService.showRecentNotes(this.$autoComplete);
|
||||
}
|
||||
|
||||
this.$autoComplete.trigger("focus").trigger("select"); // to be able to quickly remove entered text
|
||||
}
|
||||
|
||||
private getLinkType() {
|
||||
if (this.$autoComplete.getSelectedExternalLink()) {
|
||||
return "external-link";
|
||||
}
|
||||
|
||||
return this.$addLinkTitleSettings.find("input[type=radio]:checked").val();
|
||||
}
|
||||
|
||||
private updateTitleSettingsVisibility() {
|
||||
const linkType = this.getLinkType();
|
||||
|
||||
this.$addLinkTitleFormGroup.toggle(linkType !== "reference-link");
|
||||
this.$addLinkTitleRadios.toggle(linkType !== "external-link");
|
||||
}
|
||||
}
|
||||
162
apps/client/src/widgets/dialogs/add_link.tsx
Normal file
162
apps/client/src/widgets/dialogs/add_link.tsx
Normal file
@@ -0,0 +1,162 @@
|
||||
import { t } from "../../services/i18n";
|
||||
import Modal from "../react/Modal";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import Button from "../react/Button";
|
||||
import FormRadioGroup from "../react/FormRadioGroup";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
import { useRef, useState, useEffect } from "preact/hooks";
|
||||
import tree from "../../services/tree";
|
||||
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
|
||||
import { default as TextTypeWidget } from "../type_widgets/editable_text.js";
|
||||
import { logError } from "../../services/ws";
|
||||
import FormGroup from "../react/FormGroup.js";
|
||||
import { refToJQuerySelector } from "../react/react_utils";
|
||||
import useTriliumEvent from "../react/hooks";
|
||||
|
||||
type LinkType = "reference-link" | "external-link" | "hyper-link";
|
||||
|
||||
function AddLinkDialogComponent() {
|
||||
const [ textTypeWidget, setTextTypeWidget ] = useState<TextTypeWidget>();
|
||||
const initialText = useRef<string>();
|
||||
const [ linkTitle, setLinkTitle ] = useState("");
|
||||
const hasSelection = textTypeWidget?.hasSelection();
|
||||
const [ linkType, setLinkType ] = useState<LinkType>(hasSelection ? "hyper-link" : "reference-link");
|
||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||
const [ shown, setShown ] = useState(false);
|
||||
|
||||
useTriliumEvent("showAddLinkDialog", ( { textTypeWidget, text }) => {
|
||||
setTextTypeWidget(textTypeWidget);
|
||||
initialText.current = text;
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
async function setDefaultLinkTitle(noteId: string) {
|
||||
const noteTitle = await tree.getNoteTitle(noteId);
|
||||
setLinkTitle(noteTitle);
|
||||
}
|
||||
|
||||
function resetExternalLink() {
|
||||
if (linkType === "external-link") {
|
||||
setLinkType("reference-link");
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!suggestion) {
|
||||
resetExternalLink();
|
||||
return;
|
||||
}
|
||||
|
||||
if (suggestion.notePath) {
|
||||
const noteId = tree.getNoteIdFromUrl(suggestion.notePath);
|
||||
if (noteId) {
|
||||
setDefaultLinkTitle(noteId);
|
||||
}
|
||||
resetExternalLink();
|
||||
}
|
||||
|
||||
if (suggestion.externalLink) {
|
||||
setLinkTitle(suggestion.externalLink);
|
||||
setLinkType("external-link");
|
||||
}
|
||||
}, [suggestion]);
|
||||
|
||||
function onShown() {
|
||||
const $autocompleteEl = refToJQuerySelector(autocompleteRef);
|
||||
if (!initialText.current) {
|
||||
note_autocomplete.showRecentNotes($autocompleteEl);
|
||||
} else {
|
||||
note_autocomplete.setText($autocompleteEl, initialText.current);
|
||||
}
|
||||
|
||||
// to be able to quickly remove entered text
|
||||
$autocompleteEl
|
||||
.trigger("focus")
|
||||
.trigger("select");
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
if (suggestion?.notePath) {
|
||||
// Handle note link
|
||||
setShown(false);
|
||||
textTypeWidget?.addLink(suggestion.notePath, linkType === "reference-link" ? null : linkTitle);
|
||||
} else if (suggestion?.externalLink) {
|
||||
// Handle external link
|
||||
setShown(false);
|
||||
textTypeWidget?.addLink(suggestion.externalLink, linkTitle, true);
|
||||
} else {
|
||||
logError("No link to add.");
|
||||
}
|
||||
}
|
||||
|
||||
const autocompleteRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="add-link-dialog"
|
||||
size="lg"
|
||||
maxWidth={1000}
|
||||
title={t("add_link.add_link")}
|
||||
helpPageId="QEAPj01N5f7w"
|
||||
footer={<Button text={t("add_link.button_add_link")} keyboardShortcut="Enter" />}
|
||||
onSubmit={onSubmit}
|
||||
onShown={onShown}
|
||||
onHidden={() => {
|
||||
setSuggestion(null);
|
||||
setShown(false);
|
||||
}}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("add_link.note")}>
|
||||
<NoteAutocomplete
|
||||
inputRef={autocompleteRef}
|
||||
onChange={setSuggestion}
|
||||
opts={{
|
||||
allowExternalLinks: true,
|
||||
allowCreatingNotes: true
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{!hasSelection && (
|
||||
<div className="add-link-title-settings">
|
||||
{(linkType !== "external-link") && (
|
||||
<>
|
||||
<FormRadioGroup
|
||||
name="link-type"
|
||||
currentValue={linkType}
|
||||
values={[
|
||||
{ value: "reference-link", label: t("add_link.link_title_mirrors") },
|
||||
{ value: "hyper-link", label: t("add_link.link_title_arbitrary") }
|
||||
]}
|
||||
onChange={(newValue) => setLinkType(newValue as LinkType)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{(linkType !== "reference-link" && (
|
||||
<div className="add-link-title-form-group form-group">
|
||||
<br/>
|
||||
<label>
|
||||
{t("add_link.link_title")}
|
||||
|
||||
<input className="link-title form-control" style={{ width: "100%" }}
|
||||
value={linkTitle}
|
||||
onInput={e => setLinkTitle((e.target as HTMLInputElement)?.value ?? "")}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default class AddLinkDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <AddLinkDialogComponent />;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import treeService from "../../services/tree.js";
|
||||
import server from "../../services/server.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import { Modal } from "bootstrap";
|
||||
import { openDialog } from "../../services/dialog.js";
|
||||
|
||||
const TPL = /*html*/`<div class="branch-prefix-dialog modal fade mx-auto" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<form class="branch-prefix-form">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title flex-grow-1">${t("branch_prefix.edit_branch_prefix")}</h5>
|
||||
<button class="help-button" type="button" data-help-page="tree-concepts.html#prefix" title="${t("branch_prefix.help_on_tree_prefix")}">?</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("branch_prefix.close")}"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="branch-prefix-input">${t("branch_prefix.prefix")}</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input class="branch-prefix-input form-control">
|
||||
<div class="branch-prefix-note-title input-group-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary btn-sm">${t("branch_prefix.save")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class BranchPrefixDialog extends BasicWidget {
|
||||
private modal!: Modal;
|
||||
private $form!: JQuery<HTMLElement>;
|
||||
private $treePrefixInput!: JQuery<HTMLElement>;
|
||||
private $noteTitle!: JQuery<HTMLElement>;
|
||||
private branchId: string | null = null;
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
|
||||
this.$form = this.$widget.find(".branch-prefix-form");
|
||||
this.$treePrefixInput = this.$widget.find(".branch-prefix-input");
|
||||
this.$noteTitle = this.$widget.find(".branch-prefix-note-title");
|
||||
|
||||
this.$form.on("submit", () => {
|
||||
this.savePrefix();
|
||||
return false;
|
||||
});
|
||||
|
||||
this.$widget.on("shown.bs.modal", () => this.$treePrefixInput.trigger("focus"));
|
||||
}
|
||||
|
||||
async refresh(notePath: string) {
|
||||
const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath);
|
||||
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newBranchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!newBranchId) {
|
||||
return;
|
||||
}
|
||||
this.branchId = newBranchId;
|
||||
|
||||
const branch = froca.getBranch(this.branchId);
|
||||
if (!branch || branch.noteId === "root") {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentNote = await froca.getNote(branch.parentNoteId);
|
||||
if (!parentNote || parentNote.type === "search") {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$treePrefixInput.val(branch.prefix || "");
|
||||
|
||||
const noteTitle = await treeService.getNoteTitle(noteId);
|
||||
this.$noteTitle.text(` - ${noteTitle}`);
|
||||
}
|
||||
|
||||
async editBranchPrefixEvent() {
|
||||
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.refresh(notePath);
|
||||
openDialog(this.$widget);
|
||||
}
|
||||
|
||||
async savePrefix() {
|
||||
const prefix = this.$treePrefixInput.val();
|
||||
|
||||
await server.put(`branches/${this.branchId}/set-prefix`, { prefix: prefix });
|
||||
|
||||
this.modal.hide();
|
||||
|
||||
toastService.showMessage(t("branch_prefix.branch_prefix_saved"));
|
||||
}
|
||||
}
|
||||
89
apps/client/src/widgets/dialogs/branch_prefix.tsx
Normal file
89
apps/client/src/widgets/dialogs/branch_prefix.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { useRef, useState } from "preact/hooks";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import server from "../../services/server.js";
|
||||
import toast from "../../services/toast.js";
|
||||
import Modal from "../react/Modal.jsx";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import tree from "../../services/tree.js";
|
||||
import Button from "../react/Button.jsx";
|
||||
import FormGroup from "../react/FormGroup.js";
|
||||
import useTriliumEvent from "../react/hooks.jsx";
|
||||
import FBranch from "../../entities/fbranch.js";
|
||||
|
||||
function BranchPrefixDialogComponent() {
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const [ branch, setBranch ] = useState<FBranch>();
|
||||
const [ prefix, setPrefix ] = useState(branch?.prefix ?? "");
|
||||
const branchInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
useTriliumEvent("editBranchPrefix", async () => {
|
||||
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath);
|
||||
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newBranchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!newBranchId) {
|
||||
return;
|
||||
}
|
||||
const parentNote = await froca.getNote(parentNoteId);
|
||||
if (!parentNote || parentNote.type === "search") {
|
||||
return;
|
||||
}
|
||||
|
||||
setBranch(froca.getBranch(newBranchId));
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
async function onSubmit() {
|
||||
if (!branch) {
|
||||
return;
|
||||
}
|
||||
|
||||
savePrefix(branch.branchId, prefix);
|
||||
setShown(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="branch-prefix-dialog"
|
||||
title={t("branch_prefix.edit_branch_prefix")}
|
||||
size="lg"
|
||||
onShown={() => branchInput.current?.focus()}
|
||||
onHidden={() => setShown(false)}
|
||||
onSubmit={onSubmit}
|
||||
helpPageId="TBwsyfadTA18"
|
||||
footer={<Button text={t("branch_prefix.save")} />}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("branch_prefix.prefix")}>
|
||||
<div class="input-group">
|
||||
<input class="branch-prefix-input form-control" value={prefix} ref={branchInput}
|
||||
onChange={(e) => setPrefix((e.target as HTMLInputElement).value)} />
|
||||
<div class="branch-prefix-note-title input-group-text"> - {branch && branch.getNoteFromCache().title}</div>
|
||||
</div>
|
||||
</FormGroup>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default class BranchPrefixDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <BranchPrefixDialogComponent />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function savePrefix(branchId: string, prefix: string) {
|
||||
await server.put(`branches/${branchId}/set-prefix`, { prefix: prefix });
|
||||
toast.showMessage(t("branch_prefix.branch_prefix_saved"));
|
||||
}
|
||||
24
apps/client/src/widgets/dialogs/bulk_actions.css
Normal file
24
apps/client/src/widgets/dialogs/bulk_actions.css
Normal file
@@ -0,0 +1,24 @@
|
||||
.bulk-actions-dialog .modal-body h4:not(:first-child) {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-available-action-list button {
|
||||
padding: 2px 7px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list td {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list .button-column {
|
||||
/* minimal width so that table remains static sized and most space remains for middle column with settings */
|
||||
width: 50px;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import bulkActionService from "../../services/bulk_action.js";
|
||||
import server from "../../services/server.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { closeActiveDialog, openDialog } from "../../services/dialog.js";
|
||||
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="bulk-actions-dialog modal mx-auto" tabindex="-1" role="dialog">
|
||||
<style>
|
||||
.bulk-actions-dialog .modal-body h4:not(:first-child) {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-available-action-list button {
|
||||
padding: 2px 7px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list td {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
.bulk-actions-dialog .bulk-existing-action-list .button-column {
|
||||
/* minimal width so that table remains static sized and most space remains for middle column with settings */
|
||||
width: 50px;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${t("bulk_actions.bulk_actions")}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("bulk_actions.close")}"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h4>${t("bulk_actions.affected_notes")}: <span class="affected-note-count">0</span></h4>
|
||||
|
||||
<div class="form-check">
|
||||
<label for="include-descendants" class="form-check-label tn-checkbox">
|
||||
<input id="include-descendants" class="include-descendants form-check-input" type="checkbox" value="">
|
||||
${t("bulk_actions.include_descendants")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h4>${t("bulk_actions.available_actions")}</h4>
|
||||
|
||||
<table class="bulk-available-action-list"></table>
|
||||
|
||||
<h4>${t("bulk_actions.chosen_actions")}</h4>
|
||||
|
||||
<table class="bulk-existing-action-list"></table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="execute-bulk-actions btn btn-primary">${t("bulk_actions.execute_bulk_actions")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class BulkActionsDialog extends BasicWidget {
|
||||
private $includeDescendants!: JQuery<HTMLElement>;
|
||||
private $affectedNoteCount!: JQuery<HTMLElement>;
|
||||
private $availableActionList!: JQuery<HTMLElement>;
|
||||
private $existingActionList!: JQuery<HTMLElement>;
|
||||
private $executeButton!: JQuery<HTMLElement>;
|
||||
private selectedOrActiveNoteIds: string[] | null = null;
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$includeDescendants = this.$widget.find(".include-descendants");
|
||||
this.$includeDescendants.on("change", () => this.refresh());
|
||||
|
||||
this.$affectedNoteCount = this.$widget.find(".affected-note-count");
|
||||
|
||||
this.$availableActionList = this.$widget.find(".bulk-available-action-list");
|
||||
this.$existingActionList = this.$widget.find(".bulk-existing-action-list");
|
||||
|
||||
this.$widget.on("click", "[data-action-add]", async (event) => {
|
||||
const actionName = $(event.target).attr("data-action-add");
|
||||
if (!actionName) {
|
||||
return;
|
||||
}
|
||||
|
||||
await bulkActionService.addAction("_bulkAction", actionName);
|
||||
await this.refresh();
|
||||
});
|
||||
|
||||
this.$executeButton = this.$widget.find(".execute-bulk-actions");
|
||||
this.$executeButton.on("click", async () => {
|
||||
await server.post("bulk-action/execute", {
|
||||
noteIds: this.selectedOrActiveNoteIds,
|
||||
includeDescendants: this.$includeDescendants.is(":checked")
|
||||
});
|
||||
|
||||
toastService.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
|
||||
closeActiveDialog();
|
||||
});
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
this.renderAvailableActions();
|
||||
|
||||
if (!this.selectedOrActiveNoteIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { affectedNoteCount } = await server.post("bulk-action/affected-notes", {
|
||||
noteIds: this.selectedOrActiveNoteIds,
|
||||
includeDescendants: this.$includeDescendants.is(":checked")
|
||||
}) as { affectedNoteCount: number };
|
||||
|
||||
this.$affectedNoteCount.text(affectedNoteCount);
|
||||
|
||||
const bulkActionNote = await froca.getNote("_bulkAction");
|
||||
if (!bulkActionNote) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actions = bulkActionService.parseActions(bulkActionNote);
|
||||
|
||||
this.$existingActionList.empty();
|
||||
|
||||
if (actions.length > 0) {
|
||||
this.$existingActionList.append(...actions.map((action) => action.render()).filter((action) => action !== null));
|
||||
} else {
|
||||
this.$existingActionList.append($("<p>").text(t("bulk_actions.none_yet")));
|
||||
}
|
||||
}
|
||||
|
||||
renderAvailableActions() {
|
||||
this.$availableActionList.empty();
|
||||
|
||||
for (const actionGroup of bulkActionService.ACTION_GROUPS) {
|
||||
const $actionGroupList = $("<td>");
|
||||
const $actionGroup = $("<tr>")
|
||||
.append($("<td>").text(`${actionGroup.title}: `))
|
||||
.append($actionGroupList);
|
||||
|
||||
for (const action of actionGroup.actions) {
|
||||
$actionGroupList.append($('<button class="btn btn-sm">').attr("data-action-add", action.actionName).text(action.actionTitle));
|
||||
}
|
||||
|
||||
this.$availableActionList.append($actionGroup);
|
||||
}
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||
// only refreshing deleted attrs, otherwise components update themselves
|
||||
if (loadResults.getAttributeRows().find((row) => row.type === "label" && row.name === "action" && row.noteId === "_bulkAction" && row.isDeleted)) {
|
||||
// this may be triggered from e.g., sync without open widget, then no need to refresh the widget
|
||||
if (this.selectedOrActiveNoteIds && this.$widget.is(":visible")) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async openBulkActionsDialogEvent({ selectedOrActiveNoteIds }: EventData<"openBulkActionsDialog">) {
|
||||
this.selectedOrActiveNoteIds = selectedOrActiveNoteIds;
|
||||
this.$includeDescendants.prop("checked", false);
|
||||
|
||||
await this.refresh();
|
||||
openDialog(this.$widget);
|
||||
}
|
||||
}
|
||||
126
apps/client/src/widgets/dialogs/bulk_actions.tsx
Normal file
126
apps/client/src/widgets/dialogs/bulk_actions.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { useEffect, useState, useCallback } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import Modal from "../react/Modal";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import "./bulk_actions.css";
|
||||
import { BulkActionAffectedNotes } from "@triliumnext/commons";
|
||||
import server from "../../services/server";
|
||||
import FormCheckbox from "../react/FormCheckbox";
|
||||
import Button from "../react/Button";
|
||||
import bulk_action from "../../services/bulk_action";
|
||||
import toast from "../../services/toast";
|
||||
import RenameNoteBulkAction from "../bulk_actions/note/rename_note";
|
||||
import FNote from "../../entities/fnote";
|
||||
import froca from "../../services/froca";
|
||||
import useTriliumEvent from "../react/hooks";
|
||||
|
||||
function BulkActionComponent() {
|
||||
const [ selectedOrActiveNoteIds, setSelectedOrActiveNoteIds ] = useState<string[]>();
|
||||
const [ bulkActionNote, setBulkActionNote ] = useState<FNote | null>();
|
||||
const [ includeDescendants, setIncludeDescendants ] = useState(false);
|
||||
const [ affectedNoteCount, setAffectedNoteCount ] = useState(0);
|
||||
const [ existingActions, setExistingActions ] = useState<RenameNoteBulkAction[]>([]);
|
||||
const [ shown, setShown ] = useState(false);
|
||||
|
||||
useTriliumEvent("openBulkActionsDialog", async ({ selectedOrActiveNoteIds }) => {
|
||||
setSelectedOrActiveNoteIds(selectedOrActiveNoteIds);
|
||||
setBulkActionNote(await froca.getNote("_bulkAction"));
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedOrActiveNoteIds || !bulkActionNote) return;
|
||||
|
||||
server.post<BulkActionAffectedNotes>("bulk-action/affected-notes", {
|
||||
noteIds: selectedOrActiveNoteIds,
|
||||
includeDescendants
|
||||
}).then(({ affectedNoteCount }) => setAffectedNoteCount(affectedNoteCount));
|
||||
}, [ selectedOrActiveNoteIds, includeDescendants, bulkActionNote ]);
|
||||
|
||||
const refreshExistingActions = useCallback(() => {
|
||||
if (!bulkActionNote) return;
|
||||
setExistingActions(bulk_action.parseActions(bulkActionNote));
|
||||
}, [bulkActionNote]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshExistingActions();
|
||||
}, [refreshExistingActions]);
|
||||
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (loadResults.getAttributeRows().find((row) =>
|
||||
row.type === "label" && row.name === "action" && row.noteId === "_bulkAction")) {
|
||||
refreshExistingActions();
|
||||
}
|
||||
}, shown);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="bulk-actions-dialog"
|
||||
size="xl"
|
||||
title={t("bulk_actions.bulk_actions")}
|
||||
footer={<Button text={t("bulk_actions.execute_bulk_actions")} primary />}
|
||||
show={shown}
|
||||
onSubmit={async () => {
|
||||
await server.post("bulk-action/execute", {
|
||||
noteIds: selectedOrActiveNoteIds,
|
||||
includeDescendants
|
||||
});
|
||||
|
||||
toast.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
|
||||
setShown(false);
|
||||
}}
|
||||
onHidden={() => setShown(false)}
|
||||
>
|
||||
<h4>{t("bulk_actions.affected_notes")}: <span>{affectedNoteCount}</span></h4>
|
||||
<FormCheckbox
|
||||
name="include-descendants" label={t("bulk_actions.include_descendants")}
|
||||
currentValue={includeDescendants} onChange={setIncludeDescendants}
|
||||
/>
|
||||
|
||||
<h4>{t("bulk_actions.available_actions")}</h4>
|
||||
<AvailableActionsList />
|
||||
|
||||
<h4>{t("bulk_actions.chosen_actions")}</h4>
|
||||
<ExistingActionsList existingActions={existingActions} />
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
function AvailableActionsList() {
|
||||
return <table class="bulk-available-action-list">
|
||||
{bulk_action.ACTION_GROUPS.map((actionGroup) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>{ actionGroup.title }:</td>
|
||||
{actionGroup.actions.map(({ actionName, actionTitle }) =>
|
||||
<Button
|
||||
small text={actionTitle}
|
||||
onClick={() => bulk_action.addAction("_bulkAction", actionName)}
|
||||
/>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</table>;
|
||||
}
|
||||
|
||||
function ExistingActionsList({ existingActions }: { existingActions?: RenameNoteBulkAction[] }) {
|
||||
return (
|
||||
<table class="bulk-existing-action-list">
|
||||
{ existingActions
|
||||
? existingActions
|
||||
.map(action => action.doRender())
|
||||
.filter(renderedAction => renderedAction !== null)
|
||||
: <p>{t("bulk_actions.none_yet")}</p>
|
||||
}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default class BulkActionsDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <BulkActionComponent />
|
||||
}
|
||||
|
||||
}
|
||||
58
apps/client/src/widgets/dialogs/call_to_action.tsx
Normal file
58
apps/client/src/widgets/dialogs/call_to_action.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import Button from "../react/Button";
|
||||
import Modal from "../react/Modal";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import { CallToAction, dismissCallToAction, getCallToActions } from "./call_to_action_definitions";
|
||||
|
||||
function CallToActionDialogComponent({ activeCallToActions }: { activeCallToActions: CallToAction[] }) {
|
||||
if (!activeCallToActions.length) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const [ activeIndex, setActiveIndex ] = useState(0);
|
||||
const [ shown, setShown ] = useState(true);
|
||||
const activeItem = activeCallToActions[activeIndex];
|
||||
|
||||
function goToNext() {
|
||||
if (activeIndex + 1 < activeCallToActions.length) {
|
||||
setActiveIndex(activeIndex + 1);
|
||||
} else {
|
||||
setShown(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="call-to-action"
|
||||
size="md"
|
||||
title="New features"
|
||||
show={shown}
|
||||
onHidden={() => setShown(false)}
|
||||
footerAlignment="between"
|
||||
footer={<>
|
||||
<Button text="Dismiss" onClick={async () => {
|
||||
await dismissCallToAction(activeItem.id);
|
||||
goToNext();
|
||||
}} />
|
||||
{activeItem.buttons.map((button) =>
|
||||
<Button text={button.text} onClick={async () => {
|
||||
await dismissCallToAction(activeItem.id);
|
||||
await button.onClick();
|
||||
goToNext();
|
||||
}}/>
|
||||
)}
|
||||
</>}
|
||||
>
|
||||
<h4>{activeItem.title}</h4>
|
||||
<p>{activeItem.message}</p>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export class CallToActionDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <CallToActionDialogComponent activeCallToActions={getCallToActions()} />
|
||||
}
|
||||
|
||||
}
|
||||
116
apps/client/src/widgets/dialogs/call_to_action_definitions.ts
Normal file
116
apps/client/src/widgets/dialogs/call_to_action_definitions.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import utils from "../../services/utils";
|
||||
import options from "../../services/options";
|
||||
import { t } from "../../services/i18n";
|
||||
|
||||
/**
|
||||
* A "call-to-action" is an interactive message for the user, generally to present new features.
|
||||
*/
|
||||
export interface CallToAction {
|
||||
/**
|
||||
* A unique identifier to allow the call-to-action to be dismissed by the user and then never shown again.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* The title of the call-to-action, displayed as a heading in the message.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* The message body of the call-to-action.
|
||||
*/
|
||||
message: string;
|
||||
/**
|
||||
* Function that determines whether the call-to-action can be displayed to the user. The check can be based on options or
|
||||
* the platform of the user. If the user already dismissed this call-to-action, the value of this function doesn't matter.
|
||||
*
|
||||
* @returns whether to allow this call-to-action or to skip it, based on the user's environment.
|
||||
*/
|
||||
enabled: () => boolean;
|
||||
/**
|
||||
* A list of buttons to display in the footer of the modal.
|
||||
*/
|
||||
buttons: {
|
||||
/**
|
||||
* The text displayed on the button.
|
||||
*/
|
||||
text: string;
|
||||
/**
|
||||
* The listener that will be called when the button is pressed. Async methods are supported and will be awaited before proceeding to the next step.
|
||||
*/
|
||||
onClick: () => (void | Promise<void>);
|
||||
}[];
|
||||
}
|
||||
|
||||
function isNextTheme() {
|
||||
return [ "next", "next-light", "next-dark" ].includes(options.get("theme"));
|
||||
}
|
||||
|
||||
const CALL_TO_ACTIONS: CallToAction[] = [
|
||||
{
|
||||
id: "next_theme",
|
||||
title: t("call_to_action.next_theme_title"),
|
||||
message: t("call_to_action.next_theme_message"),
|
||||
enabled: () => !isNextTheme(),
|
||||
buttons: [
|
||||
{
|
||||
text: t("call_to_action.next_theme_button"),
|
||||
async onClick() {
|
||||
await options.save("theme", "next");
|
||||
await options.save("backgroundEffects", "true");
|
||||
utils.reloadFrontendApp("call-to-action");
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "background_effects",
|
||||
title: t("call_to_action.background_effects_title"),
|
||||
message: t("call_to_action.background_effects_message"),
|
||||
enabled: () => utils.isElectron() && window.glob.platform === "win32" && isNextTheme() && !options.is("backgroundEffects"),
|
||||
buttons: [
|
||||
{
|
||||
text: t("call_to_action.background_effects_button"),
|
||||
async onClick() {
|
||||
await options.save("backgroundEffects", "true");
|
||||
utils.restartDesktopApp();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Obtains the list of available call-to-actions, meaning those that are enabled based on the user's environment but also with
|
||||
* without the call-to-actions already dismissed by the user.
|
||||
*
|
||||
* @returns a list iof call to actions to display to the user.
|
||||
*/
|
||||
export function getCallToActions() {
|
||||
const seenCallToActions = new Set(getSeenCallToActions());
|
||||
|
||||
return CALL_TO_ACTIONS.filter((callToAction) =>
|
||||
!seenCallToActions.has(callToAction.id) && callToAction.enabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the call-to-action as dismissed by the user, meaning that {@link getCallToActions()} will no longer list this particular action.
|
||||
*
|
||||
* @param id the corresponding ID of the call to action.
|
||||
* @returns a promise with the option saving. Generally it's best to wait for the promise to resolve before refreshing the page.
|
||||
*/
|
||||
export async function dismissCallToAction(id: string) {
|
||||
const seenCallToActions = getSeenCallToActions();
|
||||
if (seenCallToActions.find(seenId => seenId === id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seenCallToActions.push(id);
|
||||
await options.save("seenCallToActions", JSON.stringify(seenCallToActions));
|
||||
}
|
||||
|
||||
function getSeenCallToActions() {
|
||||
try {
|
||||
return JSON.parse(options.get("seenCallToActions")) as string[];
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
import noteAutocompleteService from "../../services/note_autocomplete.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import branchService from "../../services/branches.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { openDialog } from "../../services/dialog.js";
|
||||
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="clone-to-dialog modal mx-auto" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" style="max-width: 1000px" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title flex-grow-1">${t("clone_to.clone_notes_to")}</h5>
|
||||
<button type="button" class="help-button" title="${t("clone_to.help_on_links")}" data-help-page="cloning-notes.html">?</button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("clone_to.close")}"></button>
|
||||
</div>
|
||||
<form class="clone-to-form">
|
||||
<div class="modal-body">
|
||||
<h5>${t("clone_to.notes_to_clone")}</h5>
|
||||
|
||||
<ul class="clone-to-note-list" style="max-height: 200px; overflow: auto;"></ul>
|
||||
|
||||
<div class="form-group">
|
||||
<label style="width: 100%">
|
||||
${t("clone_to.target_parent_note")}
|
||||
<div class="input-group">
|
||||
<input class="clone-to-note-autocomplete form-control" placeholder="${t("clone_to.search_for_note_by_its_name")}">
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group" title="${t("clone_to.cloned_note_prefix_title")}">
|
||||
<label style="width: 100%">
|
||||
${t("clone_to.prefix_optional")}
|
||||
<input class="clone-prefix form-control" style="width: 100%;">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">${t("clone_to.clone_to_selected_note")}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class CloneToDialog extends BasicWidget {
|
||||
private $form!: JQuery<HTMLElement>;
|
||||
private $noteAutoComplete!: JQuery<HTMLElement>;
|
||||
private $clonePrefix!: JQuery<HTMLElement>;
|
||||
private $noteList!: JQuery<HTMLElement>;
|
||||
private clonedNoteIds: string[] | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$form = this.$widget.find(".clone-to-form");
|
||||
this.$noteAutoComplete = this.$widget.find(".clone-to-note-autocomplete");
|
||||
this.$clonePrefix = this.$widget.find(".clone-prefix");
|
||||
this.$noteList = this.$widget.find(".clone-to-note-list");
|
||||
|
||||
this.$form.on("submit", () => {
|
||||
const notePath = this.$noteAutoComplete.getSelectedNotePath();
|
||||
|
||||
if (notePath) {
|
||||
this.$widget.modal("hide");
|
||||
this.cloneNotesTo(notePath);
|
||||
} else {
|
||||
logError(t("clone_to.no_path_to_clone_to"));
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async cloneNoteIdsToEvent({ noteIds }: EventData<"cloneNoteIdsTo">) {
|
||||
if (!noteIds || noteIds.length === 0) {
|
||||
noteIds = [appContext.tabManager.getActiveContextNoteId() ?? ""];
|
||||
}
|
||||
|
||||
this.clonedNoteIds = [];
|
||||
|
||||
for (const noteId of noteIds) {
|
||||
if (!this.clonedNoteIds.includes(noteId)) {
|
||||
this.clonedNoteIds.push(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
openDialog(this.$widget);
|
||||
this.$noteAutoComplete.val("").trigger("focus");
|
||||
this.$noteList.empty();
|
||||
|
||||
for (const noteId of this.clonedNoteIds) {
|
||||
const note = await froca.getNote(noteId);
|
||||
if (!note) {
|
||||
continue;
|
||||
}
|
||||
this.$noteList.append($("<li>").text(note.title));
|
||||
}
|
||||
|
||||
noteAutocompleteService.initNoteAutocomplete(this.$noteAutoComplete);
|
||||
noteAutocompleteService.showRecentNotes(this.$noteAutoComplete);
|
||||
}
|
||||
|
||||
async cloneNotesTo(notePath: string) {
|
||||
const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath);
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetBranchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!targetBranchId || !this.clonedNoteIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const cloneNoteId of this.clonedNoteIds) {
|
||||
await branchService.cloneNoteToBranch(cloneNoteId, targetBranchId, this.$clonePrefix.val() as string);
|
||||
|
||||
const clonedNote = await froca.getNote(cloneNoteId);
|
||||
const targetBranch = froca.getBranch(targetBranchId);
|
||||
if (!clonedNote || !targetBranch) {
|
||||
continue;
|
||||
}
|
||||
const targetNote = await targetBranch.getNote();
|
||||
if (!targetNote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toastService.showMessage(t("clone_to.note_cloned", { clonedTitle: clonedNote.title, targetTitle: targetNote.title }));
|
||||
}
|
||||
}
|
||||
}
|
||||
120
apps/client/src/widgets/dialogs/clone_to.tsx
Normal file
120
apps/client/src/widgets/dialogs/clone_to.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { useRef, useState } from "preact/hooks";
|
||||
import appContext from "../../components/app_context";
|
||||
import { t } from "../../services/i18n";
|
||||
import Modal from "../react/Modal";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
import froca from "../../services/froca";
|
||||
import FormGroup from "../react/FormGroup";
|
||||
import FormTextBox from "../react/FormTextBox";
|
||||
import Button from "../react/Button";
|
||||
import { Suggestion, triggerRecentNotes } from "../../services/note_autocomplete";
|
||||
import { logError } from "../../services/ws";
|
||||
import tree from "../../services/tree";
|
||||
import branches from "../../services/branches";
|
||||
import toast from "../../services/toast";
|
||||
import NoteList from "../react/NoteList";
|
||||
import useTriliumEvent from "../react/hooks";
|
||||
|
||||
function CloneToDialogComponent() {
|
||||
const [ clonedNoteIds, setClonedNoteIds ] = useState<string[]>();
|
||||
const [ prefix, setPrefix ] = useState("");
|
||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const autoCompleteRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useTriliumEvent("cloneNoteIdsTo", ({ noteIds }) => {
|
||||
if (!noteIds || noteIds.length === 0) {
|
||||
noteIds = [appContext.tabManager.getActiveContextNoteId() ?? ""];
|
||||
}
|
||||
|
||||
const clonedNoteIds: string[] = [];
|
||||
|
||||
for (const noteId of noteIds) {
|
||||
if (!clonedNoteIds.includes(noteId)) {
|
||||
clonedNoteIds.push(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
setClonedNoteIds(clonedNoteIds);
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
function onSubmit() {
|
||||
if (!clonedNoteIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const notePath = suggestion?.notePath;
|
||||
if (!notePath) {
|
||||
logError(t("clone_to.no_path_to_clone_to"));
|
||||
return;
|
||||
}
|
||||
|
||||
setShown(false);
|
||||
cloneNotesTo(notePath, clonedNoteIds, prefix);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="clone-to-dialog"
|
||||
title={t("clone_to.clone_notes_to")}
|
||||
helpPageId="IakOLONlIfGI"
|
||||
size="lg"
|
||||
footer={<Button text={t("clone_to.clone_to_selected_note")} keyboardShortcut="Enter" />}
|
||||
onSubmit={onSubmit}
|
||||
onShown={() => triggerRecentNotes(autoCompleteRef.current)}
|
||||
onHidden={() => setShown(false)}
|
||||
show={shown}
|
||||
>
|
||||
<h5>{t("clone_to.notes_to_clone")}</h5>
|
||||
<NoteList style={{ maxHeight: "200px", overflow: "auto" }} noteIds={clonedNoteIds} />
|
||||
<FormGroup label={t("clone_to.target_parent_note")}>
|
||||
<NoteAutocomplete
|
||||
placeholder={t("clone_to.search_for_note_by_its_name")}
|
||||
onChange={setSuggestion}
|
||||
inputRef={autoCompleteRef}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup label={t("clone_to.prefix_optional")} title={t("clone_to.cloned_note_prefix_title")}>
|
||||
<FormTextBox name="clone-prefix" onChange={setPrefix} />
|
||||
</FormGroup>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default class CloneToDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <CloneToDialogComponent />;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function cloneNotesTo(notePath: string, clonedNoteIds: string[], prefix?: string) {
|
||||
const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath);
|
||||
if (!noteId || !parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetBranchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
if (!targetBranchId || !clonedNoteIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const cloneNoteId of clonedNoteIds) {
|
||||
await branches.cloneNoteToBranch(cloneNoteId, targetBranchId, prefix);
|
||||
|
||||
const clonedNote = await froca.getNote(cloneNoteId);
|
||||
const targetBranch = froca.getBranch(targetBranchId);
|
||||
if (!clonedNote || !targetBranch) {
|
||||
continue;
|
||||
}
|
||||
const targetNote = await targetBranch.getNote();
|
||||
if (!targetNote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toast.showMessage(t("clone_to.note_cloned", { clonedTitle: clonedNote.title, targetTitle: targetNote.title }));
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import { Modal } from "bootstrap";
|
||||
|
||||
const DELETE_NOTE_BUTTON_CLASS = "confirm-dialog-delete-note";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="confirm-dialog modal mx-auto" tabindex="-1" role="dialog" style="z-index: 2000;">
|
||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${t("confirm.confirmation")}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("confirm.close")}"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="confirm-dialog-content"></div>
|
||||
|
||||
<div class="confirm-dialog-custom"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="confirm-dialog-cancel-button btn btn-sm">${t("confirm.cancel")}</button>
|
||||
|
||||
|
||||
|
||||
<button class="confirm-dialog-ok-button btn btn-primary btn-sm">${t("confirm.ok")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export type ConfirmDialogResult = false | ConfirmDialogOptions;
|
||||
export type ConfirmDialogCallback = (val?: ConfirmDialogResult) => void;
|
||||
|
||||
export interface ConfirmDialogOptions {
|
||||
confirmed: boolean;
|
||||
isDeleteNoteChecked: boolean;
|
||||
}
|
||||
|
||||
// For "showConfirmDialog"
|
||||
|
||||
export interface ConfirmWithMessageOptions {
|
||||
message: string | HTMLElement | JQuery<HTMLElement>;
|
||||
callback: ConfirmDialogCallback;
|
||||
}
|
||||
|
||||
export interface ConfirmWithTitleOptions {
|
||||
title: string;
|
||||
callback: ConfirmDialogCallback;
|
||||
}
|
||||
|
||||
export default class ConfirmDialog extends BasicWidget {
|
||||
private resolve: ConfirmDialogCallback | null;
|
||||
|
||||
private modal!: Modal;
|
||||
private $originallyFocused!: JQuery<HTMLElement> | null;
|
||||
private $confirmContent!: JQuery<HTMLElement>;
|
||||
private $okButton!: JQuery<HTMLElement>;
|
||||
private $cancelButton!: JQuery<HTMLElement>;
|
||||
private $custom!: JQuery<HTMLElement>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.resolve = null;
|
||||
this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterward
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
|
||||
this.$confirmContent = this.$widget.find(".confirm-dialog-content");
|
||||
this.$okButton = this.$widget.find(".confirm-dialog-ok-button");
|
||||
this.$cancelButton = this.$widget.find(".confirm-dialog-cancel-button");
|
||||
this.$custom = this.$widget.find(".confirm-dialog-custom");
|
||||
|
||||
this.$widget.on("shown.bs.modal", () => this.$okButton.trigger("focus"));
|
||||
|
||||
this.$widget.on("hidden.bs.modal", () => {
|
||||
if (this.resolve) {
|
||||
this.resolve(false);
|
||||
}
|
||||
|
||||
if (this.$originallyFocused) {
|
||||
this.$originallyFocused.trigger("focus");
|
||||
this.$originallyFocused = null;
|
||||
}
|
||||
});
|
||||
|
||||
this.$cancelButton.on("click", () => this.doResolve(false));
|
||||
this.$okButton.on("click", () => this.doResolve(true));
|
||||
}
|
||||
|
||||
showConfirmDialogEvent({ message, callback }: ConfirmWithMessageOptions) {
|
||||
this.$originallyFocused = $(":focus");
|
||||
|
||||
this.$custom.hide();
|
||||
|
||||
glob.activeDialog = this.$widget;
|
||||
|
||||
if (typeof message === "string") {
|
||||
message = $("<div>").text(message);
|
||||
}
|
||||
|
||||
this.$confirmContent.empty().append(message);
|
||||
|
||||
this.modal.show();
|
||||
|
||||
this.resolve = callback;
|
||||
}
|
||||
|
||||
showConfirmDeleteNoteBoxWithNoteDialogEvent({ title, callback }: ConfirmWithTitleOptions) {
|
||||
glob.activeDialog = this.$widget;
|
||||
|
||||
this.$confirmContent.text(`${t("confirm.are_you_sure_remove_note", { title: title })}`);
|
||||
|
||||
this.$custom
|
||||
.empty()
|
||||
.append("<br/>")
|
||||
.append(
|
||||
$("<div>")
|
||||
.addClass("form-check")
|
||||
.append(
|
||||
$("<label>")
|
||||
.addClass("form-check-label")
|
||||
.attr("style", "text-decoration: underline dotted var(--main-text-color)")
|
||||
.attr("title", `${t("confirm.if_you_dont_check")}`)
|
||||
.append($("<input>").attr("type", "checkbox").addClass(`form-check-input ${DELETE_NOTE_BUTTON_CLASS}`))
|
||||
.append(`${t("confirm.also_delete_note")}`)
|
||||
)
|
||||
);
|
||||
|
||||
this.$custom.show();
|
||||
|
||||
this.modal.show();
|
||||
|
||||
this.resolve = callback;
|
||||
}
|
||||
|
||||
doResolve(ret: boolean) {
|
||||
if (this.resolve) {
|
||||
this.resolve({
|
||||
confirmed: ret,
|
||||
isDeleteNoteChecked: this.$widget.find(`.${DELETE_NOTE_BUTTON_CLASS}:checked`).length > 0
|
||||
});
|
||||
}
|
||||
|
||||
this.resolve = null;
|
||||
|
||||
this.modal.hide();
|
||||
}
|
||||
}
|
||||
102
apps/client/src/widgets/dialogs/confirm.tsx
Normal file
102
apps/client/src/widgets/dialogs/confirm.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import Modal from "../react/Modal";
|
||||
import Button from "../react/Button";
|
||||
import { t } from "../../services/i18n";
|
||||
import { useState } from "preact/hooks";
|
||||
import FormCheckbox from "../react/FormCheckbox";
|
||||
import useTriliumEvent from "../react/hooks";
|
||||
|
||||
interface ConfirmDialogProps {
|
||||
title?: string;
|
||||
message?: string | HTMLElement;
|
||||
callback?: ConfirmDialogCallback;
|
||||
isConfirmDeleteNoteBox?: boolean;
|
||||
}
|
||||
|
||||
function ConfirmDialogComponent() {
|
||||
const [ opts, setOpts ] = useState<ConfirmDialogProps>();
|
||||
const [ isDeleteNoteChecked, setIsDeleteNoteChecked ] = useState(false);
|
||||
const [ shown, setShown ] = useState(false);
|
||||
|
||||
function showDialog(title: string | null, message: MessageType, callback: ConfirmDialogCallback, isConfirmDeleteNoteBox: boolean) {
|
||||
setOpts({
|
||||
title: title ?? undefined,
|
||||
message: (typeof message === "object" && "length" in message ? message[0] : message),
|
||||
callback,
|
||||
isConfirmDeleteNoteBox
|
||||
});
|
||||
setShown(true);
|
||||
}
|
||||
|
||||
useTriliumEvent("showConfirmDialog", ({ message, callback }) => showDialog(null, message, callback, false));
|
||||
useTriliumEvent("showConfirmDeleteNoteBoxWithNoteDialog", ({ title, callback }) => showDialog(title, t("confirm.are_you_sure_remove_note", { title: title }), callback, true));
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="confirm-dialog"
|
||||
title={opts?.title ?? t("confirm.confirmation")}
|
||||
size="md"
|
||||
zIndex={2000}
|
||||
scrollable={true}
|
||||
onHidden={() => {
|
||||
opts?.callback?.({
|
||||
confirmed: false,
|
||||
isDeleteNoteChecked
|
||||
});
|
||||
setShown(false);
|
||||
}}
|
||||
footer={<>
|
||||
<Button text={t("confirm.cancel")} onClick={() => setShown(false)} />
|
||||
<Button text={t("confirm.ok")} onClick={() => {
|
||||
opts?.callback?.({
|
||||
confirmed: true,
|
||||
isDeleteNoteChecked
|
||||
});
|
||||
setShown(false);
|
||||
}} />
|
||||
</>}
|
||||
show={shown}
|
||||
stackable
|
||||
>
|
||||
{!opts?.message || typeof opts?.message === "string"
|
||||
? <div>{(opts?.message as string) ?? ""}</div>
|
||||
: <div dangerouslySetInnerHTML={{ __html: opts?.message.outerHTML ?? "" }} />}
|
||||
|
||||
{opts?.isConfirmDeleteNoteBox && (
|
||||
<FormCheckbox
|
||||
name="confirm-dialog-delete-note"
|
||||
label={t("confirm.also_delete_note")}
|
||||
hint={t("confirm.if_you_dont_check")}
|
||||
currentValue={isDeleteNoteChecked} onChange={setIsDeleteNoteChecked} />
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export type ConfirmDialogResult = false | ConfirmDialogOptions;
|
||||
export type ConfirmDialogCallback = (val?: ConfirmDialogResult) => void;
|
||||
type MessageType = string | HTMLElement | JQuery<HTMLElement>;
|
||||
|
||||
export interface ConfirmDialogOptions {
|
||||
confirmed: boolean;
|
||||
isDeleteNoteChecked: boolean;
|
||||
}
|
||||
|
||||
export interface ConfirmWithMessageOptions {
|
||||
message: MessageType;
|
||||
callback: ConfirmDialogCallback;
|
||||
}
|
||||
|
||||
// For "showConfirmDialog"
|
||||
export interface ConfirmWithTitleOptions {
|
||||
title: string;
|
||||
callback: ConfirmDialogCallback;
|
||||
}
|
||||
|
||||
export default class ConfirmDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <ConfirmDialogComponent />;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
import server from "../../services/server.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import linkService from "../../services/link.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type { FAttributeRow } from "../../entities/fattribute.js";
|
||||
import { closeActiveDialog, openDialog } from "../../services/dialog.js";
|
||||
|
||||
// TODO: Use common with server.
|
||||
interface Response {
|
||||
noteIdsToBeDeleted: string[];
|
||||
brokenRelations: FAttributeRow[];
|
||||
}
|
||||
|
||||
export interface ResolveOptions {
|
||||
proceed: boolean;
|
||||
deleteAllClones?: boolean;
|
||||
eraseNotes?: boolean;
|
||||
}
|
||||
|
||||
interface ShowDeleteNotesDialogOpts {
|
||||
branchIdsToDelete: string[];
|
||||
callback: (opts: ResolveOptions) => void;
|
||||
forceDeleteAllClones: boolean;
|
||||
}
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="delete-notes-dialog modal mx-auto" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">${t("delete_notes.delete_notes_preview")}</h4>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("delete_notes.close")}"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-checkbox">
|
||||
<label for="delete-all-clones" class="form-check-label tn-checkbox">
|
||||
<input id="delete-all-clones" class="delete-all-clones form-check-input" value="1" type="checkbox">
|
||||
${t("delete_notes.delete_all_clones_description")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-checkbox" style="margin-bottom: 1rem">
|
||||
<label for="erase-notes" class="form-check-label tn-checkbox">
|
||||
<input id="erase-notes" class="erase-notes form-check-input" value="1" type="checkbox">
|
||||
${t("delete_notes.erase_notes_warning")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="delete-notes-list-wrapper">
|
||||
<h4>${t("delete_notes.notes_to_be_deleted", { noteCount: '<span class="deleted-notes-count"></span>' })}</h4>
|
||||
|
||||
<ul class="delete-notes-list" style="max-height: 200px; overflow: auto;"></ul>
|
||||
</div>
|
||||
|
||||
<div class="no-note-to-delete-wrapper alert alert-info">
|
||||
${t("delete_notes.no_note_to_delete")}
|
||||
</div>
|
||||
|
||||
<div class="broken-relations-wrapper">
|
||||
<div class="alert alert-danger">
|
||||
<h4>${t("delete_notes.broken_relations_to_be_deleted", { relationCount: '<span class="broke-relations-count"></span>' })}</h4>
|
||||
|
||||
<ul class="broken-relations-list" style="max-height: 200px; overflow: auto;"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="delete-notes-dialog-cancel-button btn btn-sm">${t("delete_notes.cancel")}</button>
|
||||
|
||||
|
||||
|
||||
<button class="delete-notes-dialog-ok-button btn btn-primary btn-sm">${t("delete_notes.ok")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class DeleteNotesDialog extends BasicWidget {
|
||||
private branchIds: string[] | null;
|
||||
private resolve!: (options: ResolveOptions) => void;
|
||||
|
||||
private $content!: JQuery<HTMLElement>;
|
||||
private $okButton!: JQuery<HTMLElement>;
|
||||
private $cancelButton!: JQuery<HTMLElement>;
|
||||
private $deleteNotesList!: JQuery<HTMLElement>;
|
||||
private $brokenRelationsList!: JQuery<HTMLElement>;
|
||||
private $deletedNotesCount!: JQuery<HTMLElement>;
|
||||
private $noNoteToDeleteWrapper!: JQuery<HTMLElement>;
|
||||
private $deleteNotesListWrapper!: JQuery<HTMLElement>;
|
||||
private $brokenRelationsListWrapper!: JQuery<HTMLElement>;
|
||||
private $brokenRelationsCount!: JQuery<HTMLElement>;
|
||||
private $deleteAllClones!: JQuery<HTMLElement>;
|
||||
private $eraseNotes!: JQuery<HTMLElement>;
|
||||
|
||||
private forceDeleteAllClones?: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.branchIds = null;
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$content = this.$widget.find(".recent-changes-content");
|
||||
this.$okButton = this.$widget.find(".delete-notes-dialog-ok-button");
|
||||
this.$cancelButton = this.$widget.find(".delete-notes-dialog-cancel-button");
|
||||
this.$deleteNotesList = this.$widget.find(".delete-notes-list");
|
||||
this.$brokenRelationsList = this.$widget.find(".broken-relations-list");
|
||||
this.$deletedNotesCount = this.$widget.find(".deleted-notes-count");
|
||||
this.$noNoteToDeleteWrapper = this.$widget.find(".no-note-to-delete-wrapper");
|
||||
this.$deleteNotesListWrapper = this.$widget.find(".delete-notes-list-wrapper");
|
||||
this.$brokenRelationsListWrapper = this.$widget.find(".broken-relations-wrapper");
|
||||
this.$brokenRelationsCount = this.$widget.find(".broke-relations-count");
|
||||
this.$deleteAllClones = this.$widget.find(".delete-all-clones");
|
||||
this.$eraseNotes = this.$widget.find(".erase-notes");
|
||||
|
||||
this.$widget.on("shown.bs.modal", () => this.$okButton.trigger("focus"));
|
||||
|
||||
this.$cancelButton.on("click", () => {
|
||||
closeActiveDialog();
|
||||
|
||||
this.resolve({ proceed: false });
|
||||
});
|
||||
|
||||
this.$okButton.on("click", () => {
|
||||
closeActiveDialog();
|
||||
|
||||
this.resolve({
|
||||
proceed: true,
|
||||
deleteAllClones: this.forceDeleteAllClones || this.isDeleteAllClonesChecked(),
|
||||
eraseNotes: this.isEraseNotesChecked()
|
||||
});
|
||||
});
|
||||
|
||||
this.$deleteAllClones.on("click", () => this.renderDeletePreview());
|
||||
}
|
||||
|
||||
async renderDeletePreview() {
|
||||
const response = await server.post<Response>("delete-notes-preview", {
|
||||
branchIdsToDelete: this.branchIds,
|
||||
deleteAllClones: this.forceDeleteAllClones || this.isDeleteAllClonesChecked()
|
||||
});
|
||||
|
||||
this.$deleteNotesList.empty();
|
||||
this.$brokenRelationsList.empty();
|
||||
|
||||
this.$deleteNotesListWrapper.toggle(response.noteIdsToBeDeleted.length > 0);
|
||||
this.$noNoteToDeleteWrapper.toggle(response.noteIdsToBeDeleted.length === 0);
|
||||
|
||||
for (const note of await froca.getNotes(response.noteIdsToBeDeleted)) {
|
||||
this.$deleteNotesList.append($("<li>").append(await linkService.createLink(note.noteId, { showNotePath: true })));
|
||||
}
|
||||
|
||||
this.$deletedNotesCount.text(response.noteIdsToBeDeleted.length);
|
||||
|
||||
this.$brokenRelationsListWrapper.toggle(response.brokenRelations.length > 0);
|
||||
this.$brokenRelationsCount.text(response.brokenRelations.length);
|
||||
|
||||
await froca.getNotes(response.brokenRelations.map((br) => br.noteId));
|
||||
|
||||
for (const attr of response.brokenRelations) {
|
||||
this.$brokenRelationsList.append(
|
||||
$("<li>").html(
|
||||
t("delete_notes.deleted_relation_text", {
|
||||
note: (await linkService.createLink(attr.value)).html(),
|
||||
relation: `<code>${attr.name}</code>`,
|
||||
source: (await linkService.createLink(attr.noteId)).html()
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async showDeleteNotesDialogEvent({ branchIdsToDelete, callback, forceDeleteAllClones }: ShowDeleteNotesDialogOpts) {
|
||||
this.branchIds = branchIdsToDelete;
|
||||
this.forceDeleteAllClones = forceDeleteAllClones;
|
||||
|
||||
await this.renderDeletePreview();
|
||||
|
||||
openDialog(this.$widget);
|
||||
|
||||
this.$deleteAllClones.prop("checked", !!forceDeleteAllClones).prop("disabled", !!forceDeleteAllClones);
|
||||
|
||||
this.$eraseNotes.prop("checked", false);
|
||||
|
||||
this.resolve = callback;
|
||||
}
|
||||
|
||||
isDeleteAllClonesChecked() {
|
||||
return this.$deleteAllClones.is(":checked");
|
||||
}
|
||||
|
||||
isEraseNotesChecked() {
|
||||
return this.$eraseNotes.is(":checked");
|
||||
}
|
||||
}
|
||||
181
apps/client/src/widgets/dialogs/delete_notes.tsx
Normal file
181
apps/client/src/widgets/dialogs/delete_notes.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import { useRef, useState, useEffect } from "preact/hooks";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import FormCheckbox from "../react/FormCheckbox.js";
|
||||
import Modal from "../react/Modal.js";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||
import type { DeleteNotesPreview } from "@triliumnext/commons";
|
||||
import server from "../../services/server.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import FNote from "../../entities/fnote.js";
|
||||
import link from "../../services/link.js";
|
||||
import Button from "../react/Button.jsx";
|
||||
import Alert from "../react/Alert.jsx";
|
||||
import useTriliumEvent from "../react/hooks.jsx";
|
||||
|
||||
export interface ResolveOptions {
|
||||
proceed: boolean;
|
||||
deleteAllClones?: boolean;
|
||||
eraseNotes?: boolean;
|
||||
}
|
||||
|
||||
interface ShowDeleteNotesDialogOpts {
|
||||
branchIdsToDelete?: string[];
|
||||
callback?: (opts: ResolveOptions) => void;
|
||||
forceDeleteAllClones?: boolean;
|
||||
}
|
||||
|
||||
interface BrokenRelationData {
|
||||
note: string;
|
||||
relation: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
function DeleteNotesDialogComponent() {
|
||||
const [ opts, setOpts ] = useState<ShowDeleteNotesDialogOpts>({});
|
||||
const [ deleteAllClones, setDeleteAllClones ] = useState(false);
|
||||
const [ eraseNotes, setEraseNotes ] = useState(!!opts.forceDeleteAllClones);
|
||||
const [ brokenRelations, setBrokenRelations ] = useState<DeleteNotesPreview["brokenRelations"]>([]);
|
||||
const [ noteIdsToBeDeleted, setNoteIdsToBeDeleted ] = useState<DeleteNotesPreview["noteIdsToBeDeleted"]>([]);
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const okButtonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
useTriliumEvent("showDeleteNotesDialog", (opts) => {
|
||||
setOpts(opts);
|
||||
setShown(true);
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const { branchIdsToDelete, forceDeleteAllClones } = opts;
|
||||
if (!branchIdsToDelete || branchIdsToDelete.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
server.post<DeleteNotesPreview>("delete-notes-preview", {
|
||||
branchIdsToDelete,
|
||||
deleteAllClones: forceDeleteAllClones || deleteAllClones
|
||||
}).then(response => {
|
||||
setBrokenRelations(response.brokenRelations);
|
||||
setNoteIdsToBeDeleted(response.noteIdsToBeDeleted);
|
||||
});
|
||||
}, [ opts, deleteAllClones ]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="delete-notes-dialog"
|
||||
size="xl"
|
||||
scrollable
|
||||
title={t("delete_notes.delete_notes_preview")}
|
||||
onShown={() => okButtonRef.current?.focus()}
|
||||
onHidden={() => {
|
||||
opts.callback?.({ proceed: false })
|
||||
setShown(false);
|
||||
}}
|
||||
footer={<>
|
||||
<Button text={t("delete_notes.cancel")}
|
||||
onClick={() => setShown(false)} />
|
||||
<Button text={t("delete_notes.ok")} primary
|
||||
buttonRef={okButtonRef}
|
||||
onClick={() => {
|
||||
opts.callback?.({ proceed: true, deleteAllClones, eraseNotes });
|
||||
setShown(false);
|
||||
}} />
|
||||
</>}
|
||||
show={shown}
|
||||
>
|
||||
<FormCheckbox name="delete-all-clones" label={t("delete_notes.delete_all_clones_description")}
|
||||
currentValue={deleteAllClones} onChange={setDeleteAllClones}
|
||||
/>
|
||||
<FormCheckbox
|
||||
name="erase-notes" label={t("delete_notes.erase_notes_warning")}
|
||||
disabled={opts.forceDeleteAllClones}
|
||||
currentValue={eraseNotes} onChange={setEraseNotes}
|
||||
/>
|
||||
|
||||
<DeletedNotes noteIdsToBeDeleted={noteIdsToBeDeleted} />
|
||||
<BrokenRelations brokenRelations={brokenRelations} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
function DeletedNotes({ noteIdsToBeDeleted }: { noteIdsToBeDeleted: DeleteNotesPreview["noteIdsToBeDeleted"] }) {
|
||||
const [ noteLinks, setNoteLinks ] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
froca.getNotes(noteIdsToBeDeleted).then(async (notes: FNote[]) => {
|
||||
const noteLinks: string[] = [];
|
||||
|
||||
for (const note of notes) {
|
||||
noteLinks.push((await link.createLink(note.noteId, { showNotePath: true })).html());
|
||||
}
|
||||
|
||||
setNoteLinks(noteLinks);
|
||||
});
|
||||
}, [noteIdsToBeDeleted]);
|
||||
|
||||
if (noteIdsToBeDeleted.length) {
|
||||
return (
|
||||
<div className="delete-notes-list-wrapper">
|
||||
<h4>{t("delete_notes.notes_to_be_deleted", { notesCount: noteIdsToBeDeleted.length })}</h4>
|
||||
|
||||
<ul className="delete-notes-list" style={{ maxHeight: "200px", overflow: "auto" }}>
|
||||
{noteLinks.map((link, index) => (
|
||||
<li key={index} dangerouslySetInnerHTML={{ __html: link }} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Alert type="info">
|
||||
{t("delete_notes.no_note_to_delete")}
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function BrokenRelations({ brokenRelations }: { brokenRelations: DeleteNotesPreview["brokenRelations"] }) {
|
||||
const [ notesWithBrokenRelations, setNotesWithBrokenRelations ] = useState<BrokenRelationData[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const noteIds = brokenRelations
|
||||
.map(relation => relation.noteId)
|
||||
.filter(noteId => noteId) as string[];
|
||||
froca.getNotes(noteIds).then(async (notes) => {
|
||||
const notesWithBrokenRelations: BrokenRelationData[] = [];
|
||||
for (const attr of brokenRelations) {
|
||||
notesWithBrokenRelations.push({
|
||||
note: (await link.createLink(attr.value)).html(),
|
||||
relation: `<code>${attr.name}</code>`,
|
||||
source: (await link.createLink(attr.noteId)).html()
|
||||
});
|
||||
}
|
||||
setNotesWithBrokenRelations(notesWithBrokenRelations);
|
||||
});
|
||||
}, [brokenRelations]);
|
||||
|
||||
if (brokenRelations.length) {
|
||||
return (
|
||||
<Alert type="danger" title={t("delete_notes.broken_relations_to_be_deleted", { relationCount: brokenRelations.length })}>
|
||||
<ul className="broken-relations-list" style={{ maxHeight: "200px", overflow: "auto" }}>
|
||||
{brokenRelations.map((_, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
<span dangerouslySetInnerHTML={{ __html: t("delete_notes.deleted_relation_text", notesWithBrokenRelations[index] as unknown as Record<string, string>) }} />
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Alert>
|
||||
);
|
||||
} else {
|
||||
return <></>;
|
||||
}
|
||||
}
|
||||
|
||||
export default class DeleteNotesDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <DeleteNotesDialogComponent />;
|
||||
}
|
||||
|
||||
}
|
||||
16
apps/client/src/widgets/dialogs/export.css
Normal file
16
apps/client/src/widgets/dialogs/export.css
Normal file
@@ -0,0 +1,16 @@
|
||||
.export-dialog form .form-check {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.export-dialog form .format-choice {
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.export-dialog form .opml-versions {
|
||||
padding-left: 60px;
|
||||
}
|
||||
|
||||
.export-dialog form .form-check-label {
|
||||
padding: 2px;
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
import treeService from "../../services/tree.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import ws from "../../services/ws.js";
|
||||
import toastService, { type ToastOptions } from "../../services/toast.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import openService from "../../services/open.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
import { Modal } from "bootstrap";
|
||||
import { openDialog } from "../../services/dialog.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="export-dialog modal fade mx-auto" tabindex="-1" role="dialog">
|
||||
<style>
|
||||
.export-dialog .export-form .form-check {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.export-dialog .export-form .format-choice {
|
||||
padding-left: 40px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.export-dialog .export-form .opml-versions {
|
||||
padding-left: 60px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.export-dialog .export-form .form-check-label {
|
||||
padding: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">${t("export.export_note_title")} <span class="export-note-title"></span></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("export.close")}"></button>
|
||||
</div>
|
||||
<form class="export-form">
|
||||
<div class="modal-body">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="export-type-subtree form-check-input" type="radio" name="export-type" value="subtree">
|
||||
${t("export.export_type_subtree")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="export-subtree-formats format-choice">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-subtree-format" value="html">
|
||||
${t("export.format_html_zip")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-subtree-format" value="markdown">
|
||||
${t("export.format_markdown")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-subtree-format" value="opml">
|
||||
${t("export.format_opml")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="opml-versions">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="opml-version" value="1.0">
|
||||
${t("export.opml_version_1")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="opml-version" value="2.0">
|
||||
${t("export.opml_version_2")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-type" value="single">
|
||||
${t("export.export_type_single")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="export-single-formats format-choice">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-single-format" value="html">
|
||||
${t("export.format_html")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label tn-radio">
|
||||
<input class="form-check-input" type="radio" name="export-single-format" value="markdown">
|
||||
${t("export.format_markdown")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="export-button btn btn-primary">${t("export.export")}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default class ExportDialog extends BasicWidget {
|
||||
|
||||
private taskId: string;
|
||||
private branchId: string | null;
|
||||
private modal?: Modal;
|
||||
private $form!: JQuery<HTMLElement>;
|
||||
private $noteTitle!: JQuery<HTMLElement>;
|
||||
private $subtreeFormats!: JQuery<HTMLElement>;
|
||||
private $singleFormats!: JQuery<HTMLElement>;
|
||||
private $subtreeType!: JQuery<HTMLElement>;
|
||||
private $singleType!: JQuery<HTMLElement>;
|
||||
private $exportButton!: JQuery<HTMLElement>;
|
||||
private $opmlVersions!: JQuery<HTMLElement>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.taskId = "";
|
||||
this.branchId = null;
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
|
||||
this.$form = this.$widget.find(".export-form");
|
||||
this.$noteTitle = this.$widget.find(".export-note-title");
|
||||
this.$subtreeFormats = this.$widget.find(".export-subtree-formats");
|
||||
this.$singleFormats = this.$widget.find(".export-single-formats");
|
||||
this.$subtreeType = this.$widget.find(".export-type-subtree");
|
||||
this.$singleType = this.$widget.find(".export-type-single");
|
||||
this.$exportButton = this.$widget.find(".export-button");
|
||||
this.$opmlVersions = this.$widget.find(".opml-versions");
|
||||
|
||||
this.$form.on("submit", () => {
|
||||
this.modal?.hide();
|
||||
|
||||
const exportType = this.$widget.find("input[name='export-type']:checked").val();
|
||||
|
||||
if (!exportType) {
|
||||
toastService.showError(t("export.choose_export_type"));
|
||||
return;
|
||||
}
|
||||
|
||||
const exportFormat = exportType === "subtree" ? this.$widget.find("input[name=export-subtree-format]:checked").val() : this.$widget.find("input[name=export-single-format]:checked").val();
|
||||
|
||||
const exportVersion = exportFormat === "opml" ? this.$widget.find("input[name='opml-version']:checked").val() : "1.0";
|
||||
|
||||
if (this.branchId) {
|
||||
this.exportBranch(this.branchId, String(exportType), String(exportFormat), String(exportVersion));
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this.$widget.find("input[name=export-type]").on("change", (e) => {
|
||||
if ((e.currentTarget as HTMLInputElement).value === "subtree") {
|
||||
if (this.$widget.find("input[name=export-subtree-format]:checked").length === 0) {
|
||||
this.$widget.find("input[name=export-subtree-format]:first").prop("checked", true);
|
||||
}
|
||||
|
||||
this.$subtreeFormats.slideDown();
|
||||
this.$singleFormats.slideUp();
|
||||
} else {
|
||||
if (this.$widget.find("input[name=export-single-format]:checked").length === 0) {
|
||||
this.$widget.find("input[name=export-single-format]:first").prop("checked", true);
|
||||
}
|
||||
|
||||
this.$subtreeFormats.slideUp();
|
||||
this.$singleFormats.slideDown();
|
||||
}
|
||||
});
|
||||
|
||||
this.$widget.find("input[name=export-subtree-format]").on("change", (e) => {
|
||||
if ((e.currentTarget as HTMLInputElement).value === "opml") {
|
||||
this.$opmlVersions.slideDown();
|
||||
} else {
|
||||
this.$opmlVersions.slideUp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async showExportDialogEvent({ notePath, defaultType }: EventData<"showExportDialog">) {
|
||||
this.taskId = "";
|
||||
this.$exportButton.removeAttr("disabled");
|
||||
|
||||
if (defaultType === "subtree") {
|
||||
this.$subtreeType.prop("checked", true).trigger("change");
|
||||
|
||||
this.$widget.find("input[name=export-subtree-format]:checked").trigger("change");
|
||||
} else if (defaultType === "single") {
|
||||
this.$singleType.prop("checked", true).trigger("change");
|
||||
} else {
|
||||
throw new Error(`Unrecognized type '${defaultType}'`);
|
||||
}
|
||||
|
||||
this.$widget.find(".opml-v2").prop("checked", true); // setting default
|
||||
|
||||
openDialog(this.$widget);
|
||||
|
||||
const { noteId, parentNoteId } = treeService.getNoteIdAndParentIdFromUrl(notePath);
|
||||
|
||||
if (parentNoteId) {
|
||||
this.branchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
}
|
||||
if (noteId) {
|
||||
this.$noteTitle.text(await treeService.getNoteTitle(noteId));
|
||||
}
|
||||
}
|
||||
|
||||
exportBranch(branchId: string, type: string, format: string, version: string) {
|
||||
this.taskId = utils.randomString(10);
|
||||
|
||||
const url = openService.getUrlForDownload(`api/branches/${branchId}/export/${type}/${format}/${version}/${this.taskId}`);
|
||||
|
||||
openService.download(url);
|
||||
}
|
||||
}
|
||||
|
||||
ws.subscribeToMessages(async (message) => {
|
||||
function makeToast(id: string, message: string): ToastOptions {
|
||||
return {
|
||||
id: id,
|
||||
title: t("export.export_status"),
|
||||
message: message,
|
||||
icon: "arrow-square-up-right"
|
||||
};
|
||||
}
|
||||
|
||||
if (message.taskType !== "export") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === "taskError") {
|
||||
toastService.closePersistent(message.taskId);
|
||||
toastService.showError(message.message);
|
||||
} else if (message.type === "taskProgressCount") {
|
||||
toastService.showPersistent(makeToast(message.taskId, t("export.export_in_progress", { progressCount: message.progressCount })));
|
||||
} else if (message.type === "taskSucceeded") {
|
||||
const toast = makeToast(message.taskId, t("export.export_finished_successfully"));
|
||||
toast.closeAfter = 5000;
|
||||
|
||||
toastService.showPersistent(toast);
|
||||
}
|
||||
});
|
||||
167
apps/client/src/widgets/dialogs/export.tsx
Normal file
167
apps/client/src/widgets/dialogs/export.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
import { useState } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import tree from "../../services/tree";
|
||||
import Button from "../react/Button";
|
||||
import FormRadioGroup from "../react/FormRadioGroup";
|
||||
import Modal from "../react/Modal";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
import "./export.css";
|
||||
import ws from "../../services/ws";
|
||||
import toastService, { ToastOptions } from "../../services/toast";
|
||||
import utils from "../../services/utils";
|
||||
import open from "../../services/open";
|
||||
import froca from "../../services/froca";
|
||||
import useTriliumEvent from "../react/hooks";
|
||||
|
||||
interface ExportDialogProps {
|
||||
branchId?: string | null;
|
||||
noteTitle?: string;
|
||||
defaultType?: "subtree" | "single";
|
||||
}
|
||||
|
||||
function ExportDialogComponent() {
|
||||
const [ opts, setOpts ] = useState<ExportDialogProps>();
|
||||
const [ exportType, setExportType ] = useState<string>(opts?.defaultType ?? "subtree");
|
||||
const [ subtreeFormat, setSubtreeFormat ] = useState("html");
|
||||
const [ singleFormat, setSingleFormat ] = useState("html");
|
||||
const [ opmlVersion, setOpmlVersion ] = useState("2.0");
|
||||
const [ shown, setShown ] = useState(false);
|
||||
|
||||
useTriliumEvent("showExportDialog", async ({ notePath, defaultType }) => {
|
||||
const { noteId, parentNoteId } = tree.getNoteIdAndParentIdFromUrl(notePath);
|
||||
if (!parentNoteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const branchId = await froca.getBranchId(parentNoteId, noteId);
|
||||
|
||||
setOpts({
|
||||
noteTitle: noteId && await tree.getNoteTitle(noteId),
|
||||
defaultType,
|
||||
branchId
|
||||
});
|
||||
setShown(true);
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="export-dialog"
|
||||
title={`${t("export.export_note_title")} ${opts?.noteTitle ?? ""}`}
|
||||
size="lg"
|
||||
onSubmit={() => {
|
||||
if (!opts || !opts.branchId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const format = (exportType === "subtree" ? subtreeFormat : singleFormat);
|
||||
const version = (format === "opml" ? opmlVersion : "1.0");
|
||||
exportBranch(opts.branchId, exportType, format, version);
|
||||
setShown(false);
|
||||
}}
|
||||
onHidden={() => setShown(false)}
|
||||
footer={<Button className="export-button" text={t("export.export")} primary />}
|
||||
show={shown}
|
||||
>
|
||||
|
||||
<FormRadioGroup
|
||||
name="export-type"
|
||||
currentValue={exportType} onChange={setExportType}
|
||||
values={[{
|
||||
value: "subtree",
|
||||
label: t("export.export_type_subtree")
|
||||
}]}
|
||||
/>
|
||||
|
||||
{ exportType === "subtree" &&
|
||||
<div className="export-subtree-formats format-choice">
|
||||
<FormRadioGroup
|
||||
name="export-subtree-format"
|
||||
currentValue={subtreeFormat} onChange={setSubtreeFormat}
|
||||
values={[
|
||||
{ value: "html", label: t("export.format_html_zip") },
|
||||
{ value: "markdown", label: t("export.format_markdown") },
|
||||
{ value: "opml", label: t("export.format_opml") }
|
||||
]}
|
||||
/>
|
||||
|
||||
{ subtreeFormat === "opml" &&
|
||||
<div className="opml-versions">
|
||||
<FormRadioGroup
|
||||
name="opml-version"
|
||||
currentValue={opmlVersion} onChange={setOpmlVersion}
|
||||
values={[
|
||||
{ value: "1.0", label: t("export.opml_version_1") },
|
||||
{ value: "2.0", label: t("export.opml_version_2") }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<FormRadioGroup
|
||||
name="export-type"
|
||||
currentValue={exportType} onChange={setExportType}
|
||||
values={[{
|
||||
value: "single",
|
||||
label: t("export.export_type_single")
|
||||
}]}
|
||||
/>
|
||||
|
||||
{ exportType === "single" &&
|
||||
<div class="export-single-formats format-choice">
|
||||
<FormRadioGroup
|
||||
name="export-single-format"
|
||||
currentValue={singleFormat} onChange={setSingleFormat}
|
||||
values={[
|
||||
{ value: "html", label: t("export.format_html") },
|
||||
{ value: "markdown", label: t("export.format_markdown") }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default class ExportDialog extends ReactBasicWidget {
|
||||
|
||||
get component() {
|
||||
return <ExportDialogComponent />
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function exportBranch(branchId: string, type: string, format: string, version: string) {
|
||||
const taskId = utils.randomString(10);
|
||||
const url = open.getUrlForDownload(`api/branches/${branchId}/export/${type}/${format}/${version}/${taskId}`);
|
||||
open.download(url);
|
||||
}
|
||||
|
||||
ws.subscribeToMessages(async (message) => {
|
||||
function makeToast(id: string, message: string): ToastOptions {
|
||||
return {
|
||||
id: id,
|
||||
title: t("export.export_status"),
|
||||
message: message,
|
||||
icon: "arrow-square-up-right"
|
||||
};
|
||||
}
|
||||
|
||||
if (message.taskType !== "export") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type === "taskError") {
|
||||
toastService.closePersistent(message.taskId);
|
||||
toastService.showError(message.message);
|
||||
} else if (message.type === "taskProgressCount") {
|
||||
toastService.showPersistent(makeToast(message.taskId, t("export.export_in_progress", { progressCount: message.progressCount })));
|
||||
} else if (message.type === "taskSucceeded") {
|
||||
const toast = makeToast(message.taskId, t("export.export_finished_successfully"));
|
||||
toast.closeAfter = 5000;
|
||||
|
||||
toastService.showPersistent(toast);
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user