mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	chore(highlightjs): reintroduce grouping of themes
This commit is contained in:
		| @@ -1621,7 +1621,10 @@ | |||||||
|     "color-scheme": "颜色方案" |     "color-scheme": "颜色方案" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "自动换行" |     "word_wrapping": "自动换行", | ||||||
|  |     "theme_none": "无语法高亮", | ||||||
|  |     "theme_group_light": "浅色主题", | ||||||
|  |     "theme_group_dark": "深色主题" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "格式化" |     "title": "格式化" | ||||||
|   | |||||||
| @@ -1573,7 +1573,10 @@ | |||||||
|     "color-scheme": "Farbschema" |     "color-scheme": "Farbschema" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "Wortumbruch" |     "word_wrapping": "Wortumbruch", | ||||||
|  |     "theme_none": "Keine Syntax-Hervorhebung", | ||||||
|  |     "theme_group_light": "Helle Themen", | ||||||
|  |     "theme_group_dark": "Dunkle Themen" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "Format" |     "title": "Format" | ||||||
|   | |||||||
| @@ -1827,7 +1827,10 @@ | |||||||
|     "color-scheme": "Color Scheme" |     "color-scheme": "Color Scheme" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "Word wrapping" |     "word_wrapping": "Word wrapping", | ||||||
|  |     "theme_none": "No syntax highlighting", | ||||||
|  |     "theme_group_light": "Light themes", | ||||||
|  |     "theme_group_dark": "Dark themes" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "Formatting" |     "title": "Formatting" | ||||||
|   | |||||||
| @@ -1589,7 +1589,10 @@ | |||||||
|     "color-scheme": "Esquema de color" |     "color-scheme": "Esquema de color" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "Ajuste de palabras" |     "word_wrapping": "Ajuste de palabras", | ||||||
|  |     "theme_none": "Sin resaltado de sintaxis", | ||||||
|  |     "theme_group_light": "Temas claros", | ||||||
|  |     "theme_group_dark": "Temas oscuros" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "Formato" |     "title": "Formato" | ||||||
|   | |||||||
| @@ -1579,7 +1579,10 @@ | |||||||
|     "color-scheme": "Jeu de couleurs" |     "color-scheme": "Jeu de couleurs" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "Saut à la ligne automatique suivant la largeur" |     "word_wrapping": "Saut à la ligne automatique suivant la largeur", | ||||||
|  |     "theme_none": "Pas de coloration syntaxique", | ||||||
|  |     "theme_group_light": "Thèmes clairs", | ||||||
|  |     "theme_group_dark": "Thèmes sombres" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "Mise en forme" |     "title": "Mise en forme" | ||||||
|   | |||||||
| @@ -1,5 +1,10 @@ | |||||||
| { | { | ||||||
|   "revisions": { |   "revisions": { | ||||||
|     "delete_button": "" |     "delete_button": "" | ||||||
|  |   }, | ||||||
|  |   "code_block": { | ||||||
|  |     "theme_none": "Sem destaque de sintaxe", | ||||||
|  |     "theme_group_light": "Temas claros", | ||||||
|  |     "theme_group_dark": "Temas escuros" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1585,7 +1585,10 @@ | |||||||
|     "description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări." |     "description": "Controlează evidențierea de sintaxă pentru blocurile de cod în interiorul notițelor text, notițele de tip cod nu vor fi afectate de aceste setări." | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "Încadrare text" |     "word_wrapping": "Încadrare text", | ||||||
|  |     "theme_none": "Fără evidențiere de sintaxă", | ||||||
|  |     "theme_group_dark": "Teme întunecate", | ||||||
|  |     "theme_group_light": "Teme luminoase" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "Formatare" |     "title": "Formatare" | ||||||
|   | |||||||
| @@ -1519,7 +1519,10 @@ | |||||||
|     "color-scheme": "顏色方案" |     "color-scheme": "顏色方案" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |   "code_block": { | ||||||
|     "word_wrapping": "自動換行" |     "word_wrapping": "自動換行", | ||||||
|  |     "theme_none": "無格式高亮", | ||||||
|  |     "theme_group_light": "淺色主題", | ||||||
|  |     "theme_group_dark": "深色主題" | ||||||
|   }, |   }, | ||||||
|   "classic_editor_toolbar": { |   "classic_editor_toolbar": { | ||||||
|     "title": "格式化" |     "title": "格式化" | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ import { t } from "../../../../services/i18n.js"; | |||||||
| import server from "../../../../services/server.js"; | import server from "../../../../services/server.js"; | ||||||
| import OptionsWidget from "../options_widget.js"; | import OptionsWidget from "../options_widget.js"; | ||||||
| import { ensureMimeTypesForHighlighting, loadHighlightingTheme } from "../../../../services/syntax_highlight.js"; | import { ensureMimeTypesForHighlighting, loadHighlightingTheme } from "../../../../services/syntax_highlight.js"; | ||||||
| import { Themes } from "@triliumnext/highlightjs"; | import { Themes, type Theme } from "@triliumnext/highlightjs"; | ||||||
|  |  | ||||||
| const SAMPLE_LANGUAGE = normalizeMimeTypeForCKEditor("application/javascript;env=frontend"); | const SAMPLE_LANGUAGE = normalizeMimeTypeForCKEditor("application/javascript;env=frontend"); | ||||||
| const SAMPLE_CODE = `\ | const SAMPLE_CODE = `\ | ||||||
| @@ -68,13 +68,28 @@ export default class CodeBlockOptions extends OptionsWidget { | |||||||
|     doRender() { |     doRender() { | ||||||
|         this.$widget = $(TPL); |         this.$widget = $(TPL); | ||||||
|         this.$themeSelect = this.$widget.find(".theme-select"); |         this.$themeSelect = this.$widget.find(".theme-select"); | ||||||
|  |  | ||||||
|         // Populate the list of themes. |         // Populate the list of themes. | ||||||
|         for (const [ id, theme ] of Object.entries(Themes)) { |         const themeGroups = groupThemesByLightOrDark(); | ||||||
|  |         for (const [key, themes] of Object.entries(themeGroups)) { | ||||||
|  |             const $group = key ? $("<optgroup>").attr("label", key) : null; | ||||||
|  |  | ||||||
|  |             for (const [id, theme] of Object.entries(themes)) { | ||||||
|                 const option = $("<option>") |                 const option = $("<option>") | ||||||
|                 .attr("value", `default:${id}`) |                     .attr("value", "default:" + id) | ||||||
|                     .text(theme.name); |                     .text(theme.name); | ||||||
|  |  | ||||||
|  |                 if ($group) { | ||||||
|  |                     $group.append(option); | ||||||
|  |                 } else { | ||||||
|                     this.$themeSelect.append(option); |                     this.$themeSelect.append(option); | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|  |             if ($group) { | ||||||
|  |                 this.$themeSelect.append($group); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         this.$themeSelect.on("change", async () => { |         this.$themeSelect.on("change", async () => { | ||||||
|             const newTheme = String(this.$themeSelect.val()); |             const newTheme = String(this.$themeSelect.val()); | ||||||
|             loadHighlightingTheme(newTheme); |             loadHighlightingTheme(newTheme); | ||||||
| @@ -113,3 +128,21 @@ export default class CodeBlockOptions extends OptionsWidget { | |||||||
|         this.#setupPreview(options.codeBlockTheme !== "none"); |         this.#setupPreview(options.codeBlockTheme !== "none"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function groupThemesByLightOrDark() { | ||||||
|  |     const darkThemes: Record<string, Theme> = {}; | ||||||
|  |     const lightThemes: Record<string, Theme> = {}; | ||||||
|  |  | ||||||
|  |     for (const [ id, theme ] of Object.entries(Themes)) { | ||||||
|  |         if (theme.name.includes("Dark")) { | ||||||
|  |             darkThemes[id] = theme; | ||||||
|  |         } else { | ||||||
|  |             lightThemes[id] = theme; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const output: Record<string, Record<string, Theme>> = {}; | ||||||
|  |     output[t("code_block.theme_group_light")] = lightThemes; | ||||||
|  |     output[t("code_block.theme_group_dark")] = darkThemes; | ||||||
|  |     return output; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -193,11 +193,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "搜索:" |     "search_prefix": "搜索:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "无语法高亮", |  | ||||||
|     "theme_group_light": "浅色主题", |  | ||||||
|     "theme_group_dark": "深色主题" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "同步服务器主机未配置。请先配置同步。", |     "not-configured": "同步服务器主机未配置。请先配置同步。", | ||||||
|     "successful": "同步服务器握手成功,同步已开始。" |     "successful": "同步服务器握手成功,同步已开始。" | ||||||
|   | |||||||
| @@ -185,11 +185,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Suche:" |     "search_prefix": "Suche:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "Keine Syntax-Hervorhebung", |  | ||||||
|     "theme_group_light": "Helle Themen", |  | ||||||
|     "theme_group_dark": "Dunkle Themen" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "Der Synchronisations-Server-Host ist nicht konfiguriert. Bitte konfiguriere zuerst die Synchronisation.", |     "not-configured": "Der Synchronisations-Server-Host ist nicht konfiguriert. Bitte konfiguriere zuerst die Synchronisation.", | ||||||
|     "successful": "Die Server-Verbindung wurde erfolgreich hergestellt, die Synchronisation wurde gestartet." |     "successful": "Die Server-Verbindung wurde erfolgreich hergestellt, die Synchronisation wurde gestartet." | ||||||
|   | |||||||
| @@ -193,11 +193,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Search:" |     "search_prefix": "Search:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "No syntax highlighting", |  | ||||||
|     "theme_group_light": "Light themes", |  | ||||||
|     "theme_group_dark": "Dark themes" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "Sync server host is not configured. Please configure sync first.", |     "not-configured": "Sync server host is not configured. Please configure sync first.", | ||||||
|     "successful": "Sync server handshake has been successful, sync has been started." |     "successful": "Sync server handshake has been successful, sync has been started." | ||||||
|   | |||||||
| @@ -189,11 +189,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Buscar:" |     "search_prefix": "Buscar:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "Sin resaltado de sintaxis", |  | ||||||
|     "theme_group_light": "Temas claros", |  | ||||||
|     "theme_group_dark": "Temas oscuros" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "El servidor de sincronización no está configurado. Por favor configure primero la sincronización.", |     "not-configured": "El servidor de sincronización no está configurado. Por favor configure primero la sincronización.", | ||||||
|     "successful": "El protocolo de enlace del servidor de sincronización ha sido exitoso, la sincronización ha comenzado." |     "successful": "El protocolo de enlace del servidor de sincronización ha sido exitoso, la sincronización ha comenzado." | ||||||
|   | |||||||
| @@ -189,11 +189,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Recherche :" |     "search_prefix": "Recherche :" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "Pas de coloration syntaxique", |  | ||||||
|     "theme_group_light": "Thèmes clairs", |  | ||||||
|     "theme_group_dark": "Thèmes sombres" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "L'hôte du serveur de synchronisation n'est pas configuré. Veuillez d'abord configurer la synchronisation.", |     "not-configured": "L'hôte du serveur de synchronisation n'est pas configuré. Veuillez d'abord configurer la synchronisation.", | ||||||
|     "successful": "L'établissement de liaison du serveur de synchronisation a été réussi, la synchronisation a été démarrée." |     "successful": "L'établissement de liaison du serveur de synchronisation a été réussi, la synchronisation a été démarrée." | ||||||
|   | |||||||
| @@ -186,11 +186,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Pesquisar:" |     "search_prefix": "Pesquisar:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "Sem destaque de sintaxe", |  | ||||||
|     "theme_group_light": "Temas claros", |  | ||||||
|     "theme_group_dark": "Temas escuros" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "O host do servidor de sincronização não está configurado. Por favor, configure a sincronização primeiro.", |     "not-configured": "O host do servidor de sincronização não está configurado. Por favor, configure a sincronização primeiro.", | ||||||
|     "successful": "A comunicação com o servidor de sincronização foi bem-sucedida, a sincronização foi iniciada." |     "successful": "A comunicação com o servidor de sincronização foi bem-sucedida, a sincronização foi iniciada." | ||||||
|   | |||||||
| @@ -189,11 +189,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "Căutare:" |     "search_prefix": "Căutare:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "Fără evidențiere de sintaxă", |  | ||||||
|     "theme_group_dark": "Teme întunecate", |  | ||||||
|     "theme_group_light": "Teme luminoase" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "Calea către serverul de sincronizare nu este configurată. Configurați sincronizarea înainte.", |     "not-configured": "Calea către serverul de sincronizare nu este configurată. Configurați sincronizarea înainte.", | ||||||
|     "successful": "Comunicarea cu serverul de sincronizare a avut loc cu succes, s-a început sincronizarea." |     "successful": "Comunicarea cu serverul de sincronizare a avut loc cu succes, s-a început sincronizarea." | ||||||
|   | |||||||
| @@ -185,11 +185,6 @@ | |||||||
|   "special_notes": { |   "special_notes": { | ||||||
|     "search_prefix": "搜尋:" |     "search_prefix": "搜尋:" | ||||||
|   }, |   }, | ||||||
|   "code_block": { |  | ||||||
|     "theme_none": "無格式高亮", |  | ||||||
|     "theme_group_light": "淺色主題", |  | ||||||
|     "theme_group_dark": "深色主題" |  | ||||||
|   }, |  | ||||||
|   "test_sync": { |   "test_sync": { | ||||||
|     "not-configured": "並未設定同步伺服器主機,請先設定同步", |     "not-configured": "並未設定同步伺服器主機,請先設定同步", | ||||||
|     "successful": "成功與同步伺服器握手,現在開始同步" |     "successful": "成功與同步伺服器握手,現在開始同步" | ||||||
|   | |||||||
| @@ -1,22 +0,0 @@ | |||||||
| import { describe, expect, it } from "vitest"; |  | ||||||
| import { readThemesFromFileSystem } from "./code_block_theme.js"; |  | ||||||
|  |  | ||||||
| import themeNames from "./code_block_theme_names.json" with { type: "json" }; |  | ||||||
| import path = require("path"); |  | ||||||
|  |  | ||||||
| describe("Code block theme", () => { |  | ||||||
|     it("all themes are mapped", () => { |  | ||||||
|         const themes = readThemesFromFileSystem(path.join(__dirname, "../../node_modules/@highlightjs/cdn-assets/styles")); |  | ||||||
|  |  | ||||||
|         const mappedThemeNames = new Set(Object.values(themeNames)); |  | ||||||
|         const unmappedThemeNames = new Set<string>(); |  | ||||||
|  |  | ||||||
|         for (const theme of themes) { |  | ||||||
|             if (!mappedThemeNames.has(theme.title)) { |  | ||||||
|                 unmappedThemeNames.add(theme.title); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         expect(unmappedThemeNames.size, `Unmapped themes: ${Array.from(unmappedThemeNames).join(", ")}`).toBe(0); |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
| @@ -1,102 +0,0 @@ | |||||||
| /** |  | ||||||
|  * @module |  | ||||||
|  * |  | ||||||
|  * Manages the server-side functionality of the code blocks feature, mostly for obtaining the available themes for syntax highlighting. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| import fs from "fs"; |  | ||||||
| import { t } from "i18next"; |  | ||||||
| import { join } from "path"; |  | ||||||
| import { isDev, isElectron, getResourceDir } from "./utils.js"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Represents a color scheme for the code block syntax highlight. |  | ||||||
|  */ |  | ||||||
| interface ColorTheme { |  | ||||||
|     /** The ID of the color scheme which should be stored in the options. */ |  | ||||||
|     val: string; |  | ||||||
|     /** A user-friendly name of the theme. The name is already localized. */ |  | ||||||
|     title: string; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Returns all the supported syntax highlighting themes for code blocks, in groups. |  | ||||||
|  * |  | ||||||
|  * The return value is an object where the keys represent groups in their human-readable name (e.g. "Light theme") |  | ||||||
|  * and the values are an array containing the information about every theme. There is also a special group with no |  | ||||||
|  * title (empty string) which should be displayed at the top of the listing pages, without a group. |  | ||||||
|  * |  | ||||||
|  * @returns the supported themes, grouped. |  | ||||||
|  */ |  | ||||||
| export function listSyntaxHighlightingThemes() { |  | ||||||
|     const path = getStylesDirectory(); |  | ||||||
|     const systemThemes = readThemesFromFileSystem(path); |  | ||||||
|  |  | ||||||
|     return { |  | ||||||
|         "": [ |  | ||||||
|             { |  | ||||||
|                 val: "none", |  | ||||||
|                 title: t("code_block.theme_none") |  | ||||||
|             } |  | ||||||
|         ], |  | ||||||
|         ...groupThemesByLightOrDark(systemThemes) |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function getStylesDirectory() { |  | ||||||
|     if (isElectron && !isDev) { |  | ||||||
|         return join(getResourceDir(), "styles"); |  | ||||||
|     } else if (!isDev) { |  | ||||||
|         return join(getResourceDir(), "node_modules/@highlightjs/cdn-assets/styles"); |  | ||||||
|     } else { |  | ||||||
|         return join(__dirname, "../node_modules/@highlightjs/cdn-assets/styles"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Reads all the predefined themes by listing all minified CSSes from a given directory. |  | ||||||
|  * |  | ||||||
|  * The theme names are mapped against a known list in order to provide more descriptive names such as "Visual Studio 2015 (Dark)" instead of "vs2015". |  | ||||||
|  * |  | ||||||
|  * @param path the path to read from. Usually this is the highlight.js `styles` directory. |  | ||||||
|  * @returns the list of themes. |  | ||||||
|  */ |  | ||||||
| export function readThemesFromFileSystem(path: string): ColorTheme[] { |  | ||||||
|     return fs |  | ||||||
|         .readdirSync(path) |  | ||||||
|         .filter((el) => el.endsWith(".min.css")) |  | ||||||
|         .map((name) => { |  | ||||||
|             const nameWithoutExtension = name.replace(".min.css", ""); |  | ||||||
|             let title = nameWithoutExtension.replace(/-/g, " "); |  | ||||||
|  |  | ||||||
|             return { |  | ||||||
|                 val: `default:${nameWithoutExtension}`, |  | ||||||
|                 title: title |  | ||||||
|             }; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Groups a list of themes by dark or light themes. This is done simply by checking whether "Dark" is present in the given theme, otherwise it's considered a light theme. |  | ||||||
|  * This generally only works if the theme has a known human-readable name (see {@link #readThemesFromFileSystem()}) |  | ||||||
|  * |  | ||||||
|  * @param listOfThemes the list of themes to be grouped. |  | ||||||
|  * @returns the grouped themes by light or dark. |  | ||||||
|  */ |  | ||||||
| function groupThemesByLightOrDark(listOfThemes: ColorTheme[]) { |  | ||||||
|     const darkThemes = []; |  | ||||||
|     const lightThemes = []; |  | ||||||
|  |  | ||||||
|     for (const theme of listOfThemes) { |  | ||||||
|         if (theme.title.includes("Dark")) { |  | ||||||
|             darkThemes.push(theme); |  | ||||||
|         } else { |  | ||||||
|             lightThemes.push(theme); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const output: Record<string, ColorTheme[]> = {}; |  | ||||||
|     output[t("code_block.theme_group_light")] = lightThemes; |  | ||||||
|     output[t("code_block.theme_group_dark")] = darkThemes; |  | ||||||
|     return output; |  | ||||||
| } |  | ||||||
| @@ -4,7 +4,7 @@ import syntaxDefinitions from "./syntax_highlighting.js"; | |||||||
| import { type Theme } from "./themes.js"; | import { type Theme } from "./themes.js"; | ||||||
| import { type HighlightOptions } from "highlight.js"; | import { type HighlightOptions } from "highlight.js"; | ||||||
|  |  | ||||||
| export { default as Themes } from "./themes.js"; | export { default as Themes, type Theme } from "./themes.js"; | ||||||
|  |  | ||||||
| const registeredMimeTypes = new Set<string>(); | const registeredMimeTypes = new Set<string>(); | ||||||
| const unsupportedMimeTypes = new Set<string>(); | const unsupportedMimeTypes = new Set<string>(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user