duckfn-docs-kit 0.4.0 → 0.4.1

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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The "edit the source" dialog shared by `<dfk-mermaid>` and the SQL result `svg`
3
+ * viewer: a modal holding a plain-text CodeMirror editor and an Apply / Cancel
4
+ * pair.
5
+ *
6
+ * The editor writes back through the callback {@link open} is given rather than
7
+ * through an event, so the owner keeps its own source as the single truth — the
8
+ * dialog never renders anything and never decides what a change means.
9
+ *
10
+ * The `<dialog>` is built once and reused; the editor mounts on first open and is
11
+ * kept, because a reader who edits one diagram is likely to edit the next. The
12
+ * dialog is shown *before* the editor mounts: CodeMirror measures its container as
13
+ * it is constructed, and a `display: none` dialog measures to zero.
14
+ *
15
+ * This is browser-only code.
16
+ */
17
+ export interface SourceDialogLabels {
18
+ title: string;
19
+ apply: string;
20
+ cancel: string;
21
+ }
22
+ export declare class SourceDialog {
23
+ #private;
24
+ readonly root: HTMLDialogElement;
25
+ constructor(labels: SourceDialogLabels);
26
+ setLabels(labels: SourceDialogLabels): void;
27
+ /**
28
+ * Shows the dialog with `source` in the editor. `onApply` receives the edited
29
+ * text — only when it differs from what was opened, so an unedited Apply is a
30
+ * plain close.
31
+ */
32
+ open(source: string, onApply: (value: string) => void): void;
33
+ /** Closes the dialog and releases the editor. The dialog node stays in place. */
34
+ destroy(): void;
35
+ }
@@ -1,37 +1,53 @@
1
+ import { type DownloadPayload } from '../download';
1
2
  /**
2
3
  * Every renderer's result shell: a tab strip plus the panels behind it.
3
4
  *
4
- * The strip is one tab per preview row plus a `Table` tab that always comes
5
- * **last**; a renderer with a single view passes no items at all, so a plain
6
- * table result is a strip holding nothing but that trailing `Table` tab. Every
7
- * result therefore has the same chrome — which is where the fullscreen toggle
8
- * lives.
5
+ * The strip holds one tab per item — a preview row, a `Text` view, or the
6
+ * trailing `Table` view — and, at its right end, the chrome that acts on the
7
+ * result as a whole: the active tab's own {@link PreviewTabItem.actions}, a
8
+ * **download** button, and whatever the caller parks last (the fullscreen toggle
9
+ * `<dfk-sql>` owns). Every result therefore has the same chrome, and the panel
10
+ * behind a tab is built the first time that tab is shown.
9
11
  *
10
- * Retained mode: every button and panel is built in the constructor and held in
11
- * a field. Activating a tab mutates the nodes it owns (`hidden`, `classList`,
12
- * `aria-selected`, `tabIndex`) — there is no rebuild, and a panel is filled the
13
- * first time it is shown rather than up front.
14
- *
15
- * The table panel is mounted on first activation on purpose: VTable measures
16
- * its container when it is constructed, and a `hidden` panel measures to zero.
12
+ * Retained mode: every button, action container and panel is built in the
13
+ * constructor and held in a field. Activating a tab mutates the nodes it owns
14
+ * (`hidden`, `classList`, `aria-selected`, `tabIndex`) — there is no rebuild, and
15
+ * a panel is filled the first time it is shown rather than up front.
17
16
  */
18
- /** One preview row: its tab label and how to fill its panel. */
17
+ /** One tab: its label, how to fill its panel, and what it offers the strip. */
19
18
  export interface PreviewTabItem {
20
19
  label: string;
21
- mount(panel: HTMLElement): void;
22
- }
23
- /** What `PreviewTabs` needs from the caller to own the trailing table tab. */
24
- export interface PreviewTableHandle {
25
- dispose(): void;
20
+ /**
21
+ * Fills the panel. Called once, the first time the tab is shown; an async mount
22
+ * may resolve with a disposer, which the strip runs when it is disposed (that is
23
+ * how the table's handle gets released, including when the countdown lands after
24
+ * {@link PreviewTabs.dispose}).
25
+ */
26
+ mount(panel: HTMLElement): void | (() => void) | Promise<void | (() => void)>;
27
+ /**
28
+ * Controls for the strip's right end, shown only while this tab is active — the
29
+ * place for actions that belong to *this* result (a table's search and view
30
+ * switches, a figure's zoom reset) rather than to every result.
31
+ */
32
+ actions?: HTMLElement;
33
+ /** This tab's file, or `null` while there is nothing to save yet. */
34
+ download?: () => DownloadPayload | null;
35
+ /** Told the result area's fullscreen state, for figures that zoom inside it. */
36
+ setFullscreen?: (value: boolean) => void;
26
37
  }
27
38
  export declare class PreviewTabs {
28
39
  #private;
29
40
  /**
30
- * @param corner Node parked at the right end of the strip, outside the
31
- * scrolling tab list. `<dfk-sql>` passes its fullscreen toggle: it owns that
32
- * button's state, so it owns the node and only lends it here.
41
+ * @param corner Node parked at the very end of the strip, after the download
42
+ * button. `<dfk-sql>` passes its fullscreen toggle: it owns that button's state,
43
+ * so it owns the node and only lends it here.
33
44
  */
34
- constructor(host: HTMLElement, items: readonly PreviewTabItem[], tableLabel: string, mountTable: (panel: HTMLElement) => Promise<PreviewTableHandle>, corner?: HTMLElement);
35
- /** Releases the table (if it was ever shown) and empties every panel. */
45
+ constructor(host: HTMLElement, items: readonly PreviewTabItem[], downloadLabel: string, corner?: HTMLElement);
46
+ /** Releases every mounted item and empties the panels. */
36
47
  dispose(): void;
48
+ /**
49
+ * Records the result area's fullscreen state and passes it on to the tab on
50
+ * screen: a figure zooms only where the result is expanded (see `PanZoomView`).
51
+ */
52
+ setFullscreen(value: boolean): void;
37
53
  }
@@ -0,0 +1,53 @@
1
+ import { type DownloadPayload } from '../download';
2
+ /**
3
+ * The `svg` result view: an inline SVG a reader can zoom (in the result area's
4
+ * fullscreen), edit, and download — the same interactions a diagram gets from
5
+ * `<dfk-mermaid>`, which is why both are built on `PanZoomView` and
6
+ * `SourceDialog`.
7
+ *
8
+ * A plain class rather than a custom element: nothing hands it content through
9
+ * markup, and the SQL renderer already has the parsed node, so there is no
10
+ * upgrade to wait for.
11
+ *
12
+ * Like an embedded `<dfk-mermaid>`, the element contributes no frame — the result
13
+ * area's panel is the frame — and no floating cluster: its two controls travel out
14
+ * through {@link actions} for the result's tab strip, and its file travels out
15
+ * through {@link downloadPayload} for the strip's download button. Zoom is off
16
+ * until {@link setFullscreen} says the result area is expanded.
17
+ *
18
+ * This is browser-only code.
19
+ */
20
+ /** The strings a figure's controls need. */
21
+ export interface FigureLabels {
22
+ reset: string;
23
+ edit: string;
24
+ editTitle: string;
25
+ apply: string;
26
+ cancel: string;
27
+ }
28
+ export declare class SvgViewer {
29
+ #private;
30
+ /** The box in the tab panel: the panzoom viewport, and the frame's clipping box. */
31
+ readonly root: HTMLDivElement;
32
+ /** The controls the result area's tab strip shows while this tab is active. */
33
+ readonly actions: HTMLDivElement;
34
+ constructor(svg: SVGElement | null, markup: string, labels: FigureLabels, fallback: string);
35
+ /** Turns zoom and pan on or off; the result area calls this with its fullscreen. */
36
+ setFullscreen(value: boolean): void;
37
+ /**
38
+ * The file this view would be saved as: the SVG itself, or — when the markup
39
+ * does not parse and the view is showing it as text — that text.
40
+ */
41
+ downloadPayload(): DownloadPayload;
42
+ dispose(): void;
43
+ }
44
+ /**
45
+ * Parses SVG markup from a result cell into a node this document can host.
46
+ *
47
+ * `image/svg+xml` is strict XML: malformed markup (unclosed tags, a bare `&`,
48
+ * an HTML `<br>`) comes back as a `<parsererror>` element rather than throwing,
49
+ * so the caller can degrade to text. Script-bearing and event-handler content
50
+ * is stripped — inline SVG is *not* isolated (use the `iframe` renderer for
51
+ * untrusted markup).
52
+ */
53
+ export declare function parseSvgMarkup(document: Document, markup: string): SVGElement | null;
@@ -1,4 +1,4 @@
1
- import { t as e } from "../register-Dev_kc3Z.js";
1
+ import { t as e } from "../register-wdwf0LC4.js";
2
2
  //#region src/sql/client.ts
3
3
  typeof window < "u" && e();
4
4
  //#endregion
@@ -8000,7 +8000,7 @@ var Eu, Du, Ou, ku, Au, ju, Mu, Nu, Pu, Fu, Iu, Lu, Ru, zu, Bu, Vu, Hu, Uu, Wu,
8000
8000
  11
8001
8001
  ])), od = {
8002
8002
  name: "@duckdb/duckdb-wasm",
8003
- version: "1.33.1-dev64.0",
8003
+ version: "1.33.1-dev65.0",
8004
8004
  description: "DuckDB powered by WebAssembly",
8005
8005
  license: "MIT",
8006
8006
  repository: {
@@ -25,6 +25,13 @@ export interface RenderContext {
25
25
  * renderer only borrows it so every result has the same chrome.
26
26
  */
27
27
  fullscreenButton: HTMLElement;
28
+ /**
29
+ * Subscribes to the result area's fullscreen state, calling back with the
30
+ * current value straight away and returning the unsubscribe. A renderer whose
31
+ * figure zooms only in fullscreen (`svg`, `mermaid`) forwards the value to its
32
+ * viewer; the subscription must be released by the renderer's disposer.
33
+ */
34
+ onFullscreenChange(listener: (value: boolean) => void): () => void;
28
35
  }
29
36
  /**
30
37
  * Renders `result` into `context.host`. Resolves with a disposer releasing any
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "duckfn-docs-kit",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Shared Docusaurus building blocks (TOC toggle, home-page web components, brand tokens, remark version placeholder) for duckfn-family extension docs sites.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -58,9 +58,10 @@
58
58
  "@codemirror/lang-sql": "^6.10.0",
59
59
  "@codemirror/state": "^6.7.6",
60
60
  "@codemirror/view": "^6.43.13",
61
- "@duckdb/duckdb-wasm": "1.33.1-dev64.0",
61
+ "@duckdb/duckdb-wasm": "1.33.1-dev65.0",
62
62
  "@panzoom/panzoom": "^4.6.2",
63
63
  "@visactor/vtable": "^1.26.8",
64
+ "@visactor/vtable-search": "^1.26.8",
64
65
  "codemirror": "^6.0.2",
65
66
  "filenamify": "^7.0.3",
66
67
  "iconify-icon": "^3.0.3",
package/src/codemirror.ts CHANGED
@@ -66,11 +66,20 @@ export async function mountCodeEditor(
66
66
  }),
67
67
  ],
68
68
  parent: container,
69
- // `root` is left to CodeMirror's own `getRoot(container)`. The container sits
70
- // in the component's shadow root, so style-mod mounts the base theme into
71
- // that same shadow root — exactly where the `.cm-*` rules are needed.
72
- // Pinning it to `document` would put them outside the editor's tree instead,
73
- // where a shadow boundary stops them.
69
+ // The tree the container really belongs to — `getRootNode()`, not CodeMirror's
70
+ // own `getRoot()`. `getRoot()` follows `assignedSlot` before `parentNode`, so a
71
+ // container in a *slotted* subtree is reported as living in the shadow root it
72
+ // is slotted **into**. The SQL result area is exactly that (light DOM, slotted
73
+ // into `<dfk-sql>` through `slot="dfk-result"`), so style-mod mounted the base
74
+ // theme in a shadow root, where it cannot reach slotted nodes at all: the
75
+ // editor laid out as plain block boxes — `.cm-scroller` stacked instead of
76
+ // flex, gutter above the code.
77
+ //
78
+ // `getRootNode()` stops at the tree that owns the container: `document` for
79
+ // that slotted light DOM, the shadow root for a genuine shadow child (the
80
+ // code view, a diagram's dialog) — which is where the `.cm-*` rules are
81
+ // needed. Pinning it to `document` would break the shadow cases instead.
82
+ root: container.getRootNode() as Document | ShadowRoot,
74
83
  });
75
84
 
76
85
  return {
@@ -1,28 +1,46 @@
1
1
  import filenamify from 'filenamify';
2
+ import {el} from './dom';
2
3
 
3
4
  /**
4
- * What a downloaded diagram is called.
5
+ * Saving something the kit rendered to a file: the payload shape, the click that
6
+ * performs the save, and how the file is named.
5
7
  *
6
- * The name is derived from the page, not from the diagram: a diagram has no name
7
- * of its own, and the reader downloading one is after "the diagram from that
8
- * section", not `mermaid-diagram.svg`.
9
- *
10
- * Three sources, most specific first, each falling back to the next:
11
- *
12
- * 1. **The diagram's own title** — mermaid's frontmatter
13
- * (`---\ntitle: …\n---`, which mermaid itself draws above the diagram).
14
- * 2. **The nearest heading above it** — the section the diagram belongs to, which
15
- * on a docs page is what a reader would call it.
16
- * 3. **The document title** — the browser tab's title, for a diagram that sits
17
- * above every heading on its page.
18
- *
19
- * Nothing found → {@link DEFAULT_DIAGRAM_FILE}.
8
+ * Shared by `<dfk-mermaid>` (a downloaded diagram) and the SQL result chrome (a
9
+ * downloaded result of any kind), so a docs page has one definition of "what a
10
+ * download is" rather than one per component.
20
11
  *
21
12
  * This is browser-only code.
22
13
  */
23
14
 
24
- /** Used when nothing on the page says anything about this diagram. */
25
- export const DEFAULT_DIAGRAM_FILE = 'mermaid-diagram.svg';
15
+ /** One file's worth of text, ready to save. */
16
+ export interface DownloadPayload {
17
+ /** The file name, extension included. */
18
+ name: string;
19
+ /** The blob's MIME type. */
20
+ mime: string;
21
+ /** The file's contents — text for every format the kit produces. */
22
+ text: string;
23
+ }
24
+
25
+ /**
26
+ * Saves a payload through a temporary object URL.
27
+ *
28
+ * The anchor is in the document for the click — some browsers ignore a detached
29
+ * one — and the URL is revoked on the next tick, once the download has been
30
+ * handed to the browser.
31
+ */
32
+ export function saveDownload(payload: DownloadPayload): void {
33
+ const blob = new Blob([payload.text], {type: payload.mime});
34
+ const url = URL.createObjectURL(blob);
35
+ const link = el('a', {href: url, download: payload.name});
36
+ document.body.appendChild(link);
37
+ link.click();
38
+ link.remove();
39
+ window.setTimeout(() => URL.revokeObjectURL(url), 0);
40
+ }
41
+
42
+ /** Used when nothing on the page says anything about what this is. */
43
+ const DEFAULT_BASE = 'diagram';
26
44
 
27
45
  /**
28
46
  * The length cap. `filenamify` truncates by grapheme, so a CJK heading is cut at
@@ -53,15 +71,39 @@ function cleanTitle(value: string | undefined): string {
53
71
  return value === undefined ? '' : value.replace(EDGE_NOISE, '');
54
72
  }
55
73
 
56
- export function diagramFileName(source: string, element: Element): string {
74
+ /**
75
+ * What a downloaded figure is called.
76
+ *
77
+ * The name is derived from the page, not from the figure: a diagram or an SVG
78
+ * result has no name of its own, and the reader downloading one is after "the
79
+ * figure from that section", not `diagram.svg`.
80
+ *
81
+ * Three sources, most specific first, each falling back to the next:
82
+ *
83
+ * 1. **The figure's own title** — mermaid's frontmatter (`---\ntitle: …\n---`,
84
+ * which mermaid itself draws above the diagram); only read when `options.source`
85
+ * is given.
86
+ * 2. **The nearest heading above it** — the section the figure belongs to, which
87
+ * on a docs page is what a reader would call it.
88
+ * 3. **The document title** — the browser tab's title, for a figure that sits
89
+ * above every heading on its page.
90
+ *
91
+ * Nothing found → `options.fallback` (or {@link DEFAULT_BASE}), with `extension`
92
+ * appended either way.
93
+ */
94
+ export function sectionFileName(
95
+ element: Element,
96
+ extension: string,
97
+ options: {source?: string; fallback?: string} = {},
98
+ ): string {
57
99
  const candidates = [
58
- frontmatterTitle(source),
100
+ options.source === undefined ? undefined : frontmatterTitle(options.source),
59
101
  precedingHeading(element),
60
102
  element.ownerDocument.title,
61
103
  ].map(cleanTitle);
62
104
  const title = candidates.find((candidate) => candidate !== '');
63
105
  if (title === undefined) {
64
- return DEFAULT_DIAGRAM_FILE;
106
+ return `${options.fallback ?? DEFAULT_BASE}.${extension}`;
65
107
  }
66
108
  // Filenames are a filesystem concern, so they go through a library rather than a
67
109
  // hand-rolled character class. Three things it does that matter here and that a
@@ -74,7 +116,7 @@ export function diagramFileName(source: string, element: Element): string {
74
116
  // It also normalises Unicode whitespace and drops format characters, which
75
117
  // quietly cleans up Docusaurus' heading anchors: the `<a>` it appends to every
76
118
  // heading contributes a zero-width space to `textContent`.
77
- return `${filenamify(title, {replacement: REPLACEMENT, maxLength: MAX_LENGTH})}.svg`;
119
+ return `${filenamify(title, {replacement: REPLACEMENT, maxLength: MAX_LENGTH})}.${extension}`;
78
120
  }
79
121
 
80
122
  /**
@@ -102,11 +144,11 @@ function unquote(value: string): string {
102
144
  }
103
145
 
104
146
  /**
105
- * The text of the last heading that precedes the diagram, or `undefined`.
147
+ * The text of the last heading that precedes the figure, or `undefined`.
106
148
  *
107
149
  * The search is scoped to the enclosing `<article>` where there is one: a docs
108
150
  * page's navbar, sidebar and footer are full of headings that have nothing to do
109
- * with this diagram, and the article is the one container that holds the page's
151
+ * with this figure, and the article is the one container that holds the page's
110
152
  * own content.
111
153
  */
112
154
  function precedingHeading(element: Element): string | undefined {
@@ -124,4 +166,4 @@ function precedingHeading(element: Element): string | undefined {
124
166
  }
125
167
  }
126
168
  return found;
127
- }
169
+ }
@@ -16,6 +16,14 @@
16
16
  margin: 1rem 0;
17
17
  }
18
18
 
19
+ /* Embedded in a SQL result: the result area's tab strip and panel already draw
20
+ the frame, so the element contributes neither margin nor border nor padding —
21
+ two nested frames are one too many. Its zoom controls live in the tab strip
22
+ instead of floating here, which `DfkMermaid.ts` arranges. */
23
+ :host([embedded]) {
24
+ margin: 0;
25
+ }
26
+
19
27
  .dfk-mermaid-canvas {
20
28
  position: relative;
21
29
  }
@@ -31,6 +39,34 @@
31
39
  padding: 0.75rem;
32
40
  }
33
41
 
42
+ /* The SQL result panel is the frame; this one is only a clipping box. */
43
+ :host([embedded]) .dfk-mermaid-viewport {
44
+ border: none;
45
+ border-radius: 0;
46
+ padding: 0;
47
+ }
48
+
49
+ /* Fullscreen (embedded): the result area hands the panel its height, so the
50
+ viewport fills it instead of sizing to the diagram. `:host(...)` rather than a
51
+ descendant selector because the class sits on the element itself, outside this
52
+ shadow tree. */
53
+ :host(.dfk-mermaid-fullscreen) {
54
+ height: 100%;
55
+ }
56
+
57
+ /* The canvas is what the viewport's `height: 100%` resolves against, so the
58
+ fullscreen height has to pass *through* it. Left `auto`, the percentage above
59
+ has nothing to resolve against and collapses back to the diagram's own height —
60
+ the figure then looks the same in fullscreen, and the wheel/drag surface (and
61
+ the clip box) stays a strip as tall as the diagram. */
62
+ :host(.dfk-mermaid-fullscreen) .dfk-mermaid-canvas {
63
+ height: 100%;
64
+ }
65
+
66
+ :host(.dfk-mermaid-fullscreen) .dfk-mermaid-viewport {
67
+ height: 100%;
68
+ }
69
+
34
70
  /* Mermaid sizes its own `<svg>` (`width="100%"` plus an inline `max-width`), so
35
71
  nothing here fights that: the rules only centre it once the inline cap kicks
36
72
  in, and give it a line box so the viewport has a height. */
@@ -47,12 +83,13 @@
47
83
  zoom state rather than set on the element once and for all (panzoom's `cursor`
48
84
  option does the latter, and it was promising a pan at fit — over text that is
49
85
  perfectly selectable). `cursor` is inherited, so these two rules reach the
50
- diagram and every label in it; the buttons override it with `pointer`. */
51
- .dfk-mermaid-canvas.dfk-mermaid-zoomed {
86
+ diagram and every label in it; the buttons override it with `pointer`. The state
87
+ classes are written by the shared `PanZoomView`. */
88
+ .dfk-mermaid-viewport.dfk-panzoom-zoomed {
52
89
  cursor: grab;
53
90
  }
54
91
 
55
- .dfk-mermaid-canvas.dfk-mermaid-zoomed.dfk-mermaid-grabbing {
92
+ .dfk-mermaid-viewport.dfk-panzoom-zoomed.dfk-panzoom-grabbing {
56
93
  cursor: grabbing;
57
94
  }
58
95
 
@@ -205,7 +242,7 @@
205
242
 
206
243
  /* --- Source dialog ------------------------------------------------------- */
207
244
 
208
- .dfk-mermaid-dialog {
245
+ .dfk-source-dialog {
209
246
  width: min(56rem, 92vw);
210
247
  max-width: none;
211
248
  padding: 0;
@@ -215,18 +252,18 @@
215
252
  color: var(--ifm-font-color-base, #181818);
216
253
  }
217
254
 
218
- .dfk-mermaid-dialog::backdrop {
255
+ .dfk-source-dialog::backdrop {
219
256
  background: rgb(0 0 0 / 45%);
220
257
  }
221
258
 
222
- .dfk-mermaid-dialog-body {
259
+ .dfk-source-dialog-body {
223
260
  display: flex;
224
261
  flex-direction: column;
225
262
  gap: 0.5rem;
226
263
  padding: 0.75rem;
227
264
  }
228
265
 
229
- .dfk-mermaid-dialog-title {
266
+ .dfk-source-dialog-title {
230
267
  margin: 0;
231
268
  font-size: 0.95rem;
232
269
  font-weight: 600;
@@ -236,7 +273,7 @@
236
273
  theme in the same root the `.cm-*` rules are needed in (`src/codemirror.ts`).
237
274
  The content inset is CodeMirror's own (`padding: 4px 0`) and is left alone —
238
275
  see the note in `DfkSql.css` about `ViewState.measure()`. */
239
- .dfk-mermaid-dialog-editor {
276
+ .dfk-source-dialog-editor {
240
277
  border: 1px solid var(--ifm-global-border-color, #e0e0e0);
241
278
  border-radius: var(--ifm-global-radius, 0.4rem);
242
279
  overflow: hidden;
@@ -244,24 +281,24 @@
244
281
  font-size: var(--ifm-code-font-size, 95%);
245
282
  }
246
283
 
247
- .dfk-mermaid-dialog-editor .cm-editor {
284
+ .dfk-source-dialog-editor .cm-editor {
248
285
  outline: none;
249
286
  }
250
287
 
251
- .dfk-mermaid-dialog-editor .cm-scroller {
288
+ .dfk-source-dialog-editor .cm-scroller {
252
289
  max-height: 55vh;
253
290
  font-family: var(--ifm-font-family-monospace, ui-monospace, SFMono-Regular,
254
291
  Menlo, monospace);
255
292
  line-height: 1.6;
256
293
  }
257
294
 
258
- .dfk-mermaid-dialog-footer {
295
+ .dfk-source-dialog-footer {
259
296
  display: flex;
260
297
  justify-content: flex-end;
261
298
  gap: 0.5rem;
262
299
  }
263
300
 
264
- .dfk-mermaid-dialog-button {
301
+ .dfk-source-dialog-button {
265
302
  padding: 0.3rem 0.9rem;
266
303
  border: 1px solid var(--ifm-global-border-color, #e0e0e0);
267
304
  border-radius: var(--ifm-global-radius, 0.25rem);
@@ -272,18 +309,18 @@
272
309
  cursor: pointer;
273
310
  }
274
311
 
275
- .dfk-mermaid-dialog-button:hover {
312
+ .dfk-source-dialog-button:hover {
276
313
  border-color: var(--ifm-color-primary, #14459b);
277
314
  color: var(--ifm-color-primary, #14459b);
278
315
  }
279
316
 
280
- .dfk-mermaid-dialog-apply {
317
+ .dfk-source-dialog-apply {
281
318
  border-color: var(--ifm-color-primary, #14459b);
282
319
  background: var(--ifm-color-primary, #14459b);
283
320
  color: var(--ifm-button-color, #fff);
284
321
  }
285
322
 
286
- .dfk-mermaid-dialog-apply:hover {
323
+ .dfk-source-dialog-apply:hover {
287
324
  color: var(--ifm-button-color, #fff);
288
325
  filter: brightness(1.1);
289
326
  }