diff --git a/import_map.json b/import_map.json index bce44d9a..a89f9d6c 100644 --- a/import_map.json +++ b/import_map.json @@ -37,6 +37,9 @@ "porter-stemmer": "https://esm.sh/porter-stemmer@0.9.1", "preact-feather": "https://esm.sh/preact-feather@4.2.1?external=preact", "preact-feather/types": "https://esm.sh/preact-feather@4.2.1/dist/types?external=preact", + "react-icons/md": "https://deno.land/x/react_icons_md@1.0.9/mod.ts", + "react-icons/md/": "https://deno.land/x/react_icons_md@1.0.9/ico/", + "react-icons/types": "https://deno.land/x/react_icons@1.0.9/mod.ts", "s3_lite_client/": "https://deno.land/x/s3_lite_client@0.4.0/", "turndown": "https://cdn.skypack.dev/turndown@7.1.1", "turndown-plugin-gfm": "https://cdn.skypack.dev/@joplin/turndown-plugin-gfm@1.0.45", diff --git a/web/components/top_bar.tsx b/web/components/top_bar.tsx index 446c0072..28c64c6c 100644 --- a/web/components/top_bar.tsx +++ b/web/components/top_bar.tsx @@ -2,10 +2,11 @@ import { CompletionContext, CompletionResult } from "@codemirror/autocomplete"; import type { ComponentChildren, FunctionalComponent } from "preact"; import { Notification } from "$lib/web.ts"; import { FeatherProps } from "preact-feather/types"; +import { IconBaseProps } from "react-icons/types"; import { MiniEditor } from "./mini_editor.tsx"; export type ActionButton = { - icon: FunctionalComponent; + icon: FunctionalComponent; description: string; class?: string; callback: () => void; diff --git a/web/editor_ui.tsx b/web/editor_ui.tsx index 59e7f47b..2c63e425 100644 --- a/web/editor_ui.tsx +++ b/web/editor_ui.tsx @@ -6,6 +6,7 @@ import { TopBar } from "./components/top_bar.tsx"; import reducer from "./reducer.ts"; import { Action, AppViewState, initialViewState } from "../type/web.ts"; import * as featherIcons from "preact-feather"; +import * as mdi from "./filtered_material_icons.ts" import { h, render as preactRender } from "preact"; import { useEffect, useReducer } from "preact/hooks"; import { closeSearchPanel } from "@codemirror/search"; @@ -251,13 +252,14 @@ export class MainUI { ) .map((button) => { const parsedCommand = parseCommand(button.command); + const mdiIcon = (mdi as any)[kebabToCamel(button.icon)]; let featherIcon = (featherIcons as any)[kebabToCamel(button.icon)]; if (!featherIcon) { featherIcon = featherIcons.HelpCircle; } return { - icon: featherIcon, + icon: mdiIcon ? mdiIcon : featherIcon, description: button.description || "", callback: () => { client.runCommandByName( diff --git a/web/filtered_material_icons.ts b/web/filtered_material_icons.ts new file mode 100644 index 00000000..63d457cc --- /dev/null +++ b/web/filtered_material_icons.ts @@ -0,0 +1,26 @@ +/** + * We apply a selective export of allowed icons. + * It allows us to only import icons which fit an editor context, this avoids inflating the + * bundle size with mostly unused icons, but still allows users to freely choose from the allowed + * selection. + */ +export { + MdChecklist, + MdCode, + MdFileUpload, + MdFormatBold, + MdFormatIndentDecrease, + MdFormatIndentIncrease, + MdFormatItalic, + MdFormatListBulleted, + MdFormatListNumbered, + MdFormatQuote, + MdFormatSize, + MdFormatStrikethrough, + MdHome, + MdHorizontalRule, + MdImage, + MdLink, + MdOutlineLibraryBooks, + MdTerminal, +} from "react-icons/md";