Skip to content

Commit

Permalink
iframe interactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
stereobooster committed Feb 15, 2025
1 parent f132435 commit d395b21
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 45 deletions.
4 changes: 2 additions & 2 deletions packages/docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export default defineConfig({
],
markdown: {
rehypePlugins: [
[rehypeGraphviz, { cache, class: className }],
[rehypeVizdom, { cache, class: className }],
[rehypeGraphviz, { ...conf, strategy: "inline" }],
[rehypeVizdom, { ...conf, strategy: "inline" }],
[rehypeMermaid, conf],
[rehypeGnuplot, conf],
[rehypeD2, { ...conf, shared: "shared/**/*.d2" }],
Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/components/PageFrame.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ import Default from "@astrojs/starlight/components/PageFrame.astro";
import "./vizdom.ts";
import "./graphviz.ts";
import "./d2.ts";
import "./iframeTarget.ts";
</script>
18 changes: 17 additions & 1 deletion packages/docs/src/components/d2.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { json, alg } from "@dagrejs/graphlib";

const css = `.shadow { opacity: 0.4; }
.shape { cursor: default; }`;

// interactivity for d2 diagrams
document.querySelectorAll(".d2.shadow").forEach((container) => {
document.querySelectorAll(".d2.shadow").forEach(async (container: Element) => {
const data = container.getAttribute("data-beoe")
? JSON.parse(container.getAttribute("data-beoe")!)
: null;

const iframe = container.querySelector("iframe");
if (iframe) {
if (!iframe.contentDocument)
await new Promise((resolve) =>
iframe.addEventListener("load", () => resolve(0))
);
container = iframe.contentDocument!.querySelector("svg")! as Element;
const styleSheet = iframe.contentDocument!.styleSheets[0];
css
.split("\n")
.forEach((row) => styleSheet.insertRule(row, styleSheet.cssRules.length));
}

if (!data) return;
const graph = json.read(data);

Expand Down
13 changes: 11 additions & 2 deletions packages/docs/src/components/graphviz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ import { json, alg, type Path } from "@dagrejs/graphlib";
type D = { [node: string]: Path };

// interactivity for graphviz diagrams
document.querySelectorAll(".graphviz").forEach((container) => {
document.querySelectorAll(".graphviz").forEach(async (container) => {
const data = container.getAttribute("data-beoe")
? JSON.parse(container.getAttribute("data-beoe")!)
: null;

const iframe = container.querySelector("iframe");
if (iframe) {
if (!iframe.contentDocument)
await new Promise((resolve) =>
iframe.addEventListener("load", () => resolve(0))
);
container = iframe.contentDocument!.querySelector("svg")! as Element;
}

if (!data) return;
const graph = json.read(data);

Expand Down Expand Up @@ -126,4 +135,4 @@ document.querySelectorAll(".graphviz").forEach((container) => {
}
}
});
});
});
12 changes: 12 additions & 0 deletions packages/docs/src/components/iframeTarget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// to make sure anchors open in top frame
document
.querySelectorAll(".beoe iframe")
// @ts-expect-error
.forEach((iframe: HTMLIFrameElement) => {
const addTargets = () =>
iframe.contentDocument
?.querySelectorAll("a")
.forEach((x) => x.setAttribute("target", "_top"));
iframe.addEventListener("load", addTargets);
addTargets();
});
64 changes: 62 additions & 2 deletions packages/docs/src/components/vizdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,62 @@ import { json, alg, type Path } from "@dagrejs/graphlib";

type D = { [node: string]: Path };

// const vizdomCss = [
// `@keyframes dash {
// from {
// stroke-dashoffset: 40;
// }
// to {
// stroke-dashoffset: 0;
// }
// }`,
// `.edge.active a path:first-child {
// stroke-dasharray: 5 5;
// animation-name: dash;
// animation-duration: 1000ms;
// stroke-dashoffset: 0;
// animation-iteration-count: infinite;
// animation-timing-function: linear;
// }`,

// `.node.selected a *:first-child {
// stroke-width: 2px;
// }`,
// `.node {
// cursor: pointer;
// }`,
// `@media (prefers-reduced-motion) {
// .edge.active a path:first-child {
// animation-duration: 4000ms;
// }
// }`,
// ];

// interactivity for vizdom diagrams
document.querySelectorAll(".vizdom.ants").forEach((container) => {
document.querySelectorAll(".vizdom.ants").forEach(async (container) => {
const data = container.getAttribute("data-beoe")
? JSON.parse(container.getAttribute("data-beoe")!)
: null;

// const iframe = container.querySelector("iframe");
// if (iframe) {
// if (!iframe.contentDocument)
// await new Promise((resolve) =>
// iframe.addEventListener("load", () => resolve(0))
// );

// container = iframe.contentDocument!.querySelector("svg")! as Element;
// // container.setAttribute("preserveAspectRatio", "xMinYMin meet");
// const style = iframe.contentDocument!.createElement("style");
// style.setAttribute("type", "text/css");
// container.prepend(style);
// const styleSheet = iframe.contentDocument!.styleSheets[0];
// if (styleSheet)
// vizdomCss.forEach((row) =>
// styleSheet.insertRule(row, styleSheet.cssRules.length)
// );
// }

if (!data) return;
const graph = json.read(data);

Expand Down Expand Up @@ -129,11 +179,21 @@ document.querySelectorAll(".vizdom.ants").forEach((container) => {
});

// interactivity for vizdom diagrams
document.querySelectorAll(".vizdom.shadow").forEach((container) => {
document.querySelectorAll(".vizdom.shadow").forEach(async (container) => {
const data = container.getAttribute("data-beoe")
? JSON.parse(container.getAttribute("data-beoe")!)
: null;

// const iframe = container.querySelector("iframe");
// if (iframe) {
// if (!iframe.contentDocument)
// await new Promise((resolve) =>
// iframe.addEventListener("load", () => resolve(0))
// );

// container = iframe.contentDocument!.querySelector("svg")! as Element;
// }

if (!data) return;
const graph = json.read(data);

Expand Down
7 changes: 7 additions & 0 deletions packages/docs/src/content/docs/examples/d2-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ direction: right
a -> b -> c -> d -> e
```

### tag=iframe

```d2 darkScheme=false graphFormat=dagre class=shadow svgo=false strategy=file tag=iframe
direction: right
a -> b -> c -> d -> e
```

### import

```d2
Expand Down
30 changes: 30 additions & 0 deletions packages/docs/src/content/docs/examples/vizdom-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ draft: true

**Interactivity**: ants. Try 👇 hover or click nodes.

### tag=svg

```vizdom graphFormat=dagre class=ants
digraph finite_state_machine {
bgcolor="transparent";
Expand All @@ -33,6 +35,34 @@ digraph finite_state_machine {
}
```

### tag=iframe

```vizdom graphFormat=dagre class=ants strategy=file tag=iframe
digraph finite_state_machine {
bgcolor="transparent";
fontname="Helvetica,Arial,sans-serif";
node [fontname="Helvetica,Arial,sans-serif"]
edge [fontname="Helvetica,Arial,sans-serif"]
rankdir=LR;
node [shape = doublecircle]; 0 3 4 8;
node [shape = circle];
0 -> 2 [label = "SS(B)"];
0 -> 1 [label = "SS(S)"];
1 -> 3 [label = "S($end)"];
2 -> 6 [label = "SS(b)"];
2 -> 5 [label = "SS(a)"];
2 -> 4 [label = "S(A)"];
5 -> 7 [label = "S(b)"];
5 -> 5 [label = "S(a)"];
6 -> 6 [label = "S(b)"];
6 -> 5 [label = "S(a)"];
7 -> 8 [label = "S(b)"];
7 -> 5 [label = "S(a)"];
8 -> 6 [label = "S(b)"];
8 -> 5 [label = "S(a)"];
}
```

## rehype-plugin

### works with dark mode
Expand Down
9 changes: 5 additions & 4 deletions packages/docs/src/content/docs/start-here/tag.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ diagram text
| --------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------- | -------------------- |
| [Searchable text](/start-here/interactivity/#searchable-text) | yes | no | yes |
| [Links](/start-here/interactivity/#links) | yes | no | yes with caveats (1) |
| [Interactivity with JS](/start-here/interactivity/#progressive-enhancement-with-js) (2) | yes | no | no (3) |
| [Interactivity with JS](/start-here/interactivity/#progressive-enhancement-with-js) (2) | yes | no | yes with caveats (3) |
| [Can be styled with CSS](/start-here/styling-with-css/) | yes | no | no |
| CSS conflicts | possible | no | no |
| [`alt="..."` or `title="..."`](/start-here/accessibility/) | no | yes | yes |
Expand All @@ -73,8 +73,9 @@ diagram text

- (1) Links require `target=_top`, iframe may require `allow-top-navigation`
- (2) This includes [link previews](https://astro-digital-garden.stereobooster.com/recipes/link-previews/)
- (3) Problem is that `iframe` sandboxes content, which makes it impossible to access it via JS
- **TODO**: I wonder if domain is the same, maybe restriction can be lifted.
- **TODO**: I also don't know if `embed` has the same restrictions
- (3) It is possible to access `iframe` content via JS, but I suspect it will have issues
- with [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- `embed`, it seems, doesn't have `DOM`
- there probably will be issues with `@floating-ui/dom`
- (4) [Work only if images inlined (via `data-url`)](https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image#restrictions)
- (5) gestures don't work (at least in the current implementation), buttons work though
Loading

0 comments on commit d395b21

Please sign in to comment.