diff --git a/apps/client/src/stylesheets/style.css b/apps/client/src/stylesheets/style.css index 8e1a787e0..47368ca19 100644 --- a/apps/client/src/stylesheets/style.css +++ b/apps/client/src/stylesheets/style.css @@ -1749,10 +1749,6 @@ button.close:hover { flex-grow: 0 !important; } -.options-mime-types { - column-width: 250px; -} - textarea { cursor: auto; } diff --git a/apps/client/src/stylesheets/theme-next/pages.css b/apps/client/src/stylesheets/theme-next/pages.css index 1d2d0512c..b174f6ced 100644 --- a/apps/client/src/stylesheets/theme-next/pages.css +++ b/apps/client/src/stylesheets/theme-next/pages.css @@ -233,11 +233,6 @@ div.note-detail-empty { margin-bottom: 0; } -.options-section .options-mime-types { - padding: 0; - margin: 0; -} - .options-section .form-group { margin-bottom: 1em; } diff --git a/apps/client/src/widgets/type_widgets/options/code_notes.tsx b/apps/client/src/widgets/type_widgets/options/code_notes.tsx index 4acc20c7c..4e025436f 100644 --- a/apps/client/src/widgets/type_widgets/options/code_notes.tsx +++ b/apps/client/src/widgets/type_widgets/options/code_notes.tsx @@ -4,11 +4,15 @@ import Column from "../../react/Column"; import FormCheckbox from "../../react/FormCheckbox"; import FormGroup from "../../react/FormGroup"; import FormSelect from "../../react/FormSelect"; -import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; +import { useTriliumOption, useTriliumOptionBool, useTriliumOptionJson } from "../../react/hooks"; import OptionsSection from "./components/OptionsSection"; -import { useEffect, useMemo, useRef } from "preact/hooks"; +import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import codeNoteSample from "./samples/code_note.txt?raw"; import { DEFAULT_PREFIX } from "../abstract_code_type_widget"; +import { MimeType } from "@triliumnext/commons"; +import mime_types from "../../../services/mime_types"; +import CheckboxList from "./components/CheckboxList"; +import { CSSProperties, memo } from "preact/compat"; const SAMPLE_MIME = "application/typescript"; @@ -17,6 +21,7 @@ export default function CodeNoteSettings() { <> + > ) } @@ -116,4 +121,45 @@ function CodeNotePreview({ themeName, wordWrapping }: { themeName: string, wordW style={{ margin: 0, height: "200px" }} /> ); +} + +function CodeMimeTypes() { + const [ codeNotesMimeTypes, setCodeNotesMimeTypes ] = useTriliumOptionJson("codeNotesMimeTypes"); + const sectionStyle = useMemo(() => ({ marginBottom: "1em", breakInside: "avoid-column" }), []); + const groupedMimeTypes: Record = useMemo(() => { + mime_types.loadMimeTypes(); + + const ungroupedMimeTypes = Array.from(mime_types.getMimeTypes()); + const plainTextMimeType = ungroupedMimeTypes.shift(); + const result: Record = {}; + ungroupedMimeTypes.sort((a, b) => a.title.localeCompare(b.title)); + + result[""] = [ plainTextMimeType! ]; + for (const mimeType of ungroupedMimeTypes) { + const initial = mimeType.title.charAt(0).toUpperCase(); + if (!result[initial]) { + result[initial] = []; + } + result[initial].push(mimeType); + } + return result; + }, []); + + return ( + + + {Object.entries(groupedMimeTypes).map(([ initial, mimeTypes ]) => ( + + { initial && {initial} } + + + ))} + + + ) } \ No newline at end of file diff --git a/apps/client/src/widgets/type_widgets/options/code_notes/code_mime_types.ts b/apps/client/src/widgets/type_widgets/options/code_notes/code_mime_types.ts deleted file mode 100644 index 7bb4ecac8..000000000 --- a/apps/client/src/widgets/type_widgets/options/code_notes/code_mime_types.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { t } from "../../../../services/i18n.js"; -import OptionsWidget from "../options_widget.js"; -import mimeTypesService from "../../../../services/mime_types.js"; -import type { OptionMap } from "@triliumnext/commons"; - -const TPL = /*html*/` - - ${t("code_mime_types.title")} - - - - - -`; - -let idCtr = 1; // global, since this can be shown in multiple dialogs - -interface MimeType { - title: string; - mime: string; - enabled: boolean; -} - -type GroupedMimes = Record; - -function groupMimeTypesAlphabetically(ungroupedMimeTypes: MimeType[]) { - const result: GroupedMimes = {}; - ungroupedMimeTypes = ungroupedMimeTypes.toSorted((a, b) => a.title.localeCompare(b.title)); - - for (const mimeType of ungroupedMimeTypes) { - const initial = mimeType.title.charAt(0).toUpperCase(); - if (!result[initial]) { - result[initial] = []; - } - result[initial].push(mimeType); - } - return result; -} - -export default class CodeMimeTypesOptions extends OptionsWidget { - - private $mimeTypes!: JQuery; - - doRender() { - this.$widget = $(TPL); - this.$mimeTypes = this.$widget.find(".options-mime-types"); - } - - async optionsLoaded(options: OptionMap) { - this.$mimeTypes.empty(); - mimeTypesService.loadMimeTypes(); - - const ungroupedMimeTypes = Array.from(mimeTypesService.getMimeTypes()); - const plainTextMimeType = ungroupedMimeTypes.shift(); - const groupedMimeTypes = groupMimeTypesAlphabetically(ungroupedMimeTypes); - - // Plain text is displayed at the top intentionally. - if (plainTextMimeType) { - const $plainEl = this.#buildSelectionForMimeType(plainTextMimeType); - $plainEl.find("input").attr("disabled", ""); - this.$mimeTypes.append($plainEl); - } - - for (const [initial, mimeTypes] of Object.entries(groupedMimeTypes)) { - const $section = $(""); - $section.append($("").text(initial)); - - for (const mimeType of mimeTypes) { - $section.append(this.#buildSelectionForMimeType(mimeType)); - } - - this.$mimeTypes.append($section); - } - } - - async save() { - const enabledMimeTypes: string[] = []; - - this.$mimeTypes.find("input:checked").each((i, el) => { - const mimeType = this.$widget.find(el).attr("data-mime-type"); - if (mimeType) { - enabledMimeTypes.push(mimeType); - } - }); - - await this.updateOption("codeNotesMimeTypes", JSON.stringify(enabledMimeTypes)); - } - - #buildSelectionForMimeType(mimeType: MimeType) { - const id = "code-mime-type-" + idCtr++; - - const checkbox = $(``) - .append($('').attr("id", id).attr("data-mime-type", mimeType.mime).prop("checked", mimeType.enabled)) - .on("change", () => this.save()) - .append(mimeType.title); - - return $("").append(checkbox); - } -} diff --git a/apps/client/src/widgets/type_widgets/options/components/CheckboxList.tsx b/apps/client/src/widgets/type_widgets/options/components/CheckboxList.tsx index 66b17dd48..3e0b20814 100644 --- a/apps/client/src/widgets/type_widgets/options/components/CheckboxList.tsx +++ b/apps/client/src/widgets/type_widgets/options/components/CheckboxList.tsx @@ -4,9 +4,10 @@ interface CheckboxListProps { titleProperty?: keyof T; currentValue: string[]; onChange: (newValues: string[]) => void; + columnWidth?: string; } -export default function CheckboxList({ values, keyProperty, titleProperty, currentValue, onChange }: CheckboxListProps) { +export default function CheckboxList({ values, keyProperty, titleProperty, currentValue, onChange, columnWidth }: CheckboxListProps) { function toggleValue(value: string) { if (currentValue.includes(value)) { // Already there, needs removing. @@ -18,7 +19,7 @@ export default function CheckboxList({ values, keyProperty, titleProperty, cu } return ( - + {values.map(value => ( diff --git a/apps/client/src/widgets/type_widgets/options/text_notes/date_time_format.ts b/apps/client/src/widgets/type_widgets/options/text_notes/date_time_format.ts deleted file mode 100644 index 690778173..000000000 --- a/apps/client/src/widgets/type_widgets/options/text_notes/date_time_format.ts +++ /dev/null @@ -1,65 +0,0 @@ -import OptionsWidget from "../options_widget.js"; -import { t } from "../../../../services/i18n.js"; -import type { OptionMap } from "@triliumnext/commons"; -import utils from "../../../../services/utils.js"; -import keyboardActionsService from "../../../../services/keyboard_actions.js"; -import linkService from "../../../.././services/link.js"; - -const TPL = /*html*/` - - - - - - - ${t("custom_date_time_format.format_string")} - - - - ${t("custom_date_time_format.formatted_time")} - - - - -`; - -export default class DateTimeFormatOptions extends OptionsWidget { - - private $formatInput!: JQuery; - private $formattedDate!: JQuery; - - doRender() { - this.$widget = $(TPL); - - this.$formatInput = this.$widget.find("input.custom-date-time-format"); - this.$formattedDate = this.$widget.find(".formatted-date"); - - this.$formatInput.on("input", () => { - const dateString = utils.formatDateTime(new Date(), this.$formatInput.val()); - this.$formattedDate.text(dateString); - }); - - this.$formatInput.on('blur keydown', (e) => { - if (e.type === 'blur' || (e.type === 'keydown' && e.key === 'Enter')) { - this.updateOption("customDateTimeFormat", this.$formatInput.val()); - } - }); - - return this.$widget; - } - - async optionsLoaded(options: OptionMap) { - const action = await keyboardActionsService.getAction(""); - const shortcutKey = (action.effectiveShortcuts ?? []).join(", "); - const $link = await linkService.createLink("_hidden/_options/_optionsShortcuts", { - "title": shortcutKey, - "showTooltip": false - }); - this.$widget.find(".description").find("kbd").replaceWith($link); - - const customDateTimeFormat = options.customDateTimeFormat || "YYYY-MM-DD HH:mm"; - this.$formatInput.val(customDateTimeFormat); - const dateString = utils.formatDateTime(new Date(), customDateTimeFormat); - this.$formattedDate.text(dateString); - } -}
-