collabmd 0.1.44 → 0.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{chunk-AXR3VHVW-0GTk_evH.js → chunk-ERSWUTIN-ME9RVNel.js} +3 -3
- package/dist/client/assets/{chunk-CZQZEIFA-DT3N9fo7.js → chunk-YGJVY4SA-CjSe7Bx7.js} +2 -2
- package/dist/client/assets/{comment-threads-D-iKphIp.js → comment-threads-DDegmaFO.js} +1 -1
- package/dist/client/assets/drawio-editor-ClE8jpoG.js +9 -0
- package/dist/client/assets/drawioEditor-CXaTM9Ds.js +2 -0
- package/dist/client/assets/editor-session-GTwZS6Df.js +16 -0
- package/dist/client/assets/embedded-editor-base-CiNEc8vy.css +1 -0
- package/dist/client/assets/{en-GADW4C6J-DQ6zyCEM.js → en-7NFCYGKX-BrgYZAEe.js} +1 -1
- package/dist/client/assets/{excalidraw-editor-BHu6k8d4.js → excalidraw-editor-BZVM81BO.js} +2 -2
- package/dist/client/assets/excalidraw-editor-CyGwOhLz.css +1 -0
- package/dist/client/assets/excalidraw-scene-C8n9CHsK.js +176 -0
- package/dist/client/assets/excalidrawEditor-DxJanCze.js +2 -0
- package/dist/client/assets/export-page-CUfws2T-.js +39 -0
- package/dist/client/assets/exportDocument-BCuxqXDY.js +2 -0
- package/dist/client/assets/exportDocument-DV-OX74E.css +1 -0
- package/dist/client/assets/image-QXRYHUNP-lfTHE3bb.js +1 -0
- package/dist/client/assets/index-C3YnUgMD.css +1 -0
- package/dist/client/assets/index-D2wXraJ1.js +2 -0
- package/dist/client/assets/main-DtiGz7uI.js +795 -0
- package/dist/client/assets/modulepreload-polyfill-P2Xu9kJm.js +1 -0
- package/dist/client/assets/preview-diagram-utils-txBCoW8d.js +1 -0
- package/dist/client/assets/quick-switcher-controller-shW_6vPY.js +12 -0
- package/dist/client/assets/room-CQLoqtMo.js +1 -0
- package/dist/client/assets/runtime-config-DSGmGE9V.js +1 -0
- package/dist/client/assets/vault-api-client-C6bcGwy-.js +5 -0
- package/dist/client/assets/{yjs-provider-reset-guard-Cox4nxwu.js → yjs-provider-reset-guard-DE0vINDP.js} +1 -1
- package/dist/client/drawio-editor.html +3 -2
- package/dist/client/excalidraw-editor.html +3 -2
- package/dist/client/export-document.html +4 -3
- package/dist/client/index.html +97 -27
- package/package.json +10 -12
- package/src/client/app/drawio-editor-entry.js +0 -3
- package/src/client/app/drawio-editor.html +1 -0
- package/src/client/app/excalidraw-editor-entry.js +0 -3
- package/src/client/app/excalidraw-editor.html +1 -0
- package/src/client/app/export-document-entry.js +0 -3
- package/src/client/app/export-document.html +1 -0
- package/src/client/app/index.html +94 -24
- package/src/client/app/main-entry.js +0 -5
- package/src/client/application/app-shell/chat-feature.js +180 -124
- package/src/client/application/app-shell/comments-feature.js +1 -1
- package/src/client/application/app-shell/git-feature.js +4 -9
- package/src/client/application/app-shell/presence-feature.js +16 -10
- package/src/client/application/app-shell/ui-feature-shell.js +33 -15
- package/src/client/application/app-shell/ui-feature-sidebar.js +74 -1
- package/src/client/application/app-shell/ui-feature-tab-activity.js +2 -2
- package/src/client/application/app-shell/workspace-feature.js +22 -83
- package/src/client/application/app-shell-elements.js +7 -1
- package/src/client/application/diagram-chrome.js +161 -166
- package/src/client/application/diagram-preview-export.js +7 -34
- package/src/client/application/diagram-preview-hydrator.js +1 -19
- package/src/client/application/markdown-frontmatter.js +0 -2
- package/src/client/application/mermaid-preview-hydrator.js +1 -14
- package/src/client/application/plantuml-preview-hydrator.js +0 -10
- package/src/client/application/preview-diagram-utils.js +31 -2
- package/src/client/application/preview-render-compiler.js +2 -1
- package/src/client/application/preview-renderer.js +2 -2
- package/src/client/application/quick-switcher-loader.js +3 -1
- package/src/client/application/workspace-preview-controller.js +0 -3
- package/src/client/bootstrap/collabmd-app-shell.js +125 -39
- package/src/client/domain/excalidraw-collaboration.js +0 -2
- package/src/client/domain/room.js +38 -0
- package/src/client/export/export-pipeline.js +6 -34
- package/src/client/infrastructure/auth-client.js +4 -10
- package/src/client/infrastructure/browser-notification-port.js +33 -20
- package/src/client/infrastructure/browser-preferences-port.js +36 -9
- package/src/client/infrastructure/editor-view-adapter.js +87 -3
- package/src/client/infrastructure/lobby-presence.js +1 -0
- package/src/client/infrastructure/vault-api-client.js +25 -0
- package/src/client/infrastructure/workspace-sync-client.js +13 -1
- package/src/client/presentation/comment-overview-controller.js +18 -53
- package/src/client/presentation/comment-ui/comment-ui-card.js +1 -12
- package/src/client/presentation/comment-ui/comment-ui-layout.js +242 -219
- package/src/client/presentation/comment-ui/comment-ui-render.js +32 -45
- package/src/client/presentation/comment-ui/comment-ui-shared.js +65 -14
- package/src/client/presentation/comment-ui-controller.js +5 -1
- package/src/client/presentation/file-action-controller.js +32 -0
- package/src/client/presentation/file-explorer-controller.js +33 -3
- package/src/client/presentation/file-explorer-view.js +49 -5
- package/src/client/presentation/file-tree-state.js +10 -4
- package/src/client/presentation/quick-switcher-controller.js +243 -72
- package/src/client/presentation/quick-switcher-text-search.js +2 -2
- package/src/client/presentation/toast-controller.js +3 -0
- package/src/client/styles/components/feedback.css +6 -0
- package/src/client/styles/features/collaboration-chat.css +49 -53
- package/src/client/styles/features/collaboration-presence.css +9 -7
- package/src/client/styles/features/comment-card.css +25 -11
- package/src/client/styles/features/comment-overlays.css +0 -4
- package/src/client/styles/features/comment-overview.css +44 -21
- package/src/client/styles/features/comments-drawer.css +2 -100
- package/src/client/styles/features/diagram-preview.css +5 -18
- package/src/client/styles/features/embedded-preview.css +8 -33
- package/src/client/styles/features/quick-switcher.css +8 -0
- package/src/client/styles/foundation/tokens.css +1 -0
- package/src/client/styles/layout/editor-page.css +40 -0
- package/src/client/styles/layout/responsive.css +31 -1
- package/src/client/styles/layout/shell.css +25 -6
- package/src/client/styles/layout/sidebar.css +47 -15
- package/src/client/styles/overrides/codemirror.css +217 -15
- package/src/server/application/workspace-reconciliation.js +1 -1
- package/src/server/create-app-server.js +2 -3
- package/src/server/domain/bases/base-query-service.js +1 -77
- package/src/server/domain/comment-overview.js +10 -3
- package/src/server/domain/docx-exporter.js +24 -33
- package/src/server/domain/ripgrep-search-service.js +3 -1
- package/src/server/domain/workspace-state.js +32 -11
- package/src/server/infrastructure/git/diff-service.js +24 -13
- package/src/server/infrastructure/git/git-service.js +40 -10
- package/src/server/infrastructure/git/history-service.js +42 -29
- package/src/server/infrastructure/git/path-utils.js +1 -1
- package/src/server/infrastructure/git/responses.js +0 -95
- package/src/server/infrastructure/github/github-app-client.js +22 -15
- package/src/server/infrastructure/http/create-request-handler.js +2 -8
- package/src/server/infrastructure/http/create-vault-api-command-handler.js +5 -5
- package/src/server/infrastructure/http/http-errors.js +7 -1
- package/dist/client/assets/bases-preview-controller-2pLHk0uk.js +0 -143
- package/dist/client/assets/button-BCEiw4Rw.js +0 -1
- package/dist/client/assets/diagram-action-icons-aa_KOv9h.js +0 -36
- package/dist/client/assets/drawio-editor-DDvFoarP.js +0 -9
- package/dist/client/assets/drawio-embed-controller-BD1GTRwn.js +0 -1
- package/dist/client/assets/drawioEditor-Bu5grlH5.js +0 -2
- package/dist/client/assets/editor-session-DGlpiAsK.js +0 -16
- package/dist/client/assets/embedded-editor-base-C9roKYpW.css +0 -1
- package/dist/client/assets/excalidraw-editor-Cr_184EF.css +0 -1
- package/dist/client/assets/excalidraw-embed-controller-y2fenN_g.js +0 -1
- package/dist/client/assets/excalidraw-embed-reconciler-DGiagExg.js +0 -1
- package/dist/client/assets/excalidraw-scene-BvsQ6mLP.js +0 -176
- package/dist/client/assets/excalidrawEditor-4vFE--Uw.js +0 -2
- package/dist/client/assets/export-page-Cby8JzPO.js +0 -39
- package/dist/client/assets/exportDocument-C9v-bc7I.css +0 -1
- package/dist/client/assets/exportDocument-CRHCfsdo.js +0 -2
- package/dist/client/assets/file-history-view-controller-BDjEV9xJ.js +0 -112
- package/dist/client/assets/git-diff-view-controller-DgdM1aqb.js +0 -150
- package/dist/client/assets/git-panel-controller-BDTR2HVp.js +0 -207
- package/dist/client/assets/image-XGD7JQR6-XDUWHRpO.js +0 -1
- package/dist/client/assets/index-7xOyXDhP.css +0 -1
- package/dist/client/assets/index-Bz1KuQ6y.js +0 -2
- package/dist/client/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/client/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/client/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/client/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/client/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/client/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/client/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/dist/client/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/dist/client/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/dist/client/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/dist/client/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/dist/client/assets/main-Ci07m9oP.js +0 -152
- package/dist/client/assets/preview-diagram-utils-n_bbJA9V.js +0 -1
- package/dist/client/assets/quick-switcher-controller-CoiYvllm.js +0 -12
- package/dist/client/assets/room-CDrmIdDt.js +0 -1
- package/dist/client/assets/runtime-config-CDgeuPWN.js +0 -1
- package/dist/client/assets/runtime-config-loader-BHGniHP5.js +0 -1
- package/dist/client/assets/runtime-paths-DvpihCEq.js +0 -1
- package/dist/client/assets/segmented-control-DJrHSz8M.js +0 -1
- package/dist/client/assets/vault-api-client-sLB2bo56.js +0 -1
- package/dist/client/assets/vault-paths-CVkuh0j-.js +0 -5
- package/src/client/bootstrap/lazy-controller-feature.js +0 -433
- package/src/client/infrastructure/backlinks-api-client.js +0 -16
- package/src/client/infrastructure/plantuml-api-client.js +0 -19
- package/src/client/infrastructure/runtime-config-loader.js +0 -56
- package/src/server/infrastructure/git/command-runner.js +0 -49
- package/src/server/infrastructure/git/errors.js +0 -8
- package/src/server/infrastructure/http/create-esm-proxy-handler.js +0 -130
|
@@ -8,6 +8,37 @@ export {
|
|
|
8
8
|
requestIdleRender,
|
|
9
9
|
} from '../browser-utils.js';
|
|
10
10
|
|
|
11
|
+
export function encodeSvgDataUrl(svgMarkup) {
|
|
12
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function loadImage(src) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const image = new Image();
|
|
18
|
+
image.decoding = 'async';
|
|
19
|
+
image.addEventListener('load', () => resolve(image), { once: true });
|
|
20
|
+
image.addEventListener('error', () => reject(new Error(`Failed to load image: ${src}`)), { once: true });
|
|
21
|
+
image.src = src;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveSvgDimensions(svgElement) {
|
|
26
|
+
const widthAttr = Number.parseFloat(svgElement.getAttribute('width') || '');
|
|
27
|
+
const heightAttr = Number.parseFloat(svgElement.getAttribute('height') || '');
|
|
28
|
+
const viewBoxParts = (svgElement.getAttribute('viewBox') || '')
|
|
29
|
+
.split(/\s+/u)
|
|
30
|
+
.map((value) => Number.parseFloat(value));
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
height: Number.isFinite(heightAttr) && heightAttr > 0
|
|
34
|
+
? heightAttr
|
|
35
|
+
: (Number.isFinite(viewBoxParts[3]) && viewBoxParts[3] > 0 ? viewBoxParts[3] : 800),
|
|
36
|
+
width: Number.isFinite(widthAttr) && widthAttr > 0
|
|
37
|
+
? widthAttr
|
|
38
|
+
: (Number.isFinite(viewBoxParts[2]) && viewBoxParts[2] > 0 ? viewBoxParts[2] : 1200),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
11
42
|
export function syncAttribute(target, source, name) {
|
|
12
43
|
const nextValue = source.getAttribute(name);
|
|
13
44
|
if (nextValue === null) {
|
|
@@ -62,10 +93,8 @@ export function normalizeMermaidSvg(svg) {
|
|
|
62
93
|
export function getFrameViewportSize(frame) {
|
|
63
94
|
const styles = window.getComputedStyle(frame);
|
|
64
95
|
const paddingX = Number.parseFloat(styles.paddingLeft || '0') + Number.parseFloat(styles.paddingRight || '0');
|
|
65
|
-
const paddingY = Number.parseFloat(styles.paddingTop || '0') + Number.parseFloat(styles.paddingBottom || '0');
|
|
66
96
|
|
|
67
97
|
return {
|
|
68
|
-
height: Math.max(frame.clientHeight - paddingY, 0),
|
|
69
98
|
width: Math.max(frame.clientWidth - paddingX, 0),
|
|
70
99
|
};
|
|
71
100
|
}
|
|
@@ -5,7 +5,8 @@ import { isImageAttachmentFilePath } from '../../domain/file-kind.js';
|
|
|
5
5
|
import { resolveVaultRelativePath } from '../../domain/vault-paths.js';
|
|
6
6
|
import { resolveWikiTargetPath } from '../../domain/wiki-link-resolver.js';
|
|
7
7
|
import { escapeHtml } from '../domain/vault-utils.js';
|
|
8
|
-
import { extractYamlFrontmatter
|
|
8
|
+
import { extractYamlFrontmatter } from '../../domain/yaml-frontmatter.js';
|
|
9
|
+
import { renderFrontmatterBlock } from './markdown-frontmatter.js';
|
|
9
10
|
import { analyzeMarkdownComplexity } from './preview-render-profile.js';
|
|
10
11
|
|
|
11
12
|
const DIRECT_VIDEO_MIME_TYPES = Object.freeze({
|
|
@@ -91,8 +91,8 @@ export class PreviewRenderer {
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
this.handleWindowResize = () => {
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
94
|
+
this.scheduleActiveMermaidRefit();
|
|
95
|
+
this.scheduleActivePlantUmlRefit();
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
this.diagramChrome = new DiagramChrome({
|
|
@@ -22,8 +22,10 @@ export async function ensureQuickSwitcherInstance(host) {
|
|
|
22
22
|
if (!host.quickSwitcher) {
|
|
23
23
|
host.quickSwitcher = new QuickSwitcherController({
|
|
24
24
|
getFileList: () => host.fileExplorer.flatFiles,
|
|
25
|
+
getFileMetadata: () => host.fileExplorer.fileEntries,
|
|
26
|
+
getRecentFiles: () => host.preferences?.getRecentFiles?.() ?? [],
|
|
25
27
|
getSearchConfig: () => host.runtimeConfig.search ?? {},
|
|
26
|
-
onFileSelect: (filePath) => host.handleFileSelection(filePath, {
|
|
28
|
+
onFileSelect: (filePath) => host.workspaceRouteController.handleFileSelection(filePath, {
|
|
27
29
|
closeSidebarOnMobile: true,
|
|
28
30
|
revealInTree: true,
|
|
29
31
|
}),
|
|
@@ -253,7 +253,6 @@ export class WorkspacePreviewController {
|
|
|
253
253
|
this.previewRenderer.normalizePreviewChildren(renderHost);
|
|
254
254
|
|
|
255
255
|
if (renderHost) {
|
|
256
|
-
renderHost.replaceChildren();
|
|
257
256
|
renderHost.style.minHeight = '';
|
|
258
257
|
}
|
|
259
258
|
|
|
@@ -364,8 +363,6 @@ export class WorkspacePreviewController {
|
|
|
364
363
|
return;
|
|
365
364
|
}
|
|
366
365
|
|
|
367
|
-
this.previewRenderer.scheduleActiveMermaidRefit();
|
|
368
|
-
this.previewRenderer.scheduleActivePlantUmlRefit();
|
|
369
366
|
this.videoEmbed?.syncLayout();
|
|
370
367
|
this.drawioEmbed.syncLayout();
|
|
371
368
|
this.excalidrawEmbed.syncLayout();
|
|
@@ -17,10 +17,9 @@ import { uiFeatureTabActivityMethods } from '../application/app-shell/ui-feature
|
|
|
17
17
|
import { uiFeatureToolbarMethods } from '../application/app-shell/ui-feature-toolbar.js';
|
|
18
18
|
import { workspaceFeature } from '../application/app-shell/workspace-feature.js';
|
|
19
19
|
import { LOBBY_CHAT_MESSAGE_MAX_LENGTH, LobbyPresence } from '../infrastructure/lobby-presence.js';
|
|
20
|
-
import { BrowserNotificationPort } from '../infrastructure/browser-notification-port.js';
|
|
21
20
|
import { BrowserPreferencesPort } from '../infrastructure/browser-preferences-port.js';
|
|
21
|
+
import { BrowserNotificationPort } from '../infrastructure/browser-notification-port.js';
|
|
22
22
|
import { AppVersionMonitor } from '../infrastructure/app-version-monitor.js';
|
|
23
|
-
import { backlinksApiClient } from '../infrastructure/backlinks-api-client.js';
|
|
24
23
|
import { gitApiClient } from '../infrastructure/git-api-client.js';
|
|
25
24
|
import {
|
|
26
25
|
getHashRoute,
|
|
@@ -32,7 +31,6 @@ import {
|
|
|
32
31
|
navigateToGitFilePreview,
|
|
33
32
|
navigateToGitHistory,
|
|
34
33
|
} from '../infrastructure/runtime-config.js';
|
|
35
|
-
import { plantUmlApiClient } from '../infrastructure/plantuml-api-client.js';
|
|
36
34
|
import { TabActivityLock } from '../infrastructure/tab-activity-lock.js';
|
|
37
35
|
import { vaultApiClient } from '../infrastructure/vault-api-client.js';
|
|
38
36
|
import { WorkspaceSyncClient } from '../infrastructure/workspace-sync-client.js';
|
|
@@ -40,6 +38,12 @@ import { BacklinksPanel } from '../presentation/backlinks-panel.js';
|
|
|
40
38
|
import { CommentOverviewController } from '../presentation/comment-overview-controller.js';
|
|
41
39
|
import { CommentUiController } from '../presentation/comment-ui-controller.js';
|
|
42
40
|
import { FileExplorerController } from '../presentation/file-explorer-controller.js';
|
|
41
|
+
import { FileHistoryViewController } from '../presentation/file-history-view-controller.js';
|
|
42
|
+
import { BasesPreviewController } from '../presentation/bases-preview-controller.js';
|
|
43
|
+
import { DrawioEmbedController } from '../presentation/drawio-embed-controller.js';
|
|
44
|
+
import { ExcalidrawEmbedController } from '../presentation/excalidraw-embed-controller.js';
|
|
45
|
+
import { GitDiffViewController } from '../presentation/git-diff-view-controller.js';
|
|
46
|
+
import { GitPanelController } from '../presentation/git-panel-controller.js';
|
|
43
47
|
import { LayoutController } from '../presentation/layout-controller.js';
|
|
44
48
|
import { OutlineController } from '../presentation/outline-controller.js';
|
|
45
49
|
import { ScrollSyncController } from '../presentation/scroll-sync-controller.js';
|
|
@@ -47,14 +51,12 @@ import { ThemeController } from '../presentation/theme-controller.js';
|
|
|
47
51
|
import { ToastController } from '../presentation/toast-controller.js';
|
|
48
52
|
import { VideoEmbedController } from '../presentation/video-embed-controller.js';
|
|
49
53
|
import { ImageLightboxController } from '../presentation/image-lightbox-controller.js';
|
|
50
|
-
import { lazyControllerFeature } from './lazy-controller-feature.js';
|
|
51
54
|
|
|
52
55
|
const APP_SHELL_FEATURES = [
|
|
53
56
|
chatFeature,
|
|
54
57
|
commentsFeature,
|
|
55
58
|
exportFeature,
|
|
56
59
|
gitFeature,
|
|
57
|
-
lazyControllerFeature,
|
|
58
60
|
presenceFeature,
|
|
59
61
|
{
|
|
60
62
|
...uiFeatureShellMethods,
|
|
@@ -103,18 +105,18 @@ export class CollabMdAppShell {
|
|
|
103
105
|
navigateToGitHistory,
|
|
104
106
|
};
|
|
105
107
|
this.preferences = new BrowserPreferencesPort({
|
|
106
|
-
|
|
108
|
+
fileTreeShowExtensionsKey: 'collabmd-file-tree-show-extensions',
|
|
107
109
|
lineWrappingKey: 'collabmd-editor-line-wrap',
|
|
110
|
+
recentFilesKey: 'collabmd-recent-files',
|
|
108
111
|
sidebarVisibleKey: 'collabmd-sidebar-visible',
|
|
109
112
|
userNameKey: 'collabmd-user-name',
|
|
110
113
|
});
|
|
111
114
|
this.notifications = new BrowserNotificationPort();
|
|
112
|
-
this.backlinksApiClient = backlinksApiClient;
|
|
113
115
|
this.gitApiClient = gitApiClient;
|
|
114
|
-
this.plantUmlApiClient = plantUmlApiClient;
|
|
115
116
|
this.vaultApiClient = vaultApiClient;
|
|
116
117
|
this._session = null;
|
|
117
118
|
this._hasPromptedForDisplayName = false;
|
|
119
|
+
this._basePreviewRenderTimer = null;
|
|
118
120
|
this._backlinkRefreshTimer = null;
|
|
119
121
|
this._pendingPreviewLayoutSync = false;
|
|
120
122
|
this._previewHydrationPaused = false;
|
|
@@ -124,13 +126,10 @@ export class CollabMdAppShell {
|
|
|
124
126
|
this._staticPreviewDocument = null;
|
|
125
127
|
this.pendingGitResetPath = null;
|
|
126
128
|
this.chatTimeFormatter = new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' });
|
|
127
|
-
this.chatNotificationsEnabled = this.preferences.getChatNotificationsEnabled();
|
|
128
|
-
this.chatNotificationPermission = this.notifications.getPermission();
|
|
129
129
|
this.lobbyChatMessageMaxLength = LOBBY_CHAT_MESSAGE_MAX_LENGTH;
|
|
130
130
|
this.quickSwitcher = null;
|
|
131
131
|
this.quickSwitcherModulePromise = null;
|
|
132
132
|
this.fileExplorerReadyPromise = Promise.resolve();
|
|
133
|
-
this._gitControllerPrewarmHandle = null;
|
|
134
133
|
this.mobileBreakpointQuery = window.matchMedia('(max-width: 768px)');
|
|
135
134
|
this.pendingWorkspaceRequestIds = new Set();
|
|
136
135
|
this._fileOpenPerf = null;
|
|
@@ -152,7 +151,7 @@ export class CollabMdAppShell {
|
|
|
152
151
|
this.handleCommentOverviewWorkspaceTreeChange?.();
|
|
153
152
|
this.fileExplorerReady = true;
|
|
154
153
|
if (!wasReady && this.isTabActive) {
|
|
155
|
-
void this.handleHashChange();
|
|
154
|
+
void this.workspaceRouteController.handleHashChange();
|
|
156
155
|
}
|
|
157
156
|
},
|
|
158
157
|
onWorkspaceEvent: (event) => {
|
|
@@ -165,8 +164,14 @@ export class CollabMdAppShell {
|
|
|
165
164
|
this.fileExplorer = new FileExplorerController({
|
|
166
165
|
mobileBreakpointQuery: this.mobileBreakpointQuery,
|
|
167
166
|
onFileDelete: () => this.navigation.navigateToFile(null),
|
|
168
|
-
onFileSelect: (filePath) => this.handleFileSelection(filePath, {
|
|
167
|
+
onFileSelect: (filePath) => this.workspaceRouteController.handleFileSelection(filePath, {
|
|
168
|
+
closeSidebarOnMobile: true,
|
|
169
|
+
}),
|
|
170
|
+
onShowFileExtensionsChange: (showFileExtensions) => {
|
|
171
|
+
this.preferences.setFileTreeShowExtensions(showFileExtensions);
|
|
172
|
+
},
|
|
169
173
|
pendingWorkspaceRequestIds: this.pendingWorkspaceRequestIds,
|
|
174
|
+
showFileExtensions: this.preferences.getFileTreeShowExtensions(),
|
|
170
175
|
toastController: this.toastController,
|
|
171
176
|
vaultClient: this.vaultApiClient,
|
|
172
177
|
});
|
|
@@ -179,7 +184,23 @@ export class CollabMdAppShell {
|
|
|
179
184
|
toastController: this.toastController,
|
|
180
185
|
vaultApiClient: this.vaultApiClient,
|
|
181
186
|
});
|
|
182
|
-
this.gitPanel =
|
|
187
|
+
this.gitPanel = new GitPanelController({
|
|
188
|
+
enabled: this.runtimeConfig.gitEnabled !== false,
|
|
189
|
+
gitApiClient: this.gitApiClient,
|
|
190
|
+
onCommitStaged: () => this.openGitCommitDialog(),
|
|
191
|
+
onOpenPullBackup: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
192
|
+
onPullBranch: () => this.pullGitBranch(),
|
|
193
|
+
onPushBranch: () => this.pushGitBranch(),
|
|
194
|
+
onRepoChange: (isGitRepo, status) => this.handleGitRepoChange(isGitRepo, status),
|
|
195
|
+
onResetFile: (filePath, { scope }) => this.openGitResetDialog(filePath, { scope }),
|
|
196
|
+
onSelectCommit: (hash, { path }) => this.handleGitCommitSelection(hash, { closeSidebarOnMobile: true, path }),
|
|
197
|
+
onSelectDiff: (filePath, { scope }) => this.handleGitDiffSelection(filePath, { closeSidebarOnMobile: true, scope }),
|
|
198
|
+
onStageFile: (filePath, { scope }) => this.stageGitFile(filePath, { scope }),
|
|
199
|
+
onUnstageFile: (filePath, { scope }) => this.unstageGitFile(filePath, { scope }),
|
|
200
|
+
onViewAllDiff: () => this.handleGitDiffSelection(null, { closeSidebarOnMobile: true, scope: 'all' }),
|
|
201
|
+
searchInput: this.elements.gitSearchInput,
|
|
202
|
+
toastController: this.toastController,
|
|
203
|
+
});
|
|
183
204
|
this.outlineController = new OutlineController({
|
|
184
205
|
mobileBreakpointQuery: this.mobileBreakpointQuery,
|
|
185
206
|
onNavigateToHeading: ({ sourceLine }) => {
|
|
@@ -192,7 +213,19 @@ export class CollabMdAppShell {
|
|
|
192
213
|
this.videoEmbed = new VideoEmbedController({
|
|
193
214
|
previewElement: this.elements.previewContent,
|
|
194
215
|
});
|
|
195
|
-
this.basesPreview =
|
|
216
|
+
this.basesPreview = new BasesPreviewController({
|
|
217
|
+
getActiveFilePath: () => this.currentFilePath,
|
|
218
|
+
getSession: () => this.session,
|
|
219
|
+
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
220
|
+
previewElement: this.elements.previewContent,
|
|
221
|
+
replaceBaseSource: ({ path, source }) => {
|
|
222
|
+
if (path && path === this.currentFilePath) {
|
|
223
|
+
this.session?.replaceText?.(source);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
toastController: this.toastController,
|
|
227
|
+
vaultApiClient: this.vaultApiClient,
|
|
228
|
+
});
|
|
196
229
|
this.imageLightbox = new ImageLightboxController({
|
|
197
230
|
previewElement: this.elements.previewContent,
|
|
198
231
|
});
|
|
@@ -211,12 +244,9 @@ export class CollabMdAppShell {
|
|
|
211
244
|
renderVersion: stats?.renderVersion ?? 0,
|
|
212
245
|
});
|
|
213
246
|
this.videoEmbed.reconcileEmbeds(this.elements.previewContent);
|
|
214
|
-
this.videoEmbed.syncLayout();
|
|
215
247
|
this.basesPreview.reconcileEmbeds(this.elements.previewContent);
|
|
216
248
|
this.drawioEmbed.reconcileEmbeds(this.elements.previewContent);
|
|
217
|
-
this.drawioEmbed.syncLayout();
|
|
218
249
|
this.excalidrawEmbed.reconcileEmbeds(this.elements.previewContent, { isLargeDocument: stats.isLargeDocument });
|
|
219
|
-
this.excalidrawEmbed.syncLayout();
|
|
220
250
|
this.scrollSyncController.setLargeDocumentMode(stats.isLargeDocument);
|
|
221
251
|
this.syncPreviewHeadingLinkButtons();
|
|
222
252
|
this.applyPendingPreviewRouteAnchor({ behavior: 'auto', clearMissing: true });
|
|
@@ -235,15 +265,12 @@ export class CollabMdAppShell {
|
|
|
235
265
|
this.refreshCommentUiLayout();
|
|
236
266
|
},
|
|
237
267
|
onRenderComplete: () => {
|
|
238
|
-
this.videoEmbed.syncLayout();
|
|
239
|
-
this.drawioEmbed.syncLayout();
|
|
240
|
-
this.excalidrawEmbed.syncLayout();
|
|
241
268
|
this.applyPendingPreviewRouteAnchor({ allowExpired: true, behavior: 'auto', clearMissing: true });
|
|
242
269
|
this.schedulePreviewLayoutSync({ delayMs: 0 });
|
|
243
270
|
this.refreshCommentUiLayout();
|
|
244
271
|
},
|
|
245
272
|
outlineController: this.outlineController,
|
|
246
|
-
plantUmlRenderClient: this.
|
|
273
|
+
plantUmlRenderClient: this.vaultApiClient,
|
|
247
274
|
previewContainer: this.elements.previewContainer,
|
|
248
275
|
previewElement: this.elements.previewContent,
|
|
249
276
|
toastController: this.toastController,
|
|
@@ -264,12 +291,36 @@ export class CollabMdAppShell {
|
|
|
264
291
|
this.backlinksPanel = new BacklinksPanel({
|
|
265
292
|
headerPanelElement: this.elements.backlinksHeaderPanel,
|
|
266
293
|
inlinePanelElement: this.elements.backlinksInlinePanel,
|
|
267
|
-
loadBacklinks: (filePath, options = {}) => this.
|
|
268
|
-
onFileSelect: (filePath) => this.handleFileSelection(filePath, {
|
|
294
|
+
loadBacklinks: (filePath, options = {}) => this.vaultApiClient.readBacklinks(filePath, options),
|
|
295
|
+
onFileSelect: (filePath) => this.workspaceRouteController.handleFileSelection(filePath, {
|
|
296
|
+
closeSidebarOnMobile: true,
|
|
297
|
+
}),
|
|
269
298
|
panelElement: this.elements.backlinksPanel,
|
|
270
299
|
});
|
|
271
|
-
this.excalidrawEmbed =
|
|
272
|
-
|
|
300
|
+
this.excalidrawEmbed = new ExcalidrawEmbedController({
|
|
301
|
+
getLocalUser: () => this.lobby.getLocalUser(),
|
|
302
|
+
getTheme: () => this.themeController.getTheme(),
|
|
303
|
+
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
304
|
+
onToggleQuickSwitcher: () => {
|
|
305
|
+
void this.toggleQuickSwitcher();
|
|
306
|
+
},
|
|
307
|
+
previewContainer: this.elements.previewContainer,
|
|
308
|
+
previewElement: this.elements.previewContent,
|
|
309
|
+
toastController: this.toastController,
|
|
310
|
+
});
|
|
311
|
+
this.drawioEmbed = new DrawioEmbedController({
|
|
312
|
+
getLocalUser: () => this.lobby.getLocalUser(),
|
|
313
|
+
getTheme: () => this.themeController.getTheme(),
|
|
314
|
+
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
315
|
+
onOpenTextFile: (filePath) => filePath && this.navigation.navigateToFile(filePath, { drawioMode: 'text' }),
|
|
316
|
+
onToggleQuickSwitcher: () => {
|
|
317
|
+
void this.toggleQuickSwitcher();
|
|
318
|
+
},
|
|
319
|
+
previewContainer: this.elements.previewContainer,
|
|
320
|
+
previewElement: this.elements.previewContent,
|
|
321
|
+
toastController: this.toastController,
|
|
322
|
+
vaultApiClient: this.vaultApiClient,
|
|
323
|
+
});
|
|
273
324
|
this.commentUi = new CommentUiController({
|
|
274
325
|
commentSelectionButton: this.elements.commentSelectionButton,
|
|
275
326
|
commentsDrawer: this.elements.commentsDrawer,
|
|
@@ -329,8 +380,41 @@ export class CollabMdAppShell {
|
|
|
329
380
|
vaultApiClient: this.vaultApiClient,
|
|
330
381
|
wikiLinkAutoCreate: this.runtimeConfig.wikiLinkAutoCreate !== false,
|
|
331
382
|
});
|
|
332
|
-
this.gitDiffView =
|
|
333
|
-
|
|
383
|
+
this.gitDiffView = new GitDiffViewController({
|
|
384
|
+
gitApiClient: this.gitApiClient,
|
|
385
|
+
onBackToHistory: ({ historyFilePath } = {}) => {
|
|
386
|
+
if (historyFilePath) {
|
|
387
|
+
this.navigation.navigateToGitFileHistory({ filePath: historyFilePath });
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
this.navigation.navigateToGitHistory();
|
|
391
|
+
},
|
|
392
|
+
onCommitStaged: () => this.openGitCommitDialog(),
|
|
393
|
+
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
394
|
+
onStageFile: (filePath, { scope }) => this.stageGitFile(filePath, { scope }),
|
|
395
|
+
onUnstageFile: (filePath, { scope }) => this.unstageGitFile(filePath, { scope }),
|
|
396
|
+
toastController: this.toastController,
|
|
397
|
+
});
|
|
398
|
+
this.fileHistoryView = new FileHistoryViewController({
|
|
399
|
+
diffRenderer: this.gitDiffView,
|
|
400
|
+
gitApiClient: this.gitApiClient,
|
|
401
|
+
onOpenCommitDiff: (hash, { historyFilePath, path }) => this.handleGitCommitSelection(hash, {
|
|
402
|
+
closeSidebarOnMobile: false,
|
|
403
|
+
historyFilePath,
|
|
404
|
+
path,
|
|
405
|
+
}),
|
|
406
|
+
onOpenFile: (filePath) => filePath && this.navigation.navigateToFile(filePath),
|
|
407
|
+
onOpenPreview: ({ hash, path, currentFilePath }) => this.handleGitFilePreviewSelection({
|
|
408
|
+
hash,
|
|
409
|
+
path,
|
|
410
|
+
currentFilePath,
|
|
411
|
+
}),
|
|
412
|
+
onOpenWorkspaceDiff: (filePath) => this.handleGitDiffSelection(filePath, {
|
|
413
|
+
closeSidebarOnMobile: false,
|
|
414
|
+
scope: 'all',
|
|
415
|
+
}),
|
|
416
|
+
toastController: this.toastController,
|
|
417
|
+
});
|
|
334
418
|
this.tabActivityLock = new TabActivityLock({
|
|
335
419
|
onActivated: ({ takeover }) => this.handleTabActivated({ takeover }),
|
|
336
420
|
onBlocked: () => this.handleTabBlocked({ reason: 'active-elsewhere' }),
|
|
@@ -381,10 +465,12 @@ export class CollabMdAppShell {
|
|
|
381
465
|
loadEditorSessionClass: () => this.loadEditorSessionClass(),
|
|
382
466
|
loadBacklinks: (filePath) => this.backlinksPanel.load(filePath),
|
|
383
467
|
onBeforeFileOpen: () => {
|
|
468
|
+
clearTimeout(this._basePreviewRenderTimer);
|
|
469
|
+
this._basePreviewRenderTimer = null;
|
|
384
470
|
this.session = null;
|
|
385
471
|
this.commentUi.attachSession(null);
|
|
386
472
|
this.layoutController.reset();
|
|
387
|
-
this.resetPreviewMode();
|
|
473
|
+
this.workspacePreviewController.resetPreviewMode();
|
|
388
474
|
this.elements.emptyState?.classList.add('hidden');
|
|
389
475
|
this.elements.editorPage?.classList.remove('hidden');
|
|
390
476
|
this.elements.diffPage?.classList.add('hidden');
|
|
@@ -394,7 +480,7 @@ export class CollabMdAppShell {
|
|
|
394
480
|
onContentChange: ({ isBase, isMermaid, isPlantUml }) => {
|
|
395
481
|
this.handleCommentEditorContentChange();
|
|
396
482
|
if (isBase) {
|
|
397
|
-
|
|
483
|
+
this.scheduleBaseFilePreview(this.currentFilePath, {
|
|
398
484
|
source: this.session?.getText?.() ?? '',
|
|
399
485
|
});
|
|
400
486
|
return;
|
|
@@ -414,6 +500,9 @@ export class CollabMdAppShell {
|
|
|
414
500
|
},
|
|
415
501
|
onFileOpenReady: () => {
|
|
416
502
|
this.hideEditorLoading();
|
|
503
|
+
if (this.currentFilePath) {
|
|
504
|
+
this.preferences.recordRecentFile(this.currentFilePath);
|
|
505
|
+
}
|
|
417
506
|
},
|
|
418
507
|
onSelectionChange: (anchor) => this.handleCommentSelectionChange(anchor),
|
|
419
508
|
onImagePaste: (file) => this.handleEditorImageInsert(file),
|
|
@@ -422,10 +511,10 @@ export class CollabMdAppShell {
|
|
|
422
511
|
this.session = session;
|
|
423
512
|
this.commentUi.attachSession(session);
|
|
424
513
|
},
|
|
425
|
-
onRenderDrawioPreview: (filePath) => this.renderDrawioFilePreview(filePath),
|
|
514
|
+
onRenderDrawioPreview: (filePath) => this.workspacePreviewController.renderDrawioFilePreview(filePath),
|
|
426
515
|
onRenderBasePreview: (filePath) => this.renderBaseFilePreview(filePath),
|
|
427
|
-
onRenderExcalidrawPreview: (filePath) => this.renderExcalidrawFilePreview(filePath),
|
|
428
|
-
onRenderImagePreview: (filePath) => this.renderImageFilePreview(filePath),
|
|
516
|
+
onRenderExcalidrawPreview: (filePath) => this.workspacePreviewController.renderExcalidrawFilePreview(filePath),
|
|
517
|
+
onRenderImagePreview: (filePath) => this.workspacePreviewController.renderImageFilePreview(filePath),
|
|
429
518
|
onSyncWrapToggle: () => this.syncWrapToggle(),
|
|
430
519
|
onUpdateActiveFile: (filePath) => this.fileExplorer.setActiveFile(filePath),
|
|
431
520
|
onUpdateCurrentFile: (filePath) => {
|
|
@@ -433,7 +522,7 @@ export class CollabMdAppShell {
|
|
|
433
522
|
},
|
|
434
523
|
onUpdateLobbyCurrentFile: (filePath) => this.lobby.setCurrentFile(filePath),
|
|
435
524
|
onUpdateVisibleChrome: (filePath, { displayName }) => {
|
|
436
|
-
this.syncFileChrome(filePath, {
|
|
525
|
+
this.workspacePreviewController.syncFileChrome(filePath, {
|
|
437
526
|
drawioMode: this.currentDrawioMode,
|
|
438
527
|
preferPreviewForBase: this.isBaseFile(filePath),
|
|
439
528
|
});
|
|
@@ -443,7 +532,7 @@ export class CollabMdAppShell {
|
|
|
443
532
|
this.elements.activeFileName.textContent = displayName;
|
|
444
533
|
}
|
|
445
534
|
},
|
|
446
|
-
onViewModeReset: () => this.resetPreviewMode(),
|
|
535
|
+
onViewModeReset: () => this.workspacePreviewController.resetPreviewMode(),
|
|
447
536
|
renderPresence: () => this.renderPresence(),
|
|
448
537
|
scrollContainerForSession: (session) => session.getScrollContainer(),
|
|
449
538
|
shouldUseDrawioPreview: () => Boolean(this.runtimeConfig.drawioBaseUrl),
|
|
@@ -472,7 +561,7 @@ export class CollabMdAppShell {
|
|
|
472
561
|
requestPreviewRouteAnchor: (anchorId, filePath) => this.requestPreviewRouteAnchor(anchorId, filePath),
|
|
473
562
|
renderAvatars: () => this.renderAvatars(),
|
|
474
563
|
renderPresence: () => this.renderPresence(),
|
|
475
|
-
resetPreviewMode: () => this.resetPreviewMode(),
|
|
564
|
+
resetPreviewMode: () => this.workspacePreviewController.resetPreviewMode(),
|
|
476
565
|
scrollSyncController: this.scrollSyncController,
|
|
477
566
|
setCurrentFilePath: (value) => {
|
|
478
567
|
this.currentFilePath = value;
|
|
@@ -501,9 +590,6 @@ export class CollabMdAppShell {
|
|
|
501
590
|
workspaceCoordinator: this.workspaceCoordinator,
|
|
502
591
|
});
|
|
503
592
|
|
|
504
|
-
if (this.chatNotificationPermission !== 'granted') {
|
|
505
|
-
this.chatNotificationsEnabled = false;
|
|
506
|
-
}
|
|
507
593
|
}
|
|
508
594
|
|
|
509
595
|
get session() { return this._session; }
|
|
@@ -9,6 +9,32 @@ const USER_COLORS = [
|
|
|
9
9
|
];
|
|
10
10
|
export const USER_NAME_MAX_LENGTH = 24;
|
|
11
11
|
const LOCAL_USER_ID_STORAGE_KEY = 'collabmd-user-id';
|
|
12
|
+
const HEX_COLOR_RE = /^#(?:[\da-f]{3}|[\da-f]{6})$/iu;
|
|
13
|
+
|
|
14
|
+
function colorChannelToLinear(value) {
|
|
15
|
+
const channel = value / 255;
|
|
16
|
+
return channel <= 0.04045
|
|
17
|
+
? channel / 12.92
|
|
18
|
+
: ((channel + 0.055) / 1.055) ** 2.4;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getColorLuminance(color) {
|
|
22
|
+
const hex = color.length === 4
|
|
23
|
+
? color.slice(1).split('').map((channel) => channel.repeat(2)).join('')
|
|
24
|
+
: color.slice(1);
|
|
25
|
+
const [red, green, blue] = hex.match(/../gu).map((channel) => parseInt(channel, 16));
|
|
26
|
+
return (
|
|
27
|
+
0.2126 * colorChannelToLinear(red)
|
|
28
|
+
+ 0.7152 * colorChannelToLinear(green)
|
|
29
|
+
+ 0.0722 * colorChannelToLinear(blue)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getContrastRatio(firstLuminance, secondLuminance) {
|
|
34
|
+
const lighter = Math.max(firstLuminance, secondLuminance);
|
|
35
|
+
const darker = Math.min(firstLuminance, secondLuminance);
|
|
36
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
37
|
+
}
|
|
12
38
|
|
|
13
39
|
function pickRandom(items) {
|
|
14
40
|
return items[Math.floor(Math.random() * items.length)];
|
|
@@ -73,6 +99,18 @@ export function normalizeUserName(value) {
|
|
|
73
99
|
return normalized || null;
|
|
74
100
|
}
|
|
75
101
|
|
|
102
|
+
export function getUserAvatarTextColor(value) {
|
|
103
|
+
const color = String(value ?? '').trim();
|
|
104
|
+
if (!HEX_COLOR_RE.test(color)) {
|
|
105
|
+
return '#fff';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const luminance = getColorLuminance(color.toLowerCase());
|
|
109
|
+
const whiteContrast = getContrastRatio(1, luminance);
|
|
110
|
+
const inkContrast = getContrastRatio(0, luminance);
|
|
111
|
+
return inkContrast >= whiteContrast ? '#000' : '#fff';
|
|
112
|
+
}
|
|
113
|
+
|
|
76
114
|
export function createRandomUser(preferredName = null) {
|
|
77
115
|
const color = pickRandom(USER_COLORS);
|
|
78
116
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { exportToSvg as exportExcalidrawToSvg } from '@excalidraw/excalidraw';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
encodeSvgDataUrl,
|
|
5
|
+
loadImage,
|
|
6
|
+
resolveSvgDimensions,
|
|
7
|
+
sanitizeSvgMarkup,
|
|
8
|
+
} from '../application/preview-diagram-utils.js';
|
|
4
9
|
import { compilePreviewDocument } from '../application/preview-render-compiler.js';
|
|
5
10
|
import { stripVaultFileExtension } from '../../domain/file-kind.js';
|
|
6
11
|
import { parseSceneJson, sceneToInitialData } from '../domain/excalidraw-scene.js';
|
|
@@ -60,10 +65,6 @@ function createDocumentTitle(filePath, title = '') {
|
|
|
60
65
|
return stripVaultFileExtension(leaf) || 'document';
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
function encodeSvgDataUrl(svgMarkup) {
|
|
64
|
-
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
68
|
function encodeSvgBase64DataUrl(svgMarkup) {
|
|
68
69
|
const bytes = new TextEncoder().encode(String(svgMarkup ?? ''));
|
|
69
70
|
const chunkSize = 0x8000;
|
|
@@ -87,35 +88,6 @@ function blobToDataUrl(blob) {
|
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
function loadImage(src) {
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
const image = new Image();
|
|
93
|
-
image.decoding = 'async';
|
|
94
|
-
image.addEventListener('load', () => resolve(image), { once: true });
|
|
95
|
-
image.addEventListener('error', () => reject(new Error(`Failed to load image: ${src}`)), { once: true });
|
|
96
|
-
image.src = src;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function resolveSvgDimensions(svgElement) {
|
|
101
|
-
const widthAttr = Number.parseFloat(svgElement.getAttribute('width') || '');
|
|
102
|
-
const heightAttr = Number.parseFloat(svgElement.getAttribute('height') || '');
|
|
103
|
-
const viewBox = svgElement.getAttribute('viewBox') || '';
|
|
104
|
-
const viewBoxParts = viewBox.split(/\s+/).map((value) => Number.parseFloat(value));
|
|
105
|
-
|
|
106
|
-
const width = Number.isFinite(widthAttr) && widthAttr > 0
|
|
107
|
-
? widthAttr
|
|
108
|
-
: (Number.isFinite(viewBoxParts[2]) && viewBoxParts[2] > 0 ? viewBoxParts[2] : 1200);
|
|
109
|
-
const height = Number.isFinite(heightAttr) && heightAttr > 0
|
|
110
|
-
? heightAttr
|
|
111
|
-
: (Number.isFinite(viewBoxParts[3]) && viewBoxParts[3] > 0 ? viewBoxParts[3] : 800);
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
height,
|
|
115
|
-
width,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
91
|
function trimSvgCanvas(svgMarkup, { padding = 16 } = {}) {
|
|
120
92
|
const probe = document.createElement('div');
|
|
121
93
|
probe.style.position = 'fixed';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../styles/features/auth-gate.css';
|
|
2
2
|
|
|
3
|
+
import { getHashParamsFromRaw } from '../domain/hash-routes.js';
|
|
3
4
|
import { getRuntimeConfig } from './runtime-config.js';
|
|
4
5
|
|
|
5
6
|
const DEFAULT_AUTH_CONFIG = {
|
|
@@ -24,19 +25,12 @@ function getClientAuthConfig() {
|
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function getHashParams() {
|
|
28
|
-
const rawHash = window.location.hash.startsWith('#')
|
|
29
|
-
? window.location.hash.slice(1)
|
|
30
|
-
: window.location.hash;
|
|
31
|
-
return new URLSearchParams(rawHash);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
28
|
function getPasswordFromHash() {
|
|
35
|
-
return
|
|
29
|
+
return getHashParamsFromRaw(window.location.hash).get('auth_password') || '';
|
|
36
30
|
}
|
|
37
31
|
|
|
38
32
|
function removePasswordFromHash() {
|
|
39
|
-
const params =
|
|
33
|
+
const params = getHashParamsFromRaw(window.location.hash);
|
|
40
34
|
if (!params.has('auth_password')) {
|
|
41
35
|
return;
|
|
42
36
|
}
|
|
@@ -48,7 +42,7 @@ function removePasswordFromHash() {
|
|
|
48
42
|
}
|
|
49
43
|
|
|
50
44
|
function consumeHashParam(name) {
|
|
51
|
-
const params =
|
|
45
|
+
const params = getHashParamsFromRaw(window.location.hash);
|
|
52
46
|
const value = params.get(name) || '';
|
|
53
47
|
if (!value) {
|
|
54
48
|
return '';
|