mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Merge branch 'feature/trilium_next_theme' of https://github.com/TriliumNext/Notes into feature/trilium_next_theme
This commit is contained in:
		
							
								
								
									
										12
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/ISSUE_TEMPLATE/bug_report.yml
									
									
									
									
										vendored
									
									
								
							| @@ -3,6 +3,12 @@ description: Report a bug | |||||||
| title: "(Bug report) " | title: "(Bug report) " | ||||||
| labels: "Type: Bug" | labels: "Type: Bug" | ||||||
| body: | body: | ||||||
|  | - type: textarea | ||||||
|  |   attributes: | ||||||
|  |     label: Description | ||||||
|  |     description: A clear and concise description of the bug and any additional information. | ||||||
|  |   validations: | ||||||
|  |     required: true | ||||||
| - type: input | - type: input | ||||||
|   attributes: |   attributes: | ||||||
|     label: TriliumNext Version |     label: TriliumNext Version | ||||||
| @@ -38,12 +44,6 @@ body: | |||||||
|     placeholder: "e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04" |     placeholder: "e.g. Windows 10 version 1909, macOS Catalina 10.15.7, or Ubuntu 20.04" | ||||||
|   validations: |   validations: | ||||||
|     required: true |     required: true | ||||||
| - type: textarea |  | ||||||
|   attributes: |  | ||||||
|     label: Description |  | ||||||
|     description: A clear and concise description of the bug and any additional information. |  | ||||||
|   validations: |  | ||||||
|     required: true |  | ||||||
| - type: textarea | - type: textarea | ||||||
|   attributes: |   attributes: | ||||||
|     label: Error logs |     label: Error logs | ||||||
|   | |||||||
| @@ -17,17 +17,45 @@ | |||||||
| # | # | ||||||
| # -------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | number_of_keys() { | ||||||
|  | 	[ -f "$1" ] && jq 'path(..) | select(length == 2) | .[1]' "$1" | wc -l || echo "0" | ||||||
|  | } | ||||||
|  |  | ||||||
| stats() { | stats() { | ||||||
| 	# Print the number of existing strings on the JSON files for each locale | 	# Print the number of existing strings on the JSON files for each locale | ||||||
| 	s=$(jq 'path(..) | select(length == 2) | .[1]' "${paths[0]}/en/server.json" | wc -l) | 	s=$(number_of_keys "${paths[0]}/en/server.json") | ||||||
| 	c=$(jq 'path(..) | select(length == 2) | .[1]' "${paths[1]}/en/translation.json" | wc -l) | 	c=$(number_of_keys "${paths[1]}/en/translation.json") | ||||||
| 	echo "|locale |server strings |client strings |" | 	echo "| locale |server strings |client strings |" | ||||||
| 	echo "|-------|---------------|---------------|" | 	echo "|--------|---------------|---------------|" | ||||||
| 	echo "|  en   |      ${s}      |     ${c}      |" | 	echo "|   en   |      ${s}      |     ${c}      |" | ||||||
| 	for locale in "${locales[@]}"; do | 	for locale in "${locales[@]}"; do | ||||||
| 		s=$(jq 'path(..) | select(length == 2) | .[1]' "${paths[0]}/${locale}/server.json" | wc -l) | 		s=$(number_of_keys "${paths[0]}/${locale}/server.json") | ||||||
| 		c=$(jq 'path(..) | select(length == 2) | .[1]' "${paths[1]}/${locale}/translation.json" | wc -l) | 		c=$(number_of_keys "${paths[1]}/${locale}/translation.json") | ||||||
| 		echo "|  ${locale}   |      ${s}      |     ${c}      |" | 		n1=$(((8 - ${#locale}) / 2)) | ||||||
|  | 		n2=$((n1 == 1 ? n1 + 1 : n1)) | ||||||
|  | 		echo "|$(printf "%${n1}s")${locale}$(printf "%${n2}s")|      ${s}      |     ${c}      |" | ||||||
|  | 	done | ||||||
|  | } | ||||||
|  |  | ||||||
|  | update_1() { | ||||||
|  | 	# Update PO files from English and localized JSON files as source | ||||||
|  | 	# NOTE: if you want a new language you need to first create the JSON files | ||||||
|  | 	# on their corresponding place with `{}` as content to avoid error on `json2po` | ||||||
|  | 	local locales=("$@") | ||||||
|  | 	for path in "${paths[@]}"; do | ||||||
|  | 		for locale in "${locales[@]}"; do | ||||||
|  | 			json2po -t "${path}/en" "${path}/${locale}" "${path}/po-${locale}" | ||||||
|  | 		done | ||||||
|  | 	done | ||||||
|  | } | ||||||
|  |  | ||||||
|  | update_2() { | ||||||
|  | 	# Recover translation from PO files to localized JSON files | ||||||
|  | 	local locales=("$@") | ||||||
|  | 	for path in "${paths[@]}"; do | ||||||
|  | 		for locale in "${locales[@]}"; do | ||||||
|  | 			po2json -t "${path}/en" "${path}/po-${locale}" "${path}/${locale}" | ||||||
|  | 		done | ||||||
| 	done | 	done | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -35,11 +63,11 @@ help() { | |||||||
| 	echo -e "\nDescription:" | 	echo -e "\nDescription:" | ||||||
| 	echo -e "\tCreate PO files to make easier the labor of translation" | 	echo -e "\tCreate PO files to make easier the labor of translation" | ||||||
| 	echo -e "\nUsage:" | 	echo -e "\nUsage:" | ||||||
| 	echo -e "\t./translation.sh [--stats] [--update <OPT_LOCALE>] [--update2 <OPT_LOCALE>]" | 	echo -e "\t./translation.sh [--stats] [--update1 <OPT_LOCALE>] [--update2 <OPT_LOCALE>]" | ||||||
| 	echo -e "\nFlags:" | 	echo -e "\nFlags:" | ||||||
| 	echo -e "  --clear\n\tClear all po-* directories" | 	echo -e "  --clear\n\tClear all po-* directories" | ||||||
| 	echo -e "  --stats\n\tPrint the number of existing strings on the JSON files for each locale" | 	echo -e "  --stats\n\tPrint the number of existing strings on the JSON files for each locale" | ||||||
| 	echo -e "  --update <LOCALE>\n\tUpdate PO files from English and localized JSON files as source" | 	echo -e "  --update1 <LOCALE>\n\tUpdate PO files from English and localized JSON files as source" | ||||||
| 	echo -e "  --update2 <LOCALE>\n\tRecover translation from PO files to localized JSON files" | 	echo -e "  --update2 <LOCALE>\n\tRecover translation from PO files to localized JSON files" | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -51,7 +79,7 @@ file_path="$( | |||||||
| 	pwd -P | 	pwd -P | ||||||
| )" | )" | ||||||
| paths=("${file_path}/../translations/" "${file_path}/../src/public/translations/") | paths=("${file_path}/../translations/" "${file_path}/../src/public/translations/") | ||||||
| locales=(cn es fr ro) | locales=(cn de es fr pt_br ro tw) | ||||||
|  |  | ||||||
| if [ $# -eq 1 ]; then | if [ $# -eq 1 ]; then | ||||||
| 	if [ "$1" == "--clear" ]; then | 	if [ "$1" == "--clear" ]; then | ||||||
| @@ -62,34 +90,18 @@ if [ $# -eq 1 ]; then | |||||||
| 		done | 		done | ||||||
| 	elif [ "$1" == "--stats" ]; then | 	elif [ "$1" == "--stats" ]; then | ||||||
| 		stats | 		stats | ||||||
| 	elif [ "$1" == "--update" ]; then | 	elif [ "$1" == "--update1" ]; then | ||||||
| 		# Update PO files from English and localized JSON files as source | 		update_1 "${locales[@]}" | ||||||
| 		for path in "${paths[@]}"; do |  | ||||||
| 			for locale in "${locales[@]}"; do |  | ||||||
| 				json2po -t "${path}/en" "${path}/${locale}" "${path}/po-${locale}" |  | ||||||
| 			done |  | ||||||
| 		done |  | ||||||
| 	elif [ "$1" == "--update2" ]; then | 	elif [ "$1" == "--update2" ]; then | ||||||
| 		# Recover translation from PO files to localized JSON files | 		update_2 "${locales[@]}" | ||||||
| 		for path in "${paths[@]}"; do |  | ||||||
| 			for locale in "${locales[@]}"; do |  | ||||||
| 				po2json -t "${path}/en" "${path}/po-${locale}" "${path}/${locale}" |  | ||||||
| 			done |  | ||||||
| 		done |  | ||||||
| 	else | 	else | ||||||
| 		help | 		help | ||||||
| 	fi | 	fi | ||||||
| elif [ $# -eq 2 ]; then | elif [ $# -eq 2 ]; then | ||||||
| 	if [ "$1" == "--update" ]; then | 	if [ "$1" == "--update1" ]; then | ||||||
| 		locale="$2" | 		update_1 "$2" | ||||||
| 		for path in "${paths[@]}"; do |  | ||||||
| 			json2po -t "${path}/en" "${path}/${locale}" "${path}/po-${locale}" |  | ||||||
| 		done |  | ||||||
| 	elif [ "$1" == "--update2" ]; then | 	elif [ "$1" == "--update2" ]; then | ||||||
| 		locale="$2" | 		update_2 "$2" | ||||||
| 		for path in "${paths[@]}"; do |  | ||||||
| 			po2json -t "${path}/en" "${path}/po-${locale}" "${path}/${locale}" |  | ||||||
| 		done |  | ||||||
| 	else | 	else | ||||||
| 		help | 		help | ||||||
| 	fi | 	fi | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1
									
								
								libraries/mermaid-elk/elk.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libraries/mermaid-elk/elk.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										13
									
								
								libraries/mermaid-elk/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								libraries/mermaid-elk/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "name": "mermaid-elk", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "lockfileVersion": 3, | ||||||
|  |   "requires": true, | ||||||
|  |   "packages": { | ||||||
|  |     "": { | ||||||
|  |       "name": "mermaid-elk", | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "license": "ISC" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								libraries/mermaid-elk/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								libraries/mermaid-elk/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "name": "mermaid-elk", | ||||||
|  |   "version": "1.0.0", | ||||||
|  |   "main": "index.js", | ||||||
|  |   "scripts": { | ||||||
|  |     "build": "cross-env node --import ../../loader-register.js ../../node_modules/webpack/bin/webpack.js -c webpack.config.cjs" | ||||||
|  |   }, | ||||||
|  |   "keywords": [], | ||||||
|  |   "author": "", | ||||||
|  |   "license": "ISC", | ||||||
|  |   "description": "", | ||||||
|  |   "dependencies": {} | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								libraries/mermaid-elk/webpack.config.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								libraries/mermaid-elk/webpack.config.cjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | const path = require("path"); | ||||||
|  | const webpack = require("webpack"); | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |     mode: "production", | ||||||
|  |     entry: "../../node_modules/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs", | ||||||
|  |     output: { | ||||||
|  |         library: "MERMAID_ELK", | ||||||
|  |         filename: "elk.min.js", | ||||||
|  |         path: path.resolve(__dirname), | ||||||
|  |         libraryTarget: "umd", | ||||||
|  |         libraryExport: "default" | ||||||
|  |     }, | ||||||
|  |     plugins: [ | ||||||
|  |         new webpack.optimize.LimitChunkCountPlugin({ | ||||||
|  |             maxChunks: 1 | ||||||
|  |         }) | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,18 +1,19 @@ | |||||||
| { | { | ||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "version": "0.90.11-beta", |   "version": "0.90.12", | ||||||
|   "lockfileVersion": 3, |   "lockfileVersion": 3, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "trilium", |       "name": "trilium", | ||||||
|       "version": "0.90.11-beta", |       "version": "0.90.12", | ||||||
|       "license": "AGPL-3.0-only", |       "license": "AGPL-3.0-only", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@braintree/sanitize-url": "7.1.0", |         "@braintree/sanitize-url": "7.1.0", | ||||||
|         "@electron/remote": "2.1.2", |         "@electron/remote": "2.1.2", | ||||||
|         "@excalidraw/excalidraw": "0.17.6", |         "@excalidraw/excalidraw": "0.17.6", | ||||||
|         "@highlightjs/cdn-assets": "11.10.0", |         "@highlightjs/cdn-assets": "11.10.0", | ||||||
|  |         "@mermaid-js/layout-elk": "0.1.5", | ||||||
|         "archiver": "7.0.1", |         "archiver": "7.0.1", | ||||||
|         "async-mutex": "0.5.0", |         "async-mutex": "0.5.0", | ||||||
|         "autocomplete.js": "0.38.1", |         "autocomplete.js": "0.38.1", | ||||||
| @@ -3072,6 +3073,18 @@ | |||||||
|         "url": "https://github.com/malept/cross-spawn-promise?sponsor=1" |         "url": "https://github.com/malept/cross-spawn-promise?sponsor=1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@mermaid-js/layout-elk": { | ||||||
|  |       "version": "0.1.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.1.5.tgz", | ||||||
|  |       "integrity": "sha512-6ML4iWdVdyIkSW47KiID9runHzaomLxdMfNo9U60LJvfcQkB/FAjg0Vjc4AZEQnnBq7ibAoAknAWlT1XetwXSg==", | ||||||
|  |       "dependencies": { | ||||||
|  |         "d3": "^7.9.0", | ||||||
|  |         "elkjs": "^0.9.3" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "mermaid": "^11.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@mermaid-js/parser": { |     "node_modules/@mermaid-js/parser": { | ||||||
|       "version": "0.3.0", |       "version": "0.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", |       "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.3.0.tgz", | ||||||
| @@ -7904,6 +7917,11 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", |       "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", | ||||||
|       "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" |       "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/elkjs": { | ||||||
|  |       "version": "0.9.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", | ||||||
|  |       "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==" | ||||||
|  |     }, | ||||||
|     "node_modules/emitter-listener": { |     "node_modules/emitter-listener": { | ||||||
|       "version": "1.1.2", |       "version": "1.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "TriliumNext Notes", |   "productName": "TriliumNext Notes", | ||||||
|   "description": "Build your personal knowledge base with TriliumNext Notes", |   "description": "Build your personal knowledge base with TriliumNext Notes", | ||||||
|   "version": "0.90.11-beta", |   "version": "0.90.12", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "./dist/electron-main.js", |   "main": "./dist/electron-main.js", | ||||||
|   "author": { |   "author": { | ||||||
| @@ -54,6 +54,7 @@ | |||||||
|     "@electron/remote": "2.1.2", |     "@electron/remote": "2.1.2", | ||||||
|     "@excalidraw/excalidraw": "0.17.6", |     "@excalidraw/excalidraw": "0.17.6", | ||||||
|     "@highlightjs/cdn-assets": "11.10.0", |     "@highlightjs/cdn-assets": "11.10.0", | ||||||
|  |     "@mermaid-js/layout-elk": "0.1.5", | ||||||
|     "archiver": "7.0.1", |     "archiver": "7.0.1", | ||||||
|     "async-mutex": "0.5.0", |     "async-mutex": "0.5.0", | ||||||
|     "autocomplete.js": "0.38.1", |     "autocomplete.js": "0.38.1", | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import { t } from '../services/i18n.js'; | ||||||
| import utils from "../services/utils.js"; | import utils from "../services/utils.js"; | ||||||
| import contextMenu from "./context_menu.js"; | import contextMenu from "./context_menu.js"; | ||||||
| import imageService from "../services/image.js"; | import imageService from "../services/image.js"; | ||||||
| @@ -18,14 +19,14 @@ function setupContextMenu($image) { | |||||||
|             y: e.pageY, |             y: e.pageY, | ||||||
|             items: [ |             items: [ | ||||||
|                 { |                 { | ||||||
|                     title: "Copy reference to clipboard", |                     title: t("image_context_menu.copy_reference_to_clipboard"), | ||||||
|                     command: "copyImageReferenceToClipboard", |                     command: "copyImageReferenceToClipboard", | ||||||
|                     uiIcon: "bx bx-directions" |                     uiIcon: "bx bx-directions" | ||||||
|                 }, |                 }, | ||||||
|                 {  |                 { | ||||||
|                     title: "Copy image to clipboard", |                     title: t("image_context_menu.copy_image_to_clipboard"), | ||||||
|                     command: "copyImageToClipboard", |                     command: "copyImageToClipboard", | ||||||
|                     uiIcon: "bx bx-copy"  |                     uiIcon: "bx bx-copy" | ||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|             selectMenuItemHandler: async ({ command }) => { |             selectMenuItemHandler: async ({ command }) => { | ||||||
| @@ -61,4 +62,4 @@ function setupContextMenu($image) { | |||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     setupContextMenu |     setupContextMenu | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import { t } from "../services/i18n.js"; | ||||||
| import contextMenu from "./context_menu.js"; | import contextMenu from "./context_menu.js"; | ||||||
| import appContext from "../components/app_context.js"; | import appContext from "../components/app_context.js"; | ||||||
|  |  | ||||||
| @@ -6,9 +7,9 @@ function openContextMenu(notePath, e, viewScope = {}, hoistedNoteId = null) { | |||||||
|         x: e.pageX, |         x: e.pageX, | ||||||
|         y: e.pageY, |         y: e.pageY, | ||||||
|         items: [ |         items: [ | ||||||
|             {title: "Open note in a new tab", command: "openNoteInNewTab", uiIcon: "bx bx-link-external"}, |             {title: t("link_context_menu.open_note_in_new_tab"), command: "openNoteInNewTab", uiIcon: "bx bx-link-external"}, | ||||||
|             {title: "Open note in a new split", command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right"}, |             {title: t("link_context_menu.open_note_in_new_split"), command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right"}, | ||||||
|             {title: "Open note in a new window", command: "openNoteInNewWindow", uiIcon: "bx bx-window-open"} |             {title: t("link_context_menu.open_note_in_new_window"), command: "openNoteInNewWindow", uiIcon: "bx bx-window-open"} | ||||||
|         ], |         ], | ||||||
|         selectMenuItemHandler: ({command}) => { |         selectMenuItemHandler: ({command}) => { | ||||||
|             if (!hoistedNoteId) { |             if (!hoistedNoteId) { | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ import FAttachment from "../entities/fattachment.js"; | |||||||
| import imageContextMenuService from "../menus/image_context_menu.js"; | import imageContextMenuService from "../menus/image_context_menu.js"; | ||||||
| import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_highlight.js"; | import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_highlight.js"; | ||||||
| import mime_types from "./mime_types.js"; | import mime_types from "./mime_types.js"; | ||||||
|  | import { loadElkIfNeeded } from "./mermaid.js"; | ||||||
|  |  | ||||||
| let idCounter = 1; | let idCounter = 1; | ||||||
|  |  | ||||||
| @@ -237,6 +238,7 @@ async function renderMermaid(note, $renderedContent) { | |||||||
|     mermaid.mermaidAPI.initialize({startOnLoad: false, theme: mermaidTheme.trim(), securityLevel: 'antiscript'}); |     mermaid.mermaidAPI.initialize({startOnLoad: false, theme: mermaidTheme.trim(), securityLevel: 'antiscript'}); | ||||||
|  |  | ||||||
|     try { |     try { | ||||||
|  |         await loadElkIfNeeded(content); | ||||||
|         const {svg} = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content); |         const {svg} = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content); | ||||||
|  |  | ||||||
|         $renderedContent.append($(svg)); |         $renderedContent.append($(svg)); | ||||||
|   | |||||||
| @@ -58,7 +58,19 @@ const FORCE_GRAPH = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| const MERMAID = { | const MERMAID = { | ||||||
|     js: [ "node_modules/mermaid/dist/mermaid.min.js" ] |     js: [ | ||||||
|  |         "node_modules/mermaid/dist/mermaid.min.js"         | ||||||
|  |     ] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * The ELK extension of Mermaid.js, which supports more advanced layouts. | ||||||
|  |  * See https://www.npmjs.com/package/@mermaid-js/layout-elk for more information. | ||||||
|  |  */ | ||||||
|  | const MERMAID_ELK = { | ||||||
|  |     js: [ | ||||||
|  |         "libraries/mermaid-elk/elk.min.js" | ||||||
|  |     ] | ||||||
| } | } | ||||||
|  |  | ||||||
| const EXCALIDRAW = { | const EXCALIDRAW = { | ||||||
| @@ -197,6 +209,7 @@ export default { | |||||||
|     WHEEL_ZOOM, |     WHEEL_ZOOM, | ||||||
|     FORCE_GRAPH, |     FORCE_GRAPH, | ||||||
|     MERMAID, |     MERMAID, | ||||||
|  |     MERMAID_ELK, | ||||||
|     EXCALIDRAW, |     EXCALIDRAW, | ||||||
|     MARKJS, |     MARKJS, | ||||||
|     I18NEXT, |     I18NEXT, | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								src/public/app/services/mermaid.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/public/app/services/mermaid.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | import library_loader from "./library_loader.js"; | ||||||
|  |  | ||||||
|  | let elkLoaded = false; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Determines whether the ELK extension of Mermaid.js needs to be loaded (which is a relatively large library), based on the | ||||||
|  |  * front-matter of the diagram and loads the library if needed. | ||||||
|  |  *  | ||||||
|  |  * <p> | ||||||
|  |  * If the library has already been loaded or the diagram does not require it, the method will exit immediately. | ||||||
|  |  *  | ||||||
|  |  * @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter. | ||||||
|  |  */ | ||||||
|  | export async function loadElkIfNeeded(mermaidContent) { | ||||||
|  |     if (elkLoaded) { | ||||||
|  |         // Exit immediately since the ELK library is already loaded. | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const parsedContent = await mermaid.parse(mermaidContent, { | ||||||
|  |         suppressErrors: true  | ||||||
|  |     }); | ||||||
|  |     if (parsedContent?.config?.layout === "elk") { | ||||||
|  |         elkLoaded = true; | ||||||
|  |         await library_loader.requireLibrary(library_loader.MERMAID_ELK); | ||||||
|  |         mermaid.registerLayoutLoaders(MERMAID_ELK); | ||||||
|  |     }     | ||||||
|  | } | ||||||
| @@ -6,7 +6,7 @@ function parse(value) { | |||||||
|         if (token === 'promoted') { |         if (token === 'promoted') { | ||||||
|             defObj.isPromoted = true; |             defObj.isPromoted = true; | ||||||
|         } |         } | ||||||
|         else if (['text', 'number', 'boolean', 'date', 'datetime', 'url'].includes(token)) { |         else if (['text', 'number', 'boolean', 'date', 'datetime', 'time', 'url'].includes(token)) { | ||||||
|             defObj.labelType = token; |             defObj.labelType = token; | ||||||
|         } |         } | ||||||
|         else if (['single', 'multi'].includes(token)) { |         else if (['single', 'multi'].includes(token)) { | ||||||
|   | |||||||
| @@ -125,6 +125,7 @@ const TPL = ` | |||||||
|                   <option value="boolean">${t('attribute_detail.boolean')}</option> |                   <option value="boolean">${t('attribute_detail.boolean')}</option> | ||||||
|                   <option value="date">${t('attribute_detail.date')}</option> |                   <option value="date">${t('attribute_detail.date')}</option> | ||||||
|                   <option value="datetime">${t('attribute_detail.date_time')}</option> |                   <option value="datetime">${t('attribute_detail.date_time')}</option> | ||||||
|  |                   <option value="time">${t('attribute_detail.time')}</option> | ||||||
|                   <option value="url">${t('attribute_detail.url')}</option> |                   <option value="url">${t('attribute_detail.url')}</option> | ||||||
|                 </select> |                 </select> | ||||||
|             </td> |             </td> | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ import BookmarkFolderWidget from "./buttons/bookmark_folder.js"; | |||||||
| import froca from "../services/froca.js"; | import froca from "../services/froca.js"; | ||||||
|  |  | ||||||
| export default class BookmarkButtons extends FlexContainer { | export default class BookmarkButtons extends FlexContainer { | ||||||
|     constructor() { |     constructor(isHorizontalLayout) { | ||||||
|         super("column"); |         super(isHorizontalLayout ? "row" : "column"); | ||||||
|  |  | ||||||
|         this.contentSized(); |         this.contentSized(); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ export default class LauncherWidget extends BasicWidget { | |||||||
|          |          | ||||||
|                 return new SpacerWidget(baseSize, growthFactor); |                 return new SpacerWidget(baseSize, growthFactor); | ||||||
|             case "bookmarks": |             case "bookmarks": | ||||||
|                 return new BookmarkButtons(); |                 return new BookmarkButtons(this.isHorizontalLayout); | ||||||
|             case "protectedSession": |             case "protectedSession": | ||||||
|                 return new ProtectedSessionStatusWidget(); |                 return new ProtectedSessionStatusWidget(); | ||||||
|             case "syncStatus": |             case "syncStatus": | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import libraryLoader from "../services/library_loader.js"; | |||||||
| import NoteContextAwareWidget from "./note_context_aware_widget.js"; | import NoteContextAwareWidget from "./note_context_aware_widget.js"; | ||||||
| import server from "../services/server.js"; | import server from "../services/server.js"; | ||||||
| import utils from "../services/utils.js"; | import utils from "../services/utils.js"; | ||||||
|  | import { loadElkIfNeeded } from "../services/mermaid.js"; | ||||||
|  |  | ||||||
| const TPL = `<div class="mermaid-widget"> | const TPL = `<div class="mermaid-widget"> | ||||||
|     <style> |     <style> | ||||||
| @@ -57,10 +58,10 @@ export default class MermaidWidget extends NoteContextAwareWidget { | |||||||
|         this.$errorContainer.hide(); |         this.$errorContainer.hide(); | ||||||
|  |  | ||||||
|         await libraryLoader.requireLibrary(libraryLoader.MERMAID); |         await libraryLoader.requireLibrary(libraryLoader.MERMAID); | ||||||
|  |          | ||||||
|         const documentStyle = window.getComputedStyle(document.documentElement); |         const documentStyle = window.getComputedStyle(document.documentElement); | ||||||
|         const mermaidTheme = documentStyle.getPropertyValue('--mermaid-theme'); |         const mermaidTheme = documentStyle.getPropertyValue('--mermaid-theme');         | ||||||
|  |          | ||||||
|         mermaid.mermaidAPI.initialize({ |         mermaid.mermaidAPI.initialize({ | ||||||
|             startOnLoad: false, |             startOnLoad: false, | ||||||
|             theme: mermaidTheme.trim(), |             theme: mermaidTheme.trim(), | ||||||
| @@ -111,6 +112,7 @@ export default class MermaidWidget extends NoteContextAwareWidget { | |||||||
|                 zoomOnClick: false |                 zoomOnClick: false | ||||||
|             }); |             }); | ||||||
|         } catch (e) { |         } catch (e) { | ||||||
|  |             console.warn(e); | ||||||
|             this.$errorMessage.text(e.message); |             this.$errorMessage.text(e.message); | ||||||
|             this.$errorContainer.show(); |             this.$errorContainer.show(); | ||||||
|         } |         } | ||||||
| @@ -122,6 +124,7 @@ export default class MermaidWidget extends NoteContextAwareWidget { | |||||||
|         const blob = await this.note.getBlob(); |         const blob = await this.note.getBlob(); | ||||||
|         const content = blob.content || ""; |         const content = blob.content || ""; | ||||||
|  |  | ||||||
|  |         await loadElkIfNeeded(content); | ||||||
|         const {svg} = await mermaid.mermaidAPI.render(`mermaid-graph-${idCounter}`, content); |         const {svg} = await mermaid.mermaidAPI.render(`mermaid-graph-${idCounter}`, content); | ||||||
|         return svg; |         return svg; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -225,6 +225,9 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { | |||||||
|             else if (definition.labelType === 'datetime') { |             else if (definition.labelType === 'datetime') { | ||||||
|                 $input.prop('type', 'datetime-local') |                 $input.prop('type', 'datetime-local') | ||||||
|             } |             } | ||||||
|  |             else if (definition.labelType === 'time') { | ||||||
|  |                 $input.prop('type', 'time') | ||||||
|  |             } | ||||||
|             else if (definition.labelType === 'url') { |             else if (definition.labelType === 'url') { | ||||||
|                 $input.prop("placeholder", t("promoted_attributes.url_placeholder")); |                 $input.prop("placeholder", t("promoted_attributes.url_placeholder")); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,45 +1,53 @@ | |||||||
| import NoteContextAwareWidget from "../../note_context_aware_widget.js"; |  | ||||||
| import server from "../../../services/server.js"; | import server from "../../../services/server.js"; | ||||||
| import { t } from "../../../services/i18n.js"; | import { t } from "../../../services/i18n.js"; | ||||||
|  | import AbstractCodeTypeWidget from "../abstract_code_type_widget.js"; | ||||||
|  |  | ||||||
| const TPL = `<div style="height: 100%; display: flex; flex-direction: column;"> | const TPL = `<div style="height: 100%; display: flex; flex-direction: column;"> | ||||||
|     <style> |     <style> | ||||||
|         .backend-log-textarea { |         .backend-log-editor { | ||||||
|             flex-grow: 1;  |             flex-grow: 1;  | ||||||
|             width: 100%; |             width: 100%; | ||||||
|             border: none; |             border: none; | ||||||
|  |             resize: none; | ||||||
|         }    |         }    | ||||||
|     </style> |     </style> | ||||||
|  |  | ||||||
|     <textarea class="backend-log-textarea" readonly="readonly"></textarea> |     <pre class="backend-log-editor"></pre> | ||||||
|      |      | ||||||
|     <div style="display: flex; justify-content: space-around; margin-top: 10px;"> |     <div style="display: flex; justify-content: space-around; margin-top: 10px;"> | ||||||
|         <button class="refresh-backend-log-button btn btn-primary">${t("backend_log.refresh")}</button> |         <button class="refresh-backend-log-button btn btn-primary">${t("backend_log.refresh")}</button> | ||||||
|     </div> |     </div> | ||||||
| </div>`; | </div>`; | ||||||
|  |  | ||||||
| export default class BackendLogWidget extends NoteContextAwareWidget { | export default class BackendLogWidget extends AbstractCodeTypeWidget { | ||||||
|     doRender() { |     doRender() { | ||||||
|  |         super.doRender(); | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$backendLogTextArea = this.$widget.find(".backend-log-textarea"); |         this.$editor = this.$widget.find(".backend-log-editor"); | ||||||
|  |  | ||||||
|         this.$refreshBackendLog = this.$widget.find(".refresh-backend-log-button"); |         this.$refreshBackendLog = this.$widget.find(".refresh-backend-log-button"); | ||||||
|  |  | ||||||
|         this.$refreshBackendLog.on('click', () => this.load()); |         this.$refreshBackendLog.on('click', () => this.load()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     scrollToBottom() { |  | ||||||
|         this.$backendLogTextArea.scrollTop(this.$backendLogTextArea[0].scrollHeight); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async refresh() { |     async refresh() { | ||||||
|         await this.load(); |         await this.load(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     getExtraOpts() { | ||||||
|  |         return { | ||||||
|  |             lineWrapping: false, | ||||||
|  |             readOnly: true | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     async load() { |     async load() { | ||||||
|         const backendLog = await server.get('backend-log'); |         const content = await server.get('backend-log'); | ||||||
|  |         await this.initialized; | ||||||
|  |  | ||||||
|         this.$backendLogTextArea.text(backendLog); |         this._update({ | ||||||
|  |             mime: "text/plain"             | ||||||
|         this.scrollToBottom(); |         }, content); | ||||||
|  |         this.show(); | ||||||
|  |         this.scrollToEnd(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -185,8 +185,8 @@ | |||||||
|  |  | ||||||
|         --root-background: var(--left-pane-background-color); |         --root-background: var(--left-pane-background-color); | ||||||
|  |  | ||||||
|         --gutter-color: #e7e7e7; |         --gutter-color: transparent; | ||||||
|         --gutter-hover-color: #bfbfbf; |         --gutter-hover-color: #5e5e5e; | ||||||
|      |      | ||||||
|         --active-tab-background-color: #666; |         --active-tab-background-color: #666; | ||||||
|         --active-tab-hover-background-color: #737373; |         --active-tab-hover-background-color: #737373; | ||||||
| @@ -256,7 +256,11 @@ | |||||||
|     padding-bottom: var(--launcher-pane-button-gap); |     padding-bottom: var(--launcher-pane-button-gap); | ||||||
| } | } | ||||||
|  |  | ||||||
| #launcher-pane.vertical .launcher-button { | #launcher-pane.horizontal { | ||||||
|  |     height: var(--launcher-pane-size) !important; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #launcher-pane .launcher-button { | ||||||
|     width: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; |     width: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; | ||||||
|     height: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; |     height: calc(var(--launcher-pane-size) - (var(--launcher-pane-button-margin) * 2)) !important; | ||||||
|     margin: var(--launcher-pane-button-gap) var(--launcher-pane-button-margin); |     margin: var(--launcher-pane-button-gap) var(--launcher-pane-button-margin); | ||||||
| @@ -268,14 +272,14 @@ | |||||||
|     cursor: default; |     cursor: default; | ||||||
| } | } | ||||||
|  |  | ||||||
| #launcher-pane.vertical .launcher-button:active, | #launcher-pane .launcher-button:active, | ||||||
| #launcher-pane.vertical .launcher-button.show { | #launcher-pane .launcher-button.show { | ||||||
|     transform: scale(0.9); |     transform: scale(0.9); | ||||||
|     transition: transform 50ms linear; |     transition: transform 50ms linear; | ||||||
| } | } | ||||||
|  |  | ||||||
| #launcher-pane.vertical .launcher-button:hover, | #launcher-pane .launcher-button:hover, | ||||||
| #launcher-pane.vertical .launcher-button.right-dropdown-button.show { | #launcher-pane .launcher-button.right-dropdown-button.show { | ||||||
|     background: var(--launcher-pane-button-hover-background); |     background: var(--launcher-pane-button-hover-background); | ||||||
|     color: var(--launcher-pane-button-hover-color); |     color: var(--launcher-pane-button-hover-color); | ||||||
|     box-shadow: var(--launcher-pane-button-hover-shadow); |     box-shadow: var(--launcher-pane-button-hover-shadow); | ||||||
|   | |||||||
| @@ -15,7 +15,13 @@ | |||||||
|       "message": "发生了严重错误,导致客户端应用程序无法启动:\n\n{{message}}\n\n这很可能是由于脚本以意外的方式失败引起的。请尝试以安全模式启动应用程序并解决问题。" |       "message": "发生了严重错误,导致客户端应用程序无法启动:\n\n{{message}}\n\n这很可能是由于脚本以意外的方式失败引起的。请尝试以安全模式启动应用程序并解决问题。" | ||||||
|     }, |     }, | ||||||
|     "widget-error": { |     "widget-error": { | ||||||
|       "title": "小部件初始化失败" |       "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": { | ||||||
| @@ -45,7 +51,11 @@ | |||||||
|     "chosen_actions": "选择的操作", |     "chosen_actions": "选择的操作", | ||||||
|     "execute_bulk_actions": "执行批量操作", |     "execute_bulk_actions": "执行批量操作", | ||||||
|     "bulk_actions_executed": "批量操作已成功执行。", |     "bulk_actions_executed": "批量操作已成功执行。", | ||||||
|     "none_yet": "暂无操作 ... 通过点击上方的可用操作添加一个操作。" |     "none_yet": "暂无操作 ... 通过点击上方的可用操作添加一个操作。", | ||||||
|  |     "labels": "标签", | ||||||
|  |     "relations": "关联关系", | ||||||
|  |     "notes": "笔记", | ||||||
|  |     "other": "其它" | ||||||
|   }, |   }, | ||||||
|   "clone_to": { |   "clone_to": { | ||||||
|     "clone_notes_to": "克隆笔记到...", |     "clone_notes_to": "克隆笔记到...", | ||||||
| @@ -164,7 +174,8 @@ | |||||||
|     "textImportedAsText": "如果元数据不明确,将HTML、Markdown和TXT导入为文本笔记", |     "textImportedAsText": "如果元数据不明确,将HTML、Markdown和TXT导入为文本笔记", | ||||||
|     "codeImportedAsCode": "如果元数据不明确,将识别的代码文件(例如<code>.json</code>)导入为代码笔记", |     "codeImportedAsCode": "如果元数据不明确,将识别的代码文件(例如<code>.json</code>)导入为代码笔记", | ||||||
|     "replaceUnderscoresWithSpaces": "在导入的笔记名称中将下划线替换为空格", |     "replaceUnderscoresWithSpaces": "在导入的笔记名称中将下划线替换为空格", | ||||||
|     "import": "导入" |     "import": "导入", | ||||||
|  |     "failed": "导入失败: {{message}}." | ||||||
|   }, |   }, | ||||||
|   "include_note": { |   "include_note": { | ||||||
|     "dialog_title": "包含笔记", |     "dialog_title": "包含笔记", | ||||||
| @@ -304,6 +315,7 @@ | |||||||
|     "boolean": "布尔值", |     "boolean": "布尔值", | ||||||
|     "date": "日期", |     "date": "日期", | ||||||
|     "date_time": "日期和时间", |     "date_time": "日期和时间", | ||||||
|  |     "time": "时间", | ||||||
|     "url": "网址", |     "url": "网址", | ||||||
|     "precision_title": "值设置界面中浮点数后的位数。", |     "precision_title": "值设置界面中浮点数后的位数。", | ||||||
|     "precision": "精度", |     "precision": "精度", | ||||||
| @@ -630,7 +642,10 @@ | |||||||
|     "export_note": "导出笔记", |     "export_note": "导出笔记", | ||||||
|     "delete_note": "删除笔记", |     "delete_note": "删除笔记", | ||||||
|     "print_note": "打印笔记", |     "print_note": "打印笔记", | ||||||
|     "save_revision": "保存笔记历史" |     "save_revision": "保存笔记历史", | ||||||
|  |     "convert_into_attachment_failed": "笔记 '{{title}}' 转换失败。", | ||||||
|  |     "convert_into_attachment_successful": "笔记 '{{title}}' 已成功转换为附件。", | ||||||
|  |     "convert_into_attachment_prompt": "确定要将笔记 '{{title}}' 转换为父笔记的附件吗?" | ||||||
|   }, |   }, | ||||||
|   "onclick_button": { |   "onclick_button": { | ||||||
|     "no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序" |     "no_click_handler": "按钮组件'{{componentId}}'没有定义点击处理程序" | ||||||
| @@ -885,7 +900,8 @@ | |||||||
|     "label_rock_or_pop": "只需一个标签存在即可", |     "label_rock_or_pop": "只需一个标签存在即可", | ||||||
|     "label_year_comparison": "数字比较(也包括>,>=,<)。", |     "label_year_comparison": "数字比较(也包括>,>=,<)。", | ||||||
|     "label_date_created": "上个月创建的笔记", |     "label_date_created": "上个月创建的笔记", | ||||||
|     "error": "搜索错误:{{error}}" |     "error": "搜索错误:{{error}}", | ||||||
|  |     "search_prefix": "搜索:" | ||||||
|   }, |   }, | ||||||
|   "attachment_detail": { |   "attachment_detail": { | ||||||
|     "open_help_page": "打开附件帮助页面", |     "open_help_page": "打开附件帮助页面", | ||||||
| @@ -919,7 +935,15 @@ | |||||||
|   }, |   }, | ||||||
|   "protected_session": { |   "protected_session": { | ||||||
|     "enter_password_instruction": "显示受保护的笔记需要输入您的密码:", |     "enter_password_instruction": "显示受保护的笔记需要输入您的密码:", | ||||||
|     "start_session_button": "开始受保护的会话" |     "start_session_button": "开始受保护的会话", | ||||||
|  |     "started": "受保护的会话已启动。", | ||||||
|  |     "wrong_password": "密码错误。", | ||||||
|  |     "protecting-finished-successfully": "保护操作已成功完成。", | ||||||
|  |     "unprotecting-finished-successfully": "解除保护操作已成功完成。", | ||||||
|  |     "protecting-in-progress": "保护进行中:{{count}}", | ||||||
|  |     "unprotecting-in-progress-count": "解除保护进行中:{{count}}", | ||||||
|  |     "protecting-title": "保护状态", | ||||||
|  |     "unprotecting-title": "解除保护状态" | ||||||
|   }, |   }, | ||||||
|   "relation_map": { |   "relation_map": { | ||||||
|     "open_in_new_tab": "在新标签页中打开", |     "open_in_new_tab": "在新标签页中打开", | ||||||
| @@ -990,7 +1014,9 @@ | |||||||
|     "fill_entity_changes_button": "填充实体变更记录", |     "fill_entity_changes_button": "填充实体变更记录", | ||||||
|     "full_sync_triggered": "全量同步已触发", |     "full_sync_triggered": "全量同步已触发", | ||||||
|     "filling_entity_changes": "正在填充实体变更行...", |     "filling_entity_changes": "正在填充实体变更行...", | ||||||
|     "sync_rows_filled_successfully": "同步行填充成功" |     "sync_rows_filled_successfully": "同步行填充成功", | ||||||
|  |     "finished-successfully": "同步已完成。", | ||||||
|  |     "failed": "同步失败:{{message}}" | ||||||
|   }, |   }, | ||||||
|   "vacuum_database": { |   "vacuum_database": { | ||||||
|     "title": "数据库清理", |     "title": "数据库清理", | ||||||
| @@ -1036,8 +1062,13 @@ | |||||||
|     "theme_label": "主题", |     "theme_label": "主题", | ||||||
|     "override_theme_fonts_label": "覆盖主题字体", |     "override_theme_fonts_label": "覆盖主题字体", | ||||||
|     "light_theme": "浅色", |     "light_theme": "浅色", | ||||||
|     "dark_theme": "深色" |     "dark_theme": "深色", | ||||||
|   }, |     "layout": "布局", | ||||||
|  |     "layout-vertical-title": "垂直", | ||||||
|  |     "layout-horizontal-title": "水平", | ||||||
|  |     "layout-vertical-description": "启动栏位于左侧(默认)", | ||||||
|  |     "layout-horizontal-description": "启动栏位于标签栏下方,标签栏现在是全宽的。" | ||||||
|  |  }, | ||||||
|   "zoom_factor": { |   "zoom_factor": { | ||||||
|     "title": "缩放系数(仅桌面客户端有效)", |     "title": "缩放系数(仅桌面客户端有效)", | ||||||
|     "description": "缩放也可以通过 CTRL+- 和 CTRL+= 快捷键进行控制。" |     "description": "缩放也可以通过 CTRL+- 和 CTRL+= 快捷键进行控制。" | ||||||
| @@ -1162,6 +1193,8 @@ | |||||||
|     "backup_now": "立即备份", |     "backup_now": "立即备份", | ||||||
|     "backup_database_now": "立即备份数据库", |     "backup_database_now": "立即备份数据库", | ||||||
|     "existing_backups": "现有备份", |     "existing_backups": "现有备份", | ||||||
|  |     "date-and-time": "日期和时间", | ||||||
|  |     "path": "路径", | ||||||
|     "database_backed_up_to": "数据库已备份到", |     "database_backed_up_to": "数据库已备份到", | ||||||
|     "no_backup_yet": "尚无备份" |     "no_backup_yet": "尚无备份" | ||||||
|   }, |   }, | ||||||
| @@ -1309,7 +1342,9 @@ | |||||||
|     "duplicate-subtree": "复制子树", |     "duplicate-subtree": "复制子树", | ||||||
|     "export": "导出", |     "export": "导出", | ||||||
|     "import-into-note": "导入到笔记", |     "import-into-note": "导入到笔记", | ||||||
|     "apply-bulk-actions": "应用批量操作" |     "apply-bulk-actions": "应用批量操作", | ||||||
|  |     "converted-to-attachments": "{{count}} 个笔记已被转换为附件。", | ||||||
|  |     "convert-to-attachment-confirm": "确定要将选中的笔记转换为其父笔记的附件吗?" | ||||||
|   }, |   }, | ||||||
|   "shared_info": { |   "shared_info": { | ||||||
|     "shared_publicly": "此笔记已公开分享在", |     "shared_publicly": "此笔记已公开分享在", | ||||||
| @@ -1332,7 +1367,8 @@ | |||||||
|     "image": "图片", |     "image": "图片", | ||||||
|     "launcher": "启动器", |     "launcher": "启动器", | ||||||
|     "doc": "文档", |     "doc": "文档", | ||||||
|     "widget": "小部件" |     "widget": "小部件", | ||||||
|  |     "confirm-change": "当笔记内容不为空时,不建议更改笔记类型。您仍然要继续吗?" | ||||||
|   }, |   }, | ||||||
|   "protect_note": { |   "protect_note": { | ||||||
|     "toggle-on": "保护笔记", |     "toggle-on": "保护笔记", | ||||||
| @@ -1355,7 +1391,11 @@ | |||||||
|   "open-help-page": "打开帮助页面", |   "open-help-page": "打开帮助页面", | ||||||
|   "find": { |   "find": { | ||||||
|     "case_sensitive": "区分大小写", |     "case_sensitive": "区分大小写", | ||||||
|     "match_words": "匹配单词" |     "match_words": "匹配单词", | ||||||
|  |     "find_placeholder": "在文本中查找...", | ||||||
|  |     "replace_placeholder": "替换为...", | ||||||
|  |     "replace": "替换", | ||||||
|  |     "replace_all": "全部替换" | ||||||
|   }, |   }, | ||||||
|   "highlights_list_2": { |   "highlights_list_2": { | ||||||
|     "title": "高亮列表", |     "title": "高亮列表", | ||||||
| @@ -1378,7 +1418,9 @@ | |||||||
|     "hide-archived-notes": "隐藏已归档笔记", |     "hide-archived-notes": "隐藏已归档笔记", | ||||||
|     "automatically-collapse-notes": "自动折叠笔记", |     "automatically-collapse-notes": "自动折叠笔记", | ||||||
|     "automatically-collapse-notes-title": "笔记在一段时间内未使用将被折叠,以减少树形结构的杂乱。", |     "automatically-collapse-notes-title": "笔记在一段时间内未使用将被折叠,以减少树形结构的杂乱。", | ||||||
|     "save-changes": "保存并应用更改" |     "save-changes": "保存并应用更改", | ||||||
|  |     "auto-collapsing-notes-after-inactivity": "在不活动后自动折叠笔记...", | ||||||
|  |     "saved-search-note-refreshed": "已保存的搜索笔记已刷新。" | ||||||
|   }, |   }, | ||||||
|   "title_bar_buttons": { |   "title_bar_buttons": { | ||||||
|     "window-on-top": "保持此窗口置顶" |     "window-on-top": "保持此窗口置顶" | ||||||
| @@ -1407,8 +1449,11 @@ | |||||||
|     "add_new_tab": "添加新标签页", |     "add_new_tab": "添加新标签页", | ||||||
|     "close": "关闭", |     "close": "关闭", | ||||||
|     "close_other_tabs": "关闭其他标签页", |     "close_other_tabs": "关闭其他标签页", | ||||||
|  |     "close_right_tabs": "关闭右侧标签页", | ||||||
|     "close_all_tabs": "关闭所有标签页", |     "close_all_tabs": "关闭所有标签页", | ||||||
|  |     "reopen_last_tab": "重新打开最后一个关闭的标签页", | ||||||
|     "move_tab_to_new_window": "将此标签页移动到新窗口", |     "move_tab_to_new_window": "将此标签页移动到新窗口", | ||||||
|  |     "copy_tab_to_new_window": "将此标签页复制到新窗口", | ||||||
|     "new_tab": "新标签页" |     "new_tab": "新标签页" | ||||||
|   }, |   }, | ||||||
|   "toc": { |   "toc": { | ||||||
| @@ -1422,5 +1467,101 @@ | |||||||
|   }, |   }, | ||||||
|   "app_context": { |   "app_context": { | ||||||
|     "please_wait_for_save": "请等待几秒钟以完成保存,然后您可以尝试再操作一次。" |     "please_wait_for_save": "请等待几秒钟以完成保存,然后您可以尝试再操作一次。" | ||||||
|  |   }, | ||||||
|  |   "note_create": { | ||||||
|  |     "duplicated": "笔记 \"{{title}}\" 已被复制。" | ||||||
|  |   }, | ||||||
|  |   "image": { | ||||||
|  |     "copied-to-clipboard": "图片的引用已复制到剪贴板,可以粘贴到任何文本笔记中。", | ||||||
|  |     "cannot-copy": "无法将图片引用复制到剪贴板。" | ||||||
|  |   }, | ||||||
|  |   "clipboard": { | ||||||
|  |     "cut": "笔记已剪切到剪贴板。", | ||||||
|  |     "copied": "笔记已复制到剪贴板。" | ||||||
|  |   }, | ||||||
|  |   "entrypoints": { | ||||||
|  |     "note-revision-created": "笔记修订已创建。", | ||||||
|  |     "note-executed": "笔记已执行。", | ||||||
|  |     "sql-error": "执行 SQL 查询时发生错误:{{message}}" | ||||||
|  |   }, | ||||||
|  |   "branches": { | ||||||
|  |     "cannot-move-notes-here": "无法将笔记移动到这里。", | ||||||
|  |     "delete-status": "删除状态", | ||||||
|  |     "delete-notes-in-progress": "正在删除笔记:{{count}}", | ||||||
|  |     "delete-finished-successfully": "删除成功完成。", | ||||||
|  |     "undeleting-notes-in-progress": "正在恢复删除的笔记:{{count}}", | ||||||
|  |     "undeleting-notes-finished-successfully": "恢复删除的笔记已成功完成。" | ||||||
|  |   }, | ||||||
|  |   "frontend_script_api": { | ||||||
|  |     "async_warning": "您正在将一个异步函数传递给 `api.runOnBackend()`,这可能无法按预期工作。\\n要么使该函数同步(通过移除 `async` 关键字),要么使用 `api.runAsyncOnBackendWithManualTransactionHandling()`。", | ||||||
|  |     "sync_warning": "您正在将一个同步函数传递给 `api.runAsyncOnBackendWithManualTransactionHandling()`,\\n而您可能应该使用 `api.runOnBackend()`。" | ||||||
|  |   }, | ||||||
|  |   "ws": { | ||||||
|  |     "sync-check-failed": "同步检查失败!", | ||||||
|  |     "consistency-checks-failed": "一致性检查失败!请查看日志了解详细信息。", | ||||||
|  |     "encountered-error": "遇到错误 \"{{message}}\",请查看控制台。" | ||||||
|  |   }, | ||||||
|  |   "hoisted_note": { | ||||||
|  |     "confirm_unhoisting": "请求的笔记 '{{requestedNote}}' 位于提升的笔记 '{{hoistedNote}}' 的子树之外,您必须取消提升才能访问该笔记。是否继续取消提升?" | ||||||
|  |   }, | ||||||
|  |   "launcher_context_menu": { | ||||||
|  |     "reset_launcher_confirm": "您确定要重置 \"{{title}}\" 吗?此笔记(及其子项)中的所有数据/设置将丢失,且启动器将恢复到其原始位置。", | ||||||
|  |     "add-note-launcher": "添加笔记启动器", | ||||||
|  |     "add-script-launcher": "添加脚本启动器", | ||||||
|  |     "add-custom-widget": "添加自定义小部件", | ||||||
|  |     "add-spacer": "添加间隔", | ||||||
|  |     "delete": "删除", | ||||||
|  |     "reset": "重置", | ||||||
|  |     "move-to-visible-launchers": "移动到可见启动器", | ||||||
|  |     "move-to-available-launchers": "移动到可用启动器", | ||||||
|  |     "duplicate-launcher": "复制启动器" | ||||||
|  |   }, | ||||||
|  |   "editable-text": { | ||||||
|  |     "auto-detect-language": "自动检测" | ||||||
|  |   }, | ||||||
|  |   "highlighting": { | ||||||
|  |     "title": "文本笔记的代码语法高亮", | ||||||
|  |     "description": "控制文本笔记中代码块的语法高亮,代码笔记不会受到影响。", | ||||||
|  |     "color-scheme": "颜色方案" | ||||||
|  |   }, | ||||||
|  |   "code_block": { | ||||||
|  |     "word_wrapping": "自动换行" | ||||||
|  |   }, | ||||||
|  |   "classic_editor_toolbar": { | ||||||
|  |     "title": "格式化" | ||||||
|  |   }, | ||||||
|  |   "editor": { | ||||||
|  |     "title": "编辑器" | ||||||
|  |   }, | ||||||
|  |   "editing": { | ||||||
|  |     "editor_type": { | ||||||
|  |       "label": "格式化工具栏", | ||||||
|  |       "floating": { | ||||||
|  |         "title": "浮动", | ||||||
|  |         "description": "编辑工具出现在光标附近;" | ||||||
|  |       }, | ||||||
|  |       "fixed": { | ||||||
|  |         "title": "固定", | ||||||
|  |         "description": "编辑工具出现在 \"格式化\" 功能区标签中。" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "electron_context_menu": { | ||||||
|  |     "add-term-to-dictionary": "将 \"{{term}}\" 添加到字典", | ||||||
|  |     "cut": "剪切", | ||||||
|  |     "copy": "复制", | ||||||
|  |     "copy-link": "复制链接", | ||||||
|  |     "paste": "粘贴", | ||||||
|  |     "paste-as-plain-text": "以纯文本粘贴", | ||||||
|  |     "search_online": "用 {{searchEngine}} 搜索 \"{{term}}\"" | ||||||
|  |   }, | ||||||
|  |   "image_context_menu": { | ||||||
|  |     "copy_reference_to_clipboard": "复制引用到剪贴板", | ||||||
|  |     "copy_image_to_clipboard": "复制图片到剪贴板" | ||||||
|  |   }, | ||||||
|  |   "link_context_menu": { | ||||||
|  |     "open_note_in_new_tab": "在新标签页中打开笔记", | ||||||
|  |     "open_note_in_new_split": "在新分屏中打开笔记", | ||||||
|  |     "open_note_in_new_window": "在新窗口中打开笔记" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -310,6 +310,7 @@ | |||||||
|     "boolean": "Boolescher Wert", |     "boolean": "Boolescher Wert", | ||||||
|     "date": "Datum", |     "date": "Datum", | ||||||
|     "date_time": "Datum und Uhrzeit", |     "date_time": "Datum und Uhrzeit", | ||||||
|  |     "time": "Uhrzeit", | ||||||
|     "url": "URL", |     "url": "URL", | ||||||
|     "precision_title": "Wie viele Nachkommastellen im Wert-Einstellungs-Interface verfügbar sein sollen.", |     "precision_title": "Wie viele Nachkommastellen im Wert-Einstellungs-Interface verfügbar sein sollen.", | ||||||
|     "precision": "Präzision", |     "precision": "Präzision", | ||||||
|   | |||||||
| @@ -315,6 +315,7 @@ | |||||||
|     "boolean": "Boolean", |     "boolean": "Boolean", | ||||||
|     "date": "Date", |     "date": "Date", | ||||||
|     "date_time": "Date & Time", |     "date_time": "Date & Time", | ||||||
|  |     "time": "Time", | ||||||
|     "url": "URL", |     "url": "URL", | ||||||
|     "precision_title": "What number of digits after floating point should be available in the value setting interface.", |     "precision_title": "What number of digits after floating point should be available in the value setting interface.", | ||||||
|     "precision": "Precision", |     "precision": "Precision", | ||||||
| @@ -1554,5 +1555,14 @@ | |||||||
|     "paste": "Paste", |     "paste": "Paste", | ||||||
|     "paste-as-plain-text": "Paste as plain text", |     "paste-as-plain-text": "Paste as plain text", | ||||||
|     "search_online": "Search for \"{{term}}\" with {{searchEngine}}" |     "search_online": "Search for \"{{term}}\" with {{searchEngine}}" | ||||||
|  |   }, | ||||||
|  |   "image_context_menu": { | ||||||
|  |     "copy_reference_to_clipboard": "Copy reference to clipboard", | ||||||
|  |     "copy_image_to_clipboard": "Copy image to clipboard" | ||||||
|  |   }, | ||||||
|  |   "link_context_menu": { | ||||||
|  |     "open_note_in_new_tab": "Open note in a new tab", | ||||||
|  |     "open_note_in_new_split": "Open note in a new split", | ||||||
|  |     "open_note_in_new_window": "Open note in a new window" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -51,7 +51,11 @@ | |||||||
|     "chosen_actions": "Acciones elegidas", |     "chosen_actions": "Acciones elegidas", | ||||||
|     "execute_bulk_actions": "Ejecutar acciones en bloque", |     "execute_bulk_actions": "Ejecutar acciones en bloque", | ||||||
|     "bulk_actions_executed": "Las acciones en bloque se han ejecutado con éxito.", |     "bulk_actions_executed": "Las acciones en bloque se han ejecutado con éxito.", | ||||||
|     "none_yet": "Ninguna todavía... agrega una acción haciendo clic en una de las disponibles arriba." |     "none_yet": "Ninguna todavía... agregue una acción haciendo clic en una de las disponibles arriba.", | ||||||
|  |     "labels": "Etiquetas", | ||||||
|  |     "relations": "Relaciones", | ||||||
|  |     "notes": "Notas", | ||||||
|  |     "other": "Otro" | ||||||
|   }, |   }, | ||||||
|   "clone_to": { |   "clone_to": { | ||||||
|     "clone_notes_to": "Clonar notas a...", |     "clone_notes_to": "Clonar notas a...", | ||||||
| @@ -311,6 +315,7 @@ | |||||||
|     "boolean": "Booleano", |     "boolean": "Booleano", | ||||||
|     "date": "Fecha", |     "date": "Fecha", | ||||||
|     "date_time": "Fecha y hora", |     "date_time": "Fecha y hora", | ||||||
|  |     "time": "Hora", | ||||||
|     "url": "URL", |     "url": "URL", | ||||||
|     "precision_title": "Cantidad de dígitos después del punto flotante que deben estar disponibles en la interfaz de configuración del valor.", |     "precision_title": "Cantidad de dígitos después del punto flotante que deben estar disponibles en la interfaz de configuración del valor.", | ||||||
|     "precision": "Precisión", |     "precision": "Precisión", | ||||||
| @@ -1057,7 +1062,12 @@ | |||||||
|     "theme_label": "Tema", |     "theme_label": "Tema", | ||||||
|     "override_theme_fonts_label": "Sobreescribir fuentes de tema", |     "override_theme_fonts_label": "Sobreescribir fuentes de tema", | ||||||
|     "light_theme": "Claro", |     "light_theme": "Claro", | ||||||
|     "dark_theme": "Oscuro" |     "dark_theme": "Oscuro", | ||||||
|  |     "layout": "Disposición", | ||||||
|  |     "layout-vertical-title": "Vertical", | ||||||
|  |     "layout-horizontal-title": "Horizontal", | ||||||
|  |     "layout-vertical-description": "la barra del lanzador está en la izquierda (por defecto)", | ||||||
|  |     "layout-horizontal-description": "la barra de lanzamiento está debajo de la barra de pestañas, la barra de pestañas ahora tiene ancho completo." | ||||||
|   }, |   }, | ||||||
|   "zoom_factor": { |   "zoom_factor": { | ||||||
|     "title": "Factor de zoom (solo versión de escritorio)", |     "title": "Factor de zoom (solo versión de escritorio)", | ||||||
| @@ -1183,6 +1193,8 @@ | |||||||
|     "backup_now": "Realizar copia de seguridad ahora", |     "backup_now": "Realizar copia de seguridad ahora", | ||||||
|     "backup_database_now": "Realizar copia de seguridad de la base de datos ahora", |     "backup_database_now": "Realizar copia de seguridad de la base de datos ahora", | ||||||
|     "existing_backups": "Copias de seguridad existentes", |     "existing_backups": "Copias de seguridad existentes", | ||||||
|  |     "date-and-time": "Fecha y hora", | ||||||
|  |     "path": "Ruta", | ||||||
|     "database_backed_up_to": "Se ha realizado una copia de seguridad de la base de datos en", |     "database_backed_up_to": "Se ha realizado una copia de seguridad de la base de datos en", | ||||||
|     "no_backup_yet": "no hay copia de seguridad todavía" |     "no_backup_yet": "no hay copia de seguridad todavía" | ||||||
|   }, |   }, | ||||||
| @@ -1439,7 +1451,9 @@ | |||||||
|     "close_other_tabs": "Cerrar otras pestañas", |     "close_other_tabs": "Cerrar otras pestañas", | ||||||
|     "close_right_tabs": "Cerrar pestañas a la derecha", |     "close_right_tabs": "Cerrar pestañas a la derecha", | ||||||
|     "close_all_tabs": "Cerras todas las pestañas", |     "close_all_tabs": "Cerras todas las pestañas", | ||||||
|  |     "reopen_last_tab": "Reabrir última pestaña cerrada", | ||||||
|     "move_tab_to_new_window": "Mover esta pestaña a una nueva ventana", |     "move_tab_to_new_window": "Mover esta pestaña a una nueva ventana", | ||||||
|  |     "copy_tab_to_new_window": "Copiar esta pestaña a una ventana nueva", | ||||||
|     "new_tab": "Nueva pestaña" |     "new_tab": "Nueva pestaña" | ||||||
|   }, |   }, | ||||||
|   "toc": { |   "toc": { | ||||||
| @@ -1531,5 +1545,14 @@ | |||||||
|         "description": "las herramientas de edición aparecen en la pestaña de la cinta \"Formato\")." |         "description": "las herramientas de edición aparecen en la pestaña de la cinta \"Formato\")." | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |   }, | ||||||
|  |   "electron_context_menu": { | ||||||
|  |     "add-term-to-dictionary": "Agregar \"{{term}}\" al diccionario.", | ||||||
|  |     "cut": "Cortar", | ||||||
|  |     "copy": "Copiar", | ||||||
|  |     "copy-link": "Copiar enlace", | ||||||
|  |     "paste": "Pegar", | ||||||
|  |     "paste-as-plain-text": "Pegar como texto plano", | ||||||
|  |     "search_online": "Buscar \"{{term}}\" con {{searchEngine}}" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -311,6 +311,7 @@ | |||||||
|     "boolean": "Booléen", |     "boolean": "Booléen", | ||||||
|     "date": "Date", |     "date": "Date", | ||||||
|     "date_time": "Date et heure", |     "date_time": "Date et heure", | ||||||
|  |     "time": "Heure", | ||||||
|     "url": "URL", |     "url": "URL", | ||||||
|     "precision_title": "Nombre de chiffres après la virgule devant être disponible dans l'interface définissant la valeur.", |     "precision_title": "Nombre de chiffres après la virgule devant être disponible dans l'interface définissant la valeur.", | ||||||
|     "precision": "Précision", |     "precision": "Précision", | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								src/public/translations/pt_br/translation.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/public/translations/pt_br/translation.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | {} | ||||||
| @@ -127,6 +127,7 @@ | |||||||
|     "custom_resource_provider": "a se vedea <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Custom request handler</a>", |     "custom_resource_provider": "a se vedea <a href=\"javascript:\" data-help-page=\"custom-request-handler.html\">Custom request handler</a>", | ||||||
|     "date": "Dată", |     "date": "Dată", | ||||||
|     "date_time": "Dată și timp", |     "date_time": "Dată și timp", | ||||||
|  |     "time": "Timp", | ||||||
|     "delete": "Șterge", |     "delete": "Șterge", | ||||||
|     "digits": "număr de zecimale", |     "digits": "număr de zecimale", | ||||||
|     "disable_inclusion": "script-urile cu această etichetă nu vor fi incluse în execuția scriptului părinte.", |     "disable_inclusion": "script-urile cu această etichetă nu vor fi incluse în execuția scriptului părinte.", | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								src/public/translations/tw/translation.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/public/translations/tw/translation.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | {} | ||||||
| @@ -103,7 +103,8 @@ const HIDDEN_SUBTREE_DEFINITION: Item = { | |||||||
|             type: 'contentWidget', |             type: 'contentWidget', | ||||||
|             icon: 'bx-terminal', |             icon: 'bx-terminal', | ||||||
|             attributes: [ |             attributes: [ | ||||||
|                 { type: 'label', name: 'keepCurrentHoisting' } |                 { type: 'label', name: 'keepCurrentHoisting' }, | ||||||
|  |                 { type: 'label', name: 'fullContentWidth' } | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ function parse(value: string): DefinitionObject { | |||||||
|         if (token === 'promoted') { |         if (token === 'promoted') { | ||||||
|             defObj.isPromoted = true; |             defObj.isPromoted = true; | ||||||
|         } |         } | ||||||
|         else if (['text', 'number', 'boolean', 'date', 'datetime', 'url'].includes(token)) { |         else if (['text', 'number', 'boolean', 'date', 'datetime', 'time', 'url'].includes(token)) { | ||||||
|             defObj.labelType = token; |             defObj.labelType = token; | ||||||
|         } |         } | ||||||
|         else if (['single', 'multi'].includes(token)) { |         else if (['single', 'multi'].includes(token)) { | ||||||
|   | |||||||
| @@ -27,43 +27,52 @@ class SearchResult { | |||||||
|         this.score = 0; |         this.score = 0; | ||||||
|  |  | ||||||
|         const note = becca.notes[this.noteId]; |         const note = becca.notes[this.noteId]; | ||||||
|  |         const normalizedQuery = fulltextQuery.toLowerCase(); | ||||||
|  |         const normalizedTitle = note.title.toLowerCase(); | ||||||
|  |  | ||||||
|  |         // Note ID exact match, much higher score | ||||||
|         if (note.noteId.toLowerCase() === fulltextQuery) { |         if (note.noteId.toLowerCase() === fulltextQuery) { | ||||||
|             this.score += 100; |             this.score += 1000; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (note.title.toLowerCase() === fulltextQuery) { |         // Title matching scores, make sure to always win | ||||||
|             this.score += 100; // high reward for exact match #3470 |         if (normalizedTitle === normalizedQuery) { | ||||||
|  |             this.score += 2000; // Increased from 1000 to ensure exact matches always win | ||||||
|  |         } | ||||||
|  |         else if (normalizedTitle.startsWith(normalizedQuery)) { | ||||||
|  |             this.score += 500;  // Increased to give more weight to prefix matches | ||||||
|  |         } | ||||||
|  |         else if (normalizedTitle.includes(` ${normalizedQuery} `) ||  | ||||||
|  |                 normalizedTitle.startsWith(`${normalizedQuery} `) ||  | ||||||
|  |                 normalizedTitle.endsWith(` ${normalizedQuery}`)) { | ||||||
|  |             this.score += 300;  // Increased to better distinguish word matches | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // notes with matches on its own note title as opposed to ancestors or descendants |         // Add scores for partial matches with adjusted weights | ||||||
|         this.addScoreForStrings(tokens, note.title, 1.5); |         this.addScoreForStrings(tokens, note.title, 2.0);  // Increased to give more weight to title matches | ||||||
|  |         this.addScoreForStrings(tokens, this.notePathTitle, 0.3); // Reduced to further de-emphasize path matches | ||||||
|         // matches in attributes don't get extra points and thus are implicitly valued less than note path matches |  | ||||||
|  |  | ||||||
|         this.addScoreForStrings(tokens, this.notePathTitle, 1); |  | ||||||
|  |  | ||||||
|         if (note.isInHiddenSubtree()) { |         if (note.isInHiddenSubtree()) { | ||||||
|             this.score = this.score / 2; |             this.score = this.score / 3; // Increased penalty for hidden notes | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     addScoreForStrings(tokens: string[], str: string, factor: number) { |     addScoreForStrings(tokens: string[], str: string, factor: number) { | ||||||
|         const chunks = str.toLowerCase().split(" "); |         const chunks = str.toLowerCase().split(" "); | ||||||
|  |  | ||||||
|         this.score = 0; |         let tokenScore = 0; | ||||||
|  |  | ||||||
|         for (const chunk of chunks) { |         for (const chunk of chunks) { | ||||||
|             for (const token of tokens) { |             for (const token of tokens) { | ||||||
|                 if (chunk === token) { |                 if (chunk === token) { | ||||||
|                     this.score += 4 * token.length * factor; |                     tokenScore += 4 * token.length * factor; | ||||||
|                 } else if (chunk.startsWith(token)) { |                 } else if (chunk.startsWith(token)) { | ||||||
|                     this.score += 2 * token.length * factor; |                     tokenScore += 2 * token.length * factor; | ||||||
|                 } else if (chunk.includes(token)) { |                 } else if (chunk.includes(token)) { | ||||||
|                     this.score += token.length * factor; |                     tokenScore += token.length * factor; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         this.score += tokenScore; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -89,7 +89,8 @@ | |||||||
|         "copy-without-formatting": "不带格式复制选定文本", |         "copy-without-formatting": "不带格式复制选定文本", | ||||||
|         "force-save-revision": "强制创建/保存当前笔记的历史版本", |         "force-save-revision": "强制创建/保存当前笔记的历史版本", | ||||||
|         "show-help": "显示内置帮助/备忘单", |         "show-help": "显示内置帮助/备忘单", | ||||||
|         "toggle-book-properties": "切换书籍属性" |         "toggle-book-properties": "切换书籍属性", | ||||||
|  |     	"toggle-classic-editor-toolbar": "切换具有固定工具栏的编辑器格式化选项卡" | ||||||
|     }, |     }, | ||||||
|     "login": { |     "login": { | ||||||
|         "title": "登录", |         "title": "登录", | ||||||
| @@ -157,5 +158,40 @@ | |||||||
|         "clipped-from": "此笔记最初剪切自 {{- url}}", |         "clipped-from": "此笔记最初剪切自 {{- url}}", | ||||||
|         "child-notes": "子笔记:", |         "child-notes": "子笔记:", | ||||||
|         "no-content": "此笔记没有内容。" |         "no-content": "此笔记没有内容。" | ||||||
|  |     }, | ||||||
|  |     "weekdays": { | ||||||
|  |         "monday": "周一", | ||||||
|  |         "tuesday": "周二", | ||||||
|  |         "wednesday": "周三", | ||||||
|  |         "thursday": "周四", | ||||||
|  |         "friday": "周五", | ||||||
|  |         "saturday": "周六", | ||||||
|  |         "sunday": "周日" | ||||||
|  |     }, | ||||||
|  |     "months": { | ||||||
|  |         "january": "一月", | ||||||
|  |         "february": "二月", | ||||||
|  |         "march": "三月", | ||||||
|  |         "april": "四月", | ||||||
|  |         "may": "五月", | ||||||
|  |         "june": "六月", | ||||||
|  |         "july": "七月", | ||||||
|  |         "august": "八月", | ||||||
|  |         "september": "九月", | ||||||
|  |         "october": "十月", | ||||||
|  |         "november": "十一月", | ||||||
|  |         "december": "十二月" | ||||||
|  |     }, | ||||||
|  |     "special_notes": { | ||||||
|  |        "search_prefix": "搜索:" | ||||||
|  |     }, | ||||||
|  |     "code_block": { | ||||||
|  |         "theme_none": "无语法高亮", | ||||||
|  |         "theme_group_light": "浅色主题", | ||||||
|  |         "theme_group_dark": "深色主题" | ||||||
|  |     }, | ||||||
|  |     "test_sync": { | ||||||
|  |         "not-configured": "同步服务器主机未配置。请先配置同步。", | ||||||
|  |         "successful": "同步服务器握手成功,同步已开始。" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user