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 = $(`