mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	chore(client/ts): port options/appearance
This commit is contained in:
		
							parent
							
								
									5bfcf88acd
								
							
						
					
					
						commit
						552cc2753f
					
				| @ -188,6 +188,9 @@ export type CommandMappings = { | |||||||
|     copyTabToNewWindow: CommandData; |     copyTabToNewWindow: CommandData; | ||||||
|     closeActiveTab: CommandData & { |     closeActiveTab: CommandData & { | ||||||
|         $el: JQuery<HTMLElement> |         $el: JQuery<HTMLElement> | ||||||
|  |     }, | ||||||
|  |     setZoomFactorAndSave: { | ||||||
|  |         zoomFactor: string; | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| import { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
| import library_loader from "../../../../services/library_loader.js"; | import library_loader from "../../../../services/library_loader.js"; | ||||||
| import server from "../../../../services/server.js"; | import server from "../../../../services/server.js"; | ||||||
| @ -54,15 +55,27 @@ const TPL = ` | |||||||
| </div> | </div> | ||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
|  | interface Theme { | ||||||
|  |     title: string; | ||||||
|  |     val: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Response = Record<string, Theme[]> | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Contains appearance settings for code blocks within text notes, such as the theme for the syntax highlighter. |  * Contains appearance settings for code blocks within text notes, such as the theme for the syntax highlighter. | ||||||
|  */ |  */ | ||||||
| export default class CodeBlockOptions extends OptionsWidget { | export default class CodeBlockOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $themeSelect!: JQuery<HTMLElement>; | ||||||
|  |     private $wordWrap!: JQuery<HTMLElement>; | ||||||
|  |     private $sampleEl!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$themeSelect = this.$widget.find(".theme-select"); |         this.$themeSelect = this.$widget.find(".theme-select"); | ||||||
|         this.$themeSelect.on("change", async () => { |         this.$themeSelect.on("change", async () => { | ||||||
|             const newTheme = this.$themeSelect.val(); |             const newTheme = String(this.$themeSelect.val()); | ||||||
|             library_loader.loadHighlightingTheme(newTheme); |             library_loader.loadHighlightingTheme(newTheme); | ||||||
|             await server.put(`options/codeBlockTheme/${newTheme}`); |             await server.put(`options/codeBlockTheme/${newTheme}`); | ||||||
|         }); |         }); | ||||||
| @ -74,7 +87,7 @@ export default class CodeBlockOptions extends OptionsWidget { | |||||||
|         this.$sampleEl = this.$widget.find(".code-sample"); |         this.$sampleEl = this.$widget.find(".code-sample"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #setupPreview(shouldEnableSyntaxHighlight) { |     #setupPreview(shouldEnableSyntaxHighlight: boolean) { | ||||||
|         const text = SAMPLE_CODE; |         const text = SAMPLE_CODE; | ||||||
|         if (shouldEnableSyntaxHighlight) { |         if (shouldEnableSyntaxHighlight) { | ||||||
|             library_loader.requireLibrary(library_loader.HIGHLIGHT_JS).then(() => { |             library_loader.requireLibrary(library_loader.HIGHLIGHT_JS).then(() => { | ||||||
| @ -88,8 +101,8 @@ export default class CodeBlockOptions extends OptionsWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         const themeGroups = await server.get("options/codeblock-themes"); |         const themeGroups = await server.get<Response>("options/codeblock-themes"); | ||||||
|         this.$themeSelect.empty(); |         this.$themeSelect.empty(); | ||||||
| 
 | 
 | ||||||
|         for (const [key, themes] of Object.entries(themeGroups)) { |         for (const [key, themes] of Object.entries(themeGroups)) { | ||||||
| @ -104,7 +117,9 @@ export default class CodeBlockOptions extends OptionsWidget { | |||||||
|                     this.$themeSelect.append(option); |                     this.$themeSelect.append(option); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             this.$themeSelect.append($group); |             if ($group) { | ||||||
|  |                 this.$themeSelect.append($group); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         this.$themeSelect.val(options.codeBlockTheme); |         this.$themeSelect.val(options.codeBlockTheme); | ||||||
|         this.setCheckboxState(this.$wordWrap, options.codeBlockWordWrap); |         this.setCheckboxState(this.$wordWrap, options.codeBlockWordWrap); | ||||||
| @ -1,15 +1,16 @@ | |||||||
| import OptionsWidget from "../options_widget.js"; | import OptionsWidget from "../options_widget.js"; | ||||||
| import { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
| import utils from "../../../../services/utils.js"; | import utils from "../../../../services/utils.js"; | ||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="options-section">     | <div class="options-section"> | ||||||
|     <h4>${t("electron_integration.desktop-application")}</h4> |     <h4>${t("electron_integration.desktop-application")}</h4> | ||||||
| 
 | 
 | ||||||
|     <div class="form-group row"> |     <div class="form-group row"> | ||||||
|         <div class="col-12"> |         <div class="col-12"> | ||||||
|             <label for="zoom-factor-select">${t("electron_integration.zoom-factor")}</label> |             <label for="zoom-factor-select">${t("electron_integration.zoom-factor")}</label> | ||||||
|             <input id="zoom-factor-select" type="number" class="zoom-factor-select form-control options-number-input" min="0.3" max="2.0" step="0.1"/>             |             <input id="zoom-factor-select" type="number" class="zoom-factor-select form-control options-number-input" min="0.3" max="2.0" step="0.1"/> | ||||||
|             <p>${t("zoom_factor.description")}</p> |             <p>${t("zoom_factor.description")}</p> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| @ -20,7 +21,7 @@ const TPL = ` | |||||||
|             <input type="checkbox" class="native-title-bar form-check-input" /> |             <input type="checkbox" class="native-title-bar form-check-input" /> | ||||||
|             <strong>${t("electron_integration.native-title-bar")}</strong> |             <strong>${t("electron_integration.native-title-bar")}</strong> | ||||||
|             <p>${t("electron_integration.native-title-bar-description")}</p> |             <p>${t("electron_integration.native-title-bar-description")}</p> | ||||||
|         </label>         |         </label> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <div class="side-checkbox"> |     <div class="side-checkbox"> | ||||||
| @ -28,7 +29,7 @@ const TPL = ` | |||||||
|             <input type="checkbox" class="background-effects form-check-input" /> |             <input type="checkbox" class="background-effects form-check-input" /> | ||||||
|             <strong>${t("electron_integration.background-effects")}</strong> |             <strong>${t("electron_integration.background-effects")}</strong> | ||||||
|             <p>${t("electron_integration.background-effects-description")}</p> |             <p>${t("electron_integration.background-effects-description")}</p> | ||||||
|         </label>         |         </label> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <button class="btn btn-micro restart-app-button">${t("electron_integration.restart-app-button")}</button> |     <button class="btn btn-micro restart-app-button">${t("electron_integration.restart-app-button")}</button> | ||||||
| @ -36,12 +37,17 @@ const TPL = ` | |||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
| export default class ElectronIntegrationOptions extends OptionsWidget { | export default class ElectronIntegrationOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $zoomFactorSelect!: JQuery<HTMLElement>; | ||||||
|  |     private $nativeTitleBar!: JQuery<HTMLElement>; | ||||||
|  |     private $backgroundEffects!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
| 
 | 
 | ||||||
|         this.$zoomFactorSelect = this.$widget.find(".zoom-factor-select"); |         this.$zoomFactorSelect = this.$widget.find(".zoom-factor-select"); | ||||||
|         this.$zoomFactorSelect.on("change", () => { |         this.$zoomFactorSelect.on("change", () => { | ||||||
|             appContext.triggerCommand("setZoomFactorAndSave", { zoomFactor: this.$zoomFactorSelect.val() }); |             this.triggerCommand("setZoomFactorAndSave", { zoomFactor: String(this.$zoomFactorSelect.val()) }); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.$nativeTitleBar = this.$widget.find("input.native-title-bar"); |         this.$nativeTitleBar = this.$widget.find("input.native-title-bar"); | ||||||
| @ -62,7 +68,7 @@ export default class ElectronIntegrationOptions extends OptionsWidget { | |||||||
|         return utils.isElectron(); |         return utils.isElectron(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         this.$zoomFactorSelect.val(options.zoomFactor); |         this.$zoomFactorSelect.val(options.zoomFactor); | ||||||
|         this.setCheckboxState(this.$nativeTitleBar, options.nativeTitleBarVisible); |         this.setCheckboxState(this.$nativeTitleBar, options.nativeTitleBarVisible); | ||||||
|         this.setCheckboxState(this.$backgroundEffects, options.backgroundEffects); |         this.setCheckboxState(this.$backgroundEffects, options.backgroundEffects); | ||||||
| @ -2,6 +2,7 @@ import OptionsWidget from "../options_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 { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="options-section"> | <div class="options-section"> | ||||||
| @ -24,7 +25,17 @@ const TPL = ` | |||||||
| </div> | </div> | ||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
|  | // TODO: Deduplicate with server.
 | ||||||
|  | interface Locale { | ||||||
|  |     id: string; | ||||||
|  |     name: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default class LocalizationOptions extends OptionsWidget { | export default class LocalizationOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $localeSelect!: JQuery<HTMLElement>; | ||||||
|  |     private $firstDayOfWeek!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
| 
 | 
 | ||||||
| @ -37,12 +48,12 @@ export default class LocalizationOptions extends OptionsWidget { | |||||||
| 
 | 
 | ||||||
|         this.$firstDayOfWeek = this.$widget.find(".first-day-of-week-select"); |         this.$firstDayOfWeek = this.$widget.find(".first-day-of-week-select"); | ||||||
|         this.$firstDayOfWeek.on("change", () => { |         this.$firstDayOfWeek.on("change", () => { | ||||||
|             this.updateOption("firstDayOfWeek", this.$firstDayOfWeek.val()); |             this.updateOption("firstDayOfWeek", String(this.$firstDayOfWeek.val())); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         const availableLocales = await server.get("options/locales"); |         const availableLocales = await server.get<Locale[]>("options/locales"); | ||||||
|         this.$localeSelect.empty(); |         this.$localeSelect.empty(); | ||||||
| 
 | 
 | ||||||
|         for (const locale of availableLocales) { |         for (const locale of availableLocales) { | ||||||
| @ -1,6 +1,7 @@ | |||||||
| import OptionsWidget from "../options_widget.js"; | import OptionsWidget from "../options_widget.js"; | ||||||
| import utils from "../../../../services/utils.js"; | import utils from "../../../../services/utils.js"; | ||||||
| import { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| 
 | 
 | ||||||
| const MIN_VALUE = 640; | const MIN_VALUE = 640; | ||||||
| 
 | 
 | ||||||
| @ -24,17 +25,20 @@ const TPL = ` | |||||||
| </div>`;
 | </div>`;
 | ||||||
| 
 | 
 | ||||||
| export default class MaxContentWidthOptions extends OptionsWidget { | export default class MaxContentWidthOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $maxContentWidth!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
| 
 | 
 | ||||||
|         this.$maxContentWidth = this.$widget.find(".max-content-width"); |         this.$maxContentWidth = this.$widget.find(".max-content-width"); | ||||||
| 
 | 
 | ||||||
|         this.$maxContentWidth.on("change", async () => this.updateOption("maxContentWidth", this.$maxContentWidth.val())); |         this.$maxContentWidth.on("change", async () => this.updateOption("maxContentWidth", String(this.$maxContentWidth.val()))); | ||||||
| 
 | 
 | ||||||
|         this.$widget.find(".reload-frontend-button").on("click", () => utils.reloadFrontendApp(t("max_content_width.reload_description"))); |         this.$widget.find(".reload-frontend-button").on("click", () => utils.reloadFrontendApp(t("max_content_width.reload_description"))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         this.$maxContentWidth.val(Math.max(MIN_VALUE, options.maxContentWidth)); |         this.$maxContentWidth.val(Math.max(MIN_VALUE, parseInt(options.maxContentWidth, 10))); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| import { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
| import OptionsWidget from "../options_widget.js"; | import OptionsWidget from "../options_widget.js"; | ||||||
| 
 | 
 | ||||||
| @ -8,7 +9,7 @@ const TPL = ` | |||||||
|         <input type="checkbox" class="promoted-attributes-open-in-ribbon form-check-input"> |         <input type="checkbox" class="promoted-attributes-open-in-ribbon form-check-input"> | ||||||
|         ${t("ribbon.promoted_attributes_message")} |         ${t("ribbon.promoted_attributes_message")} | ||||||
|     </label> |     </label> | ||||||
|      | 
 | ||||||
|     <label> |     <label> | ||||||
|         <input type="checkbox" class="edited-notes-open-in-ribbon form-check-input"> |         <input type="checkbox" class="edited-notes-open-in-ribbon form-check-input"> | ||||||
|         ${t("ribbon.edited_notes_message")} |         ${t("ribbon.edited_notes_message")} | ||||||
| @ -16,6 +17,10 @@ const TPL = ` | |||||||
| </div>`;
 | </div>`;
 | ||||||
| 
 | 
 | ||||||
| export default class RibbonOptions extends OptionsWidget { | export default class RibbonOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $promotedAttributesOpenInRibbon!: JQuery<HTMLElement>; | ||||||
|  |     private $editedNotesOpenInRibbon!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
| 
 | 
 | ||||||
| @ -26,7 +31,7 @@ export default class RibbonOptions extends OptionsWidget { | |||||||
|         this.$editedNotesOpenInRibbon.on("change", () => this.updateCheckboxOption("editedNotesOpenInRibbon", this.$editedNotesOpenInRibbon)); |         this.$editedNotesOpenInRibbon.on("change", () => this.updateCheckboxOption("editedNotesOpenInRibbon", this.$editedNotesOpenInRibbon)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         this.setCheckboxState(this.$promotedAttributesOpenInRibbon, options.promotedAttributesOpenInRibbon); |         this.setCheckboxState(this.$promotedAttributesOpenInRibbon, options.promotedAttributesOpenInRibbon); | ||||||
|         this.setCheckboxState(this.$editedNotesOpenInRibbon, options.editedNotesOpenInRibbon); |         this.setCheckboxState(this.$editedNotesOpenInRibbon, options.editedNotesOpenInRibbon); | ||||||
|     } |     } | ||||||
| @ -2,6 +2,7 @@ import OptionsWidget from "../options_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 { t } from "../../../../services/i18n.js"; | import { t } from "../../../../services/i18n.js"; | ||||||
|  | import type { OptionMap } from "../../../../../../services/options_interface.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="options-section"> | <div class="options-section"> | ||||||
| @ -44,13 +45,24 @@ const TPL = ` | |||||||
|     </div> |     </div> | ||||||
| </div>`;
 | </div>`;
 | ||||||
| 
 | 
 | ||||||
|  | interface Theme { | ||||||
|  |     val: string; | ||||||
|  |     title: string; | ||||||
|  |     noteId?: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default class ThemeOptions extends OptionsWidget { | export default class ThemeOptions extends OptionsWidget { | ||||||
|  | 
 | ||||||
|  |     private $themeSelect!: JQuery<HTMLElement>; | ||||||
|  |     private $overrideThemeFonts!: JQuery<HTMLElement>; | ||||||
|  |     private $layoutOrientation!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$themeSelect = this.$widget.find(".theme-select"); |         this.$themeSelect = this.$widget.find(".theme-select"); | ||||||
|         this.$overrideThemeFonts = this.$widget.find(".override-theme-fonts"); |         this.$overrideThemeFonts = this.$widget.find(".override-theme-fonts"); | ||||||
|         this.$layoutOrientation = this.$widget.find(`input[name="layout-orientation"]`).on("change", async () => { |         this.$layoutOrientation = this.$widget.find(`input[name="layout-orientation"]`).on("change", async () => { | ||||||
|             const newLayoutOrientation = this.$widget.find(`input[name="layout-orientation"]:checked`).val(); |             const newLayoutOrientation = String(this.$widget.find(`input[name="layout-orientation"]:checked`).val()); | ||||||
|             await this.updateOption("layoutOrientation", newLayoutOrientation); |             await this.updateOption("layoutOrientation", newLayoutOrientation); | ||||||
|             utils.reloadFrontendApp("layout orientation change"); |             utils.reloadFrontendApp("layout orientation change"); | ||||||
|         }); |         }); | ||||||
| @ -66,20 +78,23 @@ export default class ThemeOptions extends OptionsWidget { | |||||||
|         this.$overrideThemeFonts.on("change", () => this.updateCheckboxOption("overrideThemeFonts", this.$overrideThemeFonts)); |         this.$overrideThemeFonts.on("change", () => this.updateCheckboxOption("overrideThemeFonts", this.$overrideThemeFonts)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async optionsLoaded(options) { |     async optionsLoaded(options: OptionMap) { | ||||||
|         const themes = [ |         const themes: Theme[] = [ | ||||||
|             { val: "next", title: t("theme.triliumnext") }, |             { val: "next", title: t("theme.triliumnext") }, | ||||||
|             { val: "next-light", title: t("theme.triliumnext-light") }, |             { val: "next-light", title: t("theme.triliumnext-light") }, | ||||||
|             { val: "next-dark", title: t("theme.triliumnext-dark") }, |             { val: "next-dark", title: t("theme.triliumnext-dark") }, | ||||||
|             { val: "auto", title: t("theme.auto_theme") }, |             { val: "auto", title: t("theme.auto_theme") }, | ||||||
|             { val: "light", title: t("theme.light_theme") }, |             { val: "light", title: t("theme.light_theme") }, | ||||||
|             { val: "dark", title: t("theme.dark_theme") } |             { val: "dark", title: t("theme.dark_theme") } | ||||||
|         ].concat(await server.get("options/user-themes")); |         ].concat(await server.get<Theme[]>("options/user-themes")); | ||||||
| 
 | 
 | ||||||
|         this.$themeSelect.empty(); |         this.$themeSelect.empty(); | ||||||
| 
 | 
 | ||||||
|         for (const theme of themes) { |         for (const theme of themes) { | ||||||
|             this.$themeSelect.append($("<option>").attr("value", theme.val).attr("data-note-id", theme.noteId).text(theme.title)); |             this.$themeSelect.append($("<option>") | ||||||
|  |                 .attr("value", theme.val) | ||||||
|  |                 .attr("data-note-id", theme.noteId || "") | ||||||
|  |                 .text(theme.title)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.$themeSelect.val(options.theme); |         this.$themeSelect.val(options.theme); | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran