From 8c271c5159ca153c01145771e034f61c84ec1cea Mon Sep 17 00:00:00 2001 From: Darren Hoo Date: Thu, 25 Sep 2025 12:16:22 +0800 Subject: [PATCH 1/3] Support for Rendering Excalidraw Diagrams While issue #28903 explored integrating Draw.io, @lunny suggested in a https://github.com/go-gitea/gitea/issues/28903#issuecomment-1918468021 that Excalidraw would be a better alternative. The primary reasons are its MIT license and its ease of integration into Gitea. The recommended approach is to implement this as a plugin after the work in #34917 is completed. Key Changes: * Markdown Rendering: - The Markdown renderer now recognizes excalidraw as a language identifier in code blocks, similar to mermaid. * Configuration: - A new setting `EXCALIDRAW_MAX_SOURCE_CHARACTERS` has been added to control the maximum size of Excalidraw source data. * Dependencies: - The `@excalidraw/utils` package has been added to package.json to handle Excalidraw data processing. * Frontend Features: - A new file view plugin (`excalidraw-view.ts`) is added to render .excalidraw files directly. - The markup content handling (`content.ts`) now initializes Excalidraw rendering for embedded diagrams. - A new module (`excalidraw.ts`) is created to handle the logic of rendering Excalidraw JSON from code blocks into SVG images, including dark mode support. - The main file view feature (`file-view.ts`) now includes the Excalidraw viewer plugin. --- modules/markup/markdown/markdown.go | 2 +- modules/setting/markup.go | 8 +- package.json | 1 + web_src/js/features/file-view.ts | 3 +- web_src/js/markup/content.ts | 2 + web_src/js/markup/excalidraw.ts | 79 ++++++++++++++++++++ web_src/js/render/plugins/excalidraw-view.ts | 33 ++++++++ 7 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 web_src/js/markup/excalidraw.ts create mode 100644 web_src/js/render/plugins/excalidraw-view.ts diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 3b788432bac8d..ca4bc51aa8f75 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -82,7 +82,7 @@ func (r *GlodmarkRender) highlightingRenderer(w util.BufWriter, c highlighting.C languageStr := giteautil.IfZero(string(languageBytes), "text") preClasses := "code-block" - if languageStr == "mermaid" || languageStr == "math" { + if languageStr == "mermaid" || languageStr == "math" || languageStr == "excalidraw" { preClasses += " is-loading" } diff --git a/modules/setting/markup.go b/modules/setting/markup.go index 057b0650c30e3..b1f3b9b2f4c87 100644 --- a/modules/setting/markup.go +++ b/modules/setting/markup.go @@ -13,9 +13,10 @@ import ( // ExternalMarkupRenderers represents the external markup renderers var ( - ExternalMarkupRenderers []*MarkupRenderer - ExternalSanitizerRules []MarkupSanitizerRule - MermaidMaxSourceCharacters int + ExternalMarkupRenderers []*MarkupRenderer + ExternalSanitizerRules []MarkupSanitizerRule + ExcalidrawMaxSourceCharacters int + MermaidMaxSourceCharacters int ) const ( @@ -127,6 +128,7 @@ func loadMarkupFrom(rootCfg ConfigProvider) { } } + ExcalidrawMaxSourceCharacters = rootCfg.Section("markup").Key("EXCALIDRAW_MAX_SOURCE_CHARACTERS").MustInt(100000) MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(50000) ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10) ExternalSanitizerRules = make([]MarkupSanitizerRule, 0, 10) diff --git a/package.json b/package.json index 0b2ce03354575..365a3be7362fe 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "@citation-js/plugin-bibtex": "0.7.18", "@citation-js/plugin-csl": "0.7.18", "@citation-js/plugin-software-formats": "0.6.1", + "@excalidraw/utils": "0.1.3-test32", "@github/markdown-toolbar-element": "2.2.3", "@github/paste-markdown": "1.5.3", "@github/relative-time-element": "4.4.8", diff --git a/web_src/js/features/file-view.ts b/web_src/js/features/file-view.ts index 67f43814684e6..981684a36267c 100644 --- a/web_src/js/features/file-view.ts +++ b/web_src/js/features/file-view.ts @@ -1,6 +1,7 @@ import type {FileRenderPlugin} from '../render/plugin.ts'; import {newRenderPlugin3DViewer} from '../render/plugins/3d-viewer.ts'; import {newRenderPluginPdfViewer} from '../render/plugins/pdf-viewer.ts'; +import {newRenderPluginExcalidrawViewer} from '../render/plugins/excalidraw-view.ts'; import {registerGlobalInitFunc} from '../modules/observer.ts'; import {createElementFromHTML, showElem, toggleElemClass} from '../utils/dom.ts'; import {html} from '../utils/html.ts'; @@ -10,7 +11,7 @@ const plugins: FileRenderPlugin[] = []; function initPluginsOnce(): void { if (plugins.length) return; - plugins.push(newRenderPlugin3DViewer(), newRenderPluginPdfViewer()); + plugins.push(newRenderPlugin3DViewer(), newRenderPluginPdfViewer(), newRenderPluginExcalidrawViewer()); } function findFileRenderPlugin(filename: string, mimeType: string): FileRenderPlugin | null { diff --git a/web_src/js/markup/content.ts b/web_src/js/markup/content.ts index 55db4aa8102b3..217e594effef8 100644 --- a/web_src/js/markup/content.ts +++ b/web_src/js/markup/content.ts @@ -1,4 +1,5 @@ import {initMarkupCodeMermaid} from './mermaid.ts'; +import {initMarkupCodeExcalidraw} from './excalidraw.ts'; import {initMarkupCodeMath} from './math.ts'; import {initMarkupCodeCopy} from './codecopy.ts'; import {initMarkupRenderAsciicast} from './asciicast.ts'; @@ -12,6 +13,7 @@ export function initMarkupContent(): void { initMarkupTasklist(el); initMarkupCodeMermaid(el); initMarkupCodeMath(el); + initMarkupCodeExcalidraw(el); initMarkupRenderAsciicast(el); }); } diff --git a/web_src/js/markup/excalidraw.ts b/web_src/js/markup/excalidraw.ts new file mode 100644 index 0000000000000..d49d3145ffb74 --- /dev/null +++ b/web_src/js/markup/excalidraw.ts @@ -0,0 +1,79 @@ +import {isDarkTheme} from '../utils.ts'; +import {makeCodeCopyButton} from './codecopy.ts'; +import {displayError} from './common.ts'; +import {queryElems} from '../utils/dom.ts'; +import {html, htmlRaw} from '../utils/html.ts'; + +const {excalidrawMaxSourceCharacters} = window.config; + +const iframeCss = `body { margin: 0; } svg { max-width: 100%; height: auto; }`; + +export async function initMarkupCodeExcalidraw(elMarkup: HTMLElement): Promise { + queryElems(elMarkup, 'code.language-excalidraw', async (el) => { + const {exportToSvg} = await import(/* webpackChunkName: "excalidraw/utils" */ '@excalidraw/utils'); + + const pre = el.closest('pre'); + if (pre.hasAttribute('data-render-done')) return; + + const source = el.textContent; + if (excalidrawMaxSourceCharacters >= 0 && source.length > excalidrawMaxSourceCharacters) { + displayError(pre, new Error(`Excalidraw source of ${source.length} characters exceeds the maximum allowed length of ${excalidrawMaxSourceCharacters}.`)); + return; + } + + let excalidrawJson; + try { + excalidrawJson = JSON.parse(source); + } catch (err) { + displayError(pre, new Error(`Invalid Excalidraw JSON: ${err}`)); + return; + } + + try { + const svg = await exportToSvg({ + elements: excalidrawJson.elements, + appState: { + ...excalidrawJson.appState, + exportWithDarkMode: isDarkTheme(), + }, + files: excalidrawJson.files, + skipInliningFonts: true, + }); + const iframe = document.createElement('iframe'); + iframe.classList.add('markup-content-iframe', 'tw-invisible'); + iframe.srcdoc = html`${htmlRaw(svg.outerHTML)}`; + + const excalidrawBlock = document.createElement('div'); + excalidrawBlock.classList.add('excalidraw-block', 'is-loading', 'tw-hidden'); + excalidrawBlock.append(iframe); + + const btn = makeCodeCopyButton(); + btn.setAttribute('data-clipboard-text', source); + excalidrawBlock.append(btn); + + const updateIframeHeight = () => { + const body = iframe.contentWindow?.document?.body; + if (body) { + iframe.style.height = `${body.clientHeight}px`; + } + }; + iframe.addEventListener('load', () => { + pre.replaceWith(excalidrawBlock); + excalidrawBlock.classList.remove('tw-hidden'); + updateIframeHeight(); + setTimeout(() => { // avoid flash of iframe background + excalidrawBlock.classList.remove('is-loading'); + iframe.classList.remove('tw-invisible'); + }, 0); + + (new IntersectionObserver(() => { + updateIframeHeight(); + }, {root: document.documentElement})).observe(iframe); + }); + + document.body.append(excalidrawBlock); + } catch (err) { + displayError(pre, err); + } + }); +} diff --git a/web_src/js/render/plugins/excalidraw-view.ts b/web_src/js/render/plugins/excalidraw-view.ts new file mode 100644 index 0000000000000..148a63895ef16 --- /dev/null +++ b/web_src/js/render/plugins/excalidraw-view.ts @@ -0,0 +1,33 @@ +import type {FileRenderPlugin} from '../plugin.ts'; +import {isDarkTheme} from '../../utils.ts'; +import {request} from '../../modules/fetch.ts'; + +export function newRenderPluginExcalidrawViewer(): FileRenderPlugin { + return { + name: 'excalidraw-viewer', + + canHandle(filename: string, _mimeType: string): boolean { + return filename.toLowerCase().endsWith('.excalidraw'); + }, + + async render(container: HTMLElement, fileUrl: string): Promise { + const {exportToSvg} = await import(/* webpackChunkName: "excalidraw/utils" */ '@excalidraw/utils'); + const data = await request(fileUrl); + const excalidrawJson = await data.json(); + const svg = await exportToSvg({ + elements: excalidrawJson.elements, + appState: { + ...excalidrawJson.appState, + exportWithDarkMode: isDarkTheme(), + }, + files: excalidrawJson.files, + skipInliningFonts: true, + }); + container.style.display = 'flex'; + container.style.justifyContent = 'center'; + svg.style.maxWidth = '80%'; + svg.style.height = 'auto'; + container.append(svg); + }, + }; +} From e2287d9f0d8bed97fee2907390a1968824a7f1d9 Mon Sep 17 00:00:00 2001 From: Darren Hoo Date: Thu, 25 Sep 2025 12:26:06 +0800 Subject: [PATCH 2/3] Sync pnpm-lock.yaml with package.json --- pnpm-lock.yaml | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5d40acd101921..9f8433a4c58c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: '@citation-js/plugin-software-formats': specifier: 0.6.1 version: 0.6.1 + '@excalidraw/utils': + specifier: 0.1.3-test32 + version: 0.1.3-test32 '@github/markdown-toolbar-element': specifier: 2.2.3 version: 2.2.3 @@ -383,6 +386,9 @@ packages: resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@braintree/sanitize-url@6.0.2': + resolution: {integrity: sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==} + '@braintree/sanitize-url@7.1.1': resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} @@ -697,6 +703,12 @@ packages: resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@excalidraw/laser-pointer@1.3.1': + resolution: {integrity: sha512-psA1z1N2qeAfsORdXc9JmD2y4CmDwmuMRxnNdJHZexIcPwaNEyIpNcelw+QkL9rz9tosaN9krXuKaRqYpRAR6g==} + + '@excalidraw/utils@0.1.3-test32': + resolution: {integrity: sha512-xOXYkkR6bRneoW4in5Ha5Iz2PyS9R9vPpzW7jcTOEE1ae9D5cz5hwBT8BxXfGKWp+YTCyHRHIJaa0ZhlW4H5nQ==} + '@github/browserslist-config@1.0.0': resolution: {integrity: sha512-gIhjdJp/c2beaIWWIlsXdqXVRUz3r2BxBCpfz/F3JXHvSAQ1paMYjLH+maEATtENg+k5eLV7gA+9yPp762ieuw==} @@ -1859,6 +1871,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browser-fs-access@0.29.1: + resolution: {integrity: sha512-LSvVX5e21LRrXqVMhqtAwj5xPgDb+fXAIH80NsnCQ9xuZPs2xWsOREi24RKgZa1XOiQRbcmVrv87+ulOKsgjxw==} + browserslist@4.25.4: resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -2070,6 +2085,10 @@ packages: typescript: optional: true + crc-32@0.3.0: + resolution: {integrity: sha512-kucVIjOmMc1f0tv53BJ/5WIX+MGLcKuoBhnGqQrgKJNqLByb/sVMWfW/Aw6hw0jgcqjJ2pi9E5y32zOIpaUlsA==} + engines: {node: '>=0.8'} + cropperjs@1.6.2: resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==} @@ -3610,6 +3629,9 @@ packages: online-3d-viewer@0.16.0: resolution: {integrity: sha512-Mcmo41TM3K+svlMDRH8ySKSY2e8s7Sssdb5U9LV3gkFKVWGGuS304Vk5gqxopAJbE72DpsC67Ve3YNtcAuROwQ==} + open-color@1.9.1: + resolution: {integrity: sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3640,6 +3662,9 @@ packages: package-manager-detector@1.3.0: resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + pako@2.0.3: + resolution: {integrity: sha512-WjR1hOeg+kki3ZIOjaf4b5WVcay1jaliKSYiEaB1XzwhMQZJxRdQRv0V31EKBYlxb4T7SK3hjfc/jxyU64BoSw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3697,6 +3722,9 @@ packages: perfect-debounce@2.0.0: resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} + perfect-freehand@1.2.0: + resolution: {integrity: sha512-h/0ikF1M3phW7CwpZ5MMvKnfpHficWoOEyr//KVNTxV4F6deRK1eYMtHyBKEAKFK0aXIEUK9oBvlF6PNXMDsAw==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3740,6 +3768,15 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + png-chunk-text@1.0.0: + resolution: {integrity: sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==} + + png-chunks-encode@1.0.0: + resolution: {integrity: sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA==} + + png-chunks-extract@1.0.0: + resolution: {integrity: sha512-ZiVwF5EJ0DNZyzAqld8BP1qyJBaGOFaq9zl579qfbkcmOwWLLO4I9L8i2O4j3HkI6/35i0nKG2n+dZplxiT89Q==} + points-on-curve@0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} @@ -3978,6 +4015,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + roughjs@4.6.4: + resolution: {integrity: sha512-s6EZ0BntezkFYMf/9mGn7M8XGIoaav9QQBCnJROWB3brUWQ683Q2LbRD/hq0Z3bAJ/9NVpU/5LpiTWvQMyLDhw==} + roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} @@ -4061,6 +4101,9 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} + sliced@1.0.1: + resolution: {integrity: sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==} + smol-toml@1.3.4: resolution: {integrity: sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==} engines: {node: '>= 18'} @@ -4750,6 +4793,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@braintree/sanitize-url@6.0.2': {} + '@braintree/sanitize-url@7.1.1': {} '@chevrotain/cst-dts-gen@11.0.3': @@ -4994,6 +5039,21 @@ snapshots: '@eslint/core': 0.15.2 levn: 0.4.1 + '@excalidraw/laser-pointer@1.3.1': {} + + '@excalidraw/utils@0.1.3-test32': + dependencies: + '@braintree/sanitize-url': 6.0.2 + '@excalidraw/laser-pointer': 1.3.1 + browser-fs-access: 0.29.1 + open-color: 1.9.1 + pako: 2.0.3 + perfect-freehand: 1.2.0 + png-chunk-text: 1.0.0 + png-chunks-encode: 1.0.0 + png-chunks-extract: 1.0.0 + roughjs: 4.6.4 + '@github/browserslist-config@1.0.0': {} '@github/combobox-nav@2.3.1': {} @@ -6313,6 +6373,8 @@ snapshots: dependencies: fill-range: 7.1.1 + browser-fs-access@0.29.1: {} + browserslist@4.25.4: dependencies: caniuse-lite: 1.0.30001741 @@ -6507,6 +6569,8 @@ snapshots: optionalDependencies: typescript: 5.9.2 + crc-32@0.3.0: {} + cropperjs@1.6.2: {} cross-spawn@7.0.6: @@ -8226,6 +8290,8 @@ snapshots: fflate: 0.8.2 three: 0.176.0 + open-color@1.9.1: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -8257,6 +8323,8 @@ snapshots: package-manager-detector@1.3.0: {} + pako@2.0.3: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -8310,6 +8378,8 @@ snapshots: perfect-debounce@2.0.0: {} + perfect-freehand@1.2.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -8346,6 +8416,17 @@ snapshots: pluralize@8.0.0: {} + png-chunk-text@1.0.0: {} + + png-chunks-encode@1.0.0: + dependencies: + crc-32: 0.3.0 + sliced: 1.0.1 + + png-chunks-extract@1.0.0: + dependencies: + crc-32: 0.3.0 + points-on-curve@0.2.0: {} points-on-path@0.2.1: @@ -8570,6 +8651,13 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.50.1 fsevents: 2.3.3 + roughjs@4.6.4: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + roughjs@4.6.6: dependencies: hachure-fill: 0.5.2 @@ -8649,6 +8737,8 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + sliced@1.0.1: {} + smol-toml@1.3.4: {} solid-js@1.9.9: From 029b86871a9c4ea46b35b203a8cd81d296e7ee36 Mon Sep 17 00:00:00 2001 From: Darren Hoo Date: Thu, 25 Sep 2025 12:35:38 +0800 Subject: [PATCH 3/3] Rename to excalidraw-viewer.ts --- web_src/js/features/file-view.ts | 2 +- .../render/plugins/{excalidraw-view.ts => excalidraw-viewer.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename web_src/js/render/plugins/{excalidraw-view.ts => excalidraw-viewer.ts} (100%) diff --git a/web_src/js/features/file-view.ts b/web_src/js/features/file-view.ts index 981684a36267c..3b5edd92c147c 100644 --- a/web_src/js/features/file-view.ts +++ b/web_src/js/features/file-view.ts @@ -1,7 +1,7 @@ import type {FileRenderPlugin} from '../render/plugin.ts'; import {newRenderPlugin3DViewer} from '../render/plugins/3d-viewer.ts'; import {newRenderPluginPdfViewer} from '../render/plugins/pdf-viewer.ts'; -import {newRenderPluginExcalidrawViewer} from '../render/plugins/excalidraw-view.ts'; +import {newRenderPluginExcalidrawViewer} from '../render/plugins/excalidraw-viewer.ts'; import {registerGlobalInitFunc} from '../modules/observer.ts'; import {createElementFromHTML, showElem, toggleElemClass} from '../utils/dom.ts'; import {html} from '../utils/html.ts'; diff --git a/web_src/js/render/plugins/excalidraw-view.ts b/web_src/js/render/plugins/excalidraw-viewer.ts similarity index 100% rename from web_src/js/render/plugins/excalidraw-view.ts rename to web_src/js/render/plugins/excalidraw-viewer.ts