mirror of
https://github.com/zadam/trilium.git
synced 2025-11-10 15:25:51 +01:00
chore(react/type_widget): port content widget
This commit is contained in:
@@ -10,6 +10,7 @@ import Doc from "./type_widgets/Doc";
|
||||
import { TypeWidgetProps } from "./type_widgets/type_widget";
|
||||
import ProtectedSession from "./type_widgets/ProtectedSession";
|
||||
import Book from "./type_widgets/Book";
|
||||
import ContentWidget from "./type_widgets/ContentWidget";
|
||||
|
||||
/**
|
||||
* A `NoteType` altered by the note detail widget, taking into consideration whether the note is editable or not and adding special note types such as an empty one,
|
||||
@@ -62,6 +63,7 @@ function getCorrespondingWidget(noteType: ExtendedNoteType | undefined, props: T
|
||||
case "search": return <div className="note-detail-none note-detail-printable" />
|
||||
case "protectedSession": return <ProtectedSession />
|
||||
case "book": return <Book {...props} />
|
||||
case "contentWidget": return <ContentWidget {...props} />
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import sync from "../../services/sync";
|
||||
import HelpButton from "../react/HelpButton";
|
||||
import { TabContext } from "./ribbon-interface";
|
||||
import Modal from "../react/Modal";
|
||||
import { CodeMimeTypesList } from "../type_widgets_old/options/code_notes";
|
||||
import { ContentLanguagesList } from "../type_widgets_old/options/i18n";
|
||||
import { CodeMimeTypesList } from "../type_widgets/options/code_notes";
|
||||
import { ContentLanguagesList } from "../type_widgets/options/i18n";
|
||||
|
||||
export default function BasicPropertiesTab({ note }: TabContext) {
|
||||
return (
|
||||
|
||||
16
apps/client/src/widgets/type_widgets/ContentWidget.css
Normal file
16
apps/client/src/widgets/type_widgets/ContentWidget.css
Normal file
@@ -0,0 +1,16 @@
|
||||
.type-contentWidget .note-detail {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail-content-widget {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail-content-widget-content {
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail.full-height .note-detail-content-widget-content {
|
||||
padding: 0;
|
||||
}
|
||||
60
apps/client/src/widgets/type_widgets/ContentWidget.tsx
Normal file
60
apps/client/src/widgets/type_widgets/ContentWidget.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { TypeWidgetProps } from "./type_widget";
|
||||
import { JSX } from "preact/jsx-runtime";
|
||||
import { OptionPages } from "../type_widgets_old/content_widget";
|
||||
import AppearanceSettings from "./options/appearance";
|
||||
import ShortcutSettings from "./options/shortcuts";
|
||||
import TextNoteSettings from "./options/text_notes";
|
||||
import CodeNoteSettings from "./options/code_notes";
|
||||
import ImageSettings from "./options/images";
|
||||
import SpellcheckSettings from "./options/spellcheck";
|
||||
import PasswordSettings from "./options/password";
|
||||
import MultiFactorAuthenticationSettings from "./options/multi_factor_authentication";
|
||||
import EtapiSettings from "./options/etapi";
|
||||
import BackupSettings from "./options/backup";
|
||||
import SyncOptions from "./options/sync";
|
||||
import AiSettings from "./options/ai_settings";
|
||||
import OtherSettings from "./options/other";
|
||||
import InternationalizationOptions from "./options/i18n";
|
||||
import AdvancedSettings from "./options/advanced";
|
||||
import "./ContentWidget.css";
|
||||
import { t } from "../../services/i18n";
|
||||
|
||||
export type OptionPages = "_optionsAppearance" | "_optionsShortcuts" | "_optionsTextNotes" | "_optionsCodeNotes" | "_optionsImages" | "_optionsSpellcheck" | "_optionsPassword" | "_optionsMFA" | "_optionsEtapi" | "_optionsBackup" | "_optionsSync" | "_optionsAi" | "_optionsOther" | "_optionsLocalization" | "_optionsAdvanced";
|
||||
|
||||
const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", () => JSX.Element> = {
|
||||
_optionsAppearance: AppearanceSettings,
|
||||
_optionsShortcuts: ShortcutSettings,
|
||||
_optionsTextNotes: TextNoteSettings,
|
||||
_optionsCodeNotes: CodeNoteSettings,
|
||||
_optionsImages: ImageSettings,
|
||||
_optionsSpellcheck: SpellcheckSettings,
|
||||
_optionsPassword: PasswordSettings,
|
||||
_optionsMFA: MultiFactorAuthenticationSettings,
|
||||
_optionsEtapi: EtapiSettings,
|
||||
_optionsBackup: BackupSettings,
|
||||
_optionsSync: SyncOptions,
|
||||
_optionsAi: AiSettings,
|
||||
_optionsOther: OtherSettings,
|
||||
_optionsLocalization: InternationalizationOptions,
|
||||
_optionsAdvanced: AdvancedSettings,
|
||||
_backendLog: () => <></> // FIXME
|
||||
}
|
||||
|
||||
/**
|
||||
* Type widget that displays one or more widgets based on the type of note, generally used for options and other interactive notes such as the backend log.
|
||||
*
|
||||
* @param param0
|
||||
* @returns
|
||||
*/
|
||||
export default function ContentWidget({ note }: TypeWidgetProps) {
|
||||
const Content = CONTENT_WIDGETS[note.noteId];
|
||||
return (
|
||||
<div className="note-detail-content-widget note-detail-printable">
|
||||
<div className={`note-detail-content-widget-content ${note.noteId.startsWith("_options") ? "options" : ""}`}>
|
||||
{Content
|
||||
? <Content />
|
||||
: (t("content_widget.unknown_widget", { id: note.noteId }))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
1
apps/client/src/widgets/type_widgets/constants.ts
Normal file
1
apps/client/src/widgets/type_widgets/constants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const CODE_THEME_DEFAULT_PREFIX = "default:";
|
||||
@@ -8,7 +8,7 @@ import { useTriliumOption, useTriliumOptionBool, useTriliumOptionJson } from "..
|
||||
import OptionsSection from "./components/OptionsSection";
|
||||
import { useEffect, useMemo, useRef } from "preact/hooks";
|
||||
import codeNoteSample from "./samples/code_note.txt?raw";
|
||||
import { DEFAULT_PREFIX } from "../abstract_code_type_widget";
|
||||
import { CODE_THEME_DEFAULT_PREFIX as DEFAULT_PREFIX } from "../constants";
|
||||
import { MimeType } from "@triliumnext/commons";
|
||||
import mime_types from "../../../services/mime_types";
|
||||
import CheckboxList from "./components/CheckboxList";
|
||||
@@ -58,7 +58,7 @@ function Appearance() {
|
||||
<OptionsSection title={t("code_theme.title")}>
|
||||
<div className="row" style={{ marginBottom: "15px" }}>
|
||||
<FormGroup name="color-scheme" label={t("code_theme.color-scheme")} className="col-md-6" style={{ marginBottom: 0 }}>
|
||||
<FormSelect
|
||||
<FormSelect
|
||||
values={themes}
|
||||
keyProperty="id" titleProperty="name"
|
||||
currentValue={codeNoteTheme} onChange={setCodeNoteTheme}
|
||||
@@ -148,7 +148,7 @@ export function CodeMimeTypesList() {
|
||||
plainTextMimeType.enabled = true;
|
||||
plainTextMimeType.disabled = true;
|
||||
}
|
||||
|
||||
|
||||
for (const mimeType of ungroupedMimeTypes) {
|
||||
const initial = mimeType.title.charAt(0).toUpperCase();
|
||||
if (!result[initial]) {
|
||||
@@ -157,7 +157,7 @@ export function CodeMimeTypesList() {
|
||||
result[initial].push(mimeType);
|
||||
}
|
||||
return result;
|
||||
}, [ codeNotesMimeTypes ]);
|
||||
}, [ codeNotesMimeTypes ]);
|
||||
|
||||
return (
|
||||
<ul class="options-mime-types">
|
||||
@@ -174,4 +174,4 @@ export function CodeMimeTypesList() {
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import OptionsSection from "./OptionsSection";
|
||||
import type { OptionPages } from "../../content_widget";
|
||||
import type { OptionPages } from "../../ContentWidget";
|
||||
import { t } from "../../../../services/i18n";
|
||||
|
||||
interface RelatedSettingsProps {
|
||||
@@ -21,4 +21,4 @@ export default function RelatedSettings({ items }: RelatedSettingsProps) {
|
||||
</nav>
|
||||
</OptionsSection>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import TypeWidget from "./type_widget.js";
|
||||
import CodeMirror, { type EditorConfig } from "@triliumnext/codemirror";
|
||||
import type { EventData } from "../../components/app_context.js";
|
||||
|
||||
export const DEFAULT_PREFIX = "default:";
|
||||
|
||||
/**
|
||||
* An abstract {@link TypeWidget} which implements the CodeMirror editor, meant to be used as a parent for
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
import TypeWidget from "./type_widget.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import { t } from "../../services/i18n.js";
|
||||
import type { JSX } from "preact/jsx-runtime";
|
||||
import AppearanceSettings from "./options/appearance.jsx";
|
||||
import { disposeReactWidget, renderReactWidgetAtElement } from "../react/react_utils.jsx";
|
||||
import ImageSettings from "./options/images.jsx";
|
||||
import AdvancedSettings from "./options/advanced.jsx";
|
||||
import InternationalizationOptions from "./options/i18n.jsx";
|
||||
import SyncOptions from "./options/sync.jsx";
|
||||
import EtapiSettings from "./options/etapi.js";
|
||||
import BackupSettings from "./options/backup.js";
|
||||
import SpellcheckSettings from "./options/spellcheck.js";
|
||||
import PasswordSettings from "./options/password.jsx";
|
||||
import ShortcutSettings from "./options/shortcuts.js";
|
||||
import TextNoteSettings from "./options/text_notes.jsx";
|
||||
import CodeNoteSettings from "./options/code_notes.jsx";
|
||||
import OtherSettings from "./options/other.jsx";
|
||||
import BackendLogWidget from "./content/backend_log.js";
|
||||
import MultiFactorAuthenticationSettings from "./options/multi_factor_authentication.js";
|
||||
import AiSettings from "./options/ai_settings.jsx";
|
||||
import { unmountComponentAtNode } from "preact/compat";
|
||||
|
||||
const TPL = /*html*/`<div class="note-detail-content-widget note-detail-printable">
|
||||
<style>
|
||||
.type-contentWidget .note-detail {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail-content-widget {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail-content-widget-content {
|
||||
padding: 15px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.note-detail.full-height .note-detail-content-widget-content {
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="note-detail-content-widget-content"></div>
|
||||
</div>`;
|
||||
|
||||
export type OptionPages = "_optionsAppearance" | "_optionsShortcuts" | "_optionsTextNotes" | "_optionsCodeNotes" | "_optionsImages" | "_optionsSpellcheck" | "_optionsPassword" | "_optionsMFA" | "_optionsEtapi" | "_optionsBackup" | "_optionsSync" | "_optionsAi" | "_optionsOther" | "_optionsLocalization" | "_optionsAdvanced";
|
||||
|
||||
const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", ((typeof NoteContextAwareWidget)[] | JSX.Element)> = {
|
||||
_optionsAppearance: <AppearanceSettings />,
|
||||
_optionsShortcuts: <ShortcutSettings />,
|
||||
_optionsTextNotes: <TextNoteSettings />,
|
||||
_optionsCodeNotes: <CodeNoteSettings />,
|
||||
_optionsImages: <ImageSettings />,
|
||||
_optionsSpellcheck: <SpellcheckSettings />,
|
||||
_optionsPassword: <PasswordSettings />,
|
||||
_optionsMFA: <MultiFactorAuthenticationSettings />,
|
||||
_optionsEtapi: <EtapiSettings />,
|
||||
_optionsBackup: <BackupSettings />,
|
||||
_optionsSync: <SyncOptions />,
|
||||
_optionsAi: <AiSettings />,
|
||||
_optionsOther: <OtherSettings />,
|
||||
_optionsLocalization: <InternationalizationOptions />,
|
||||
_optionsAdvanced: <AdvancedSettings />,
|
||||
_backendLog: [
|
||||
BackendLogWidget
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Type widget that displays one or more widgets based on the type of note, generally used for options and other interactive notes such as the backend log.
|
||||
*
|
||||
* One important aspect is that, like its parent {@link TypeWidget}, the content widgets don't receive all events by default and they must be manually added
|
||||
* to the propagation list in {@link TypeWidget.handleEventInChildren}.
|
||||
*/
|
||||
export default class ContentWidgetTypeWidget extends TypeWidget {
|
||||
private $content!: JQuery<HTMLElement>;
|
||||
|
||||
static getType() {
|
||||
return "contentWidget";
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$content = this.$widget.find(".note-detail-content-widget-content");
|
||||
|
||||
super.doRender();
|
||||
}
|
||||
|
||||
async doRefresh(note: FNote) {
|
||||
unmountComponentAtNode(this.$content[0]);
|
||||
this.$content.empty();
|
||||
this.children = [];
|
||||
|
||||
const contentWidgets = (CONTENT_WIDGETS as Record<string, (typeof NoteContextAwareWidget[] | JSX.Element)>)[note.noteId];
|
||||
this.$content.toggleClass("options", note.noteId.startsWith("_options"));
|
||||
|
||||
// Unknown widget.
|
||||
if (!contentWidgets) {
|
||||
this.$content.append(t("content_widget.unknown_widget", { id: note.noteId }));
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy widget.
|
||||
if (Array.isArray(contentWidgets)) {
|
||||
for (const clazz of contentWidgets) {
|
||||
const widget = new clazz();
|
||||
|
||||
if (this.noteContext) {
|
||||
await widget.handleEvent("setNoteContext", { noteContext: this.noteContext });
|
||||
}
|
||||
this.child(widget);
|
||||
|
||||
this.$content.append(widget.render());
|
||||
await widget.refresh();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// React widget.
|
||||
renderReactWidgetAtElement(this, contentWidgets, this.$content[0]);
|
||||
}
|
||||
|
||||
cleanup(): void {
|
||||
if (this.noteId) {
|
||||
const contentWidgets = (CONTENT_WIDGETS as Record<string, (typeof NoteContextAwareWidget[] | JSX.Element)>)[this.noteId];
|
||||
if (contentWidgets && !Array.isArray(contentWidgets)) {
|
||||
disposeReactWidget(this.$content[0]);
|
||||
}
|
||||
}
|
||||
|
||||
super.cleanup();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user