@markdy/renderer-dom 1.0.12 → 1.0.14
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/index.js +591 -82
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1636,6 +1636,16 @@ function ensureNodeStyles(doc) {
|
|
|
1636
1636
|
transform: rotate(0deg);
|
|
1637
1637
|
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
|
1638
1638
|
}
|
|
1639
|
+
.markdy-node[data-shape="diamond"] .markdy-node__body {
|
|
1640
|
+
justify-content: center;
|
|
1641
|
+
padding: 6px 16%;
|
|
1642
|
+
text-align: center;
|
|
1643
|
+
}
|
|
1644
|
+
.markdy-node[data-shape="diamond"] .markdy-node__label {
|
|
1645
|
+
flex: 0 1 auto;
|
|
1646
|
+
line-height: 1.18;
|
|
1647
|
+
text-align: center;
|
|
1648
|
+
}
|
|
1639
1649
|
.markdy-node[data-shape="pill"] {
|
|
1640
1650
|
border-radius: 999px;
|
|
1641
1651
|
min-height: 54px;
|
|
@@ -2100,11 +2110,11 @@ function createNodeEl(node, theme, assets) {
|
|
|
2100
2110
|
el.setAttribute("aria-label", el.title);
|
|
2101
2111
|
const body = document.createElement("div");
|
|
2102
2112
|
body.className = "markdy-node__body";
|
|
2103
|
-
const icon = createNodeMediaEl(document, node, assets);
|
|
2104
2113
|
const label = document.createElement("div");
|
|
2105
2114
|
label.className = "markdy-node__label";
|
|
2106
2115
|
label.textContent = node.label;
|
|
2107
|
-
body.append(
|
|
2116
|
+
if (node.shape !== "diamond") body.append(createNodeMediaEl(document, node, assets));
|
|
2117
|
+
body.append(label);
|
|
2108
2118
|
const value = node.props?.value ?? node.props?.metric;
|
|
2109
2119
|
if (value !== void 0 && value !== null) {
|
|
2110
2120
|
const valueEl = document.createElement("div");
|
|
@@ -2493,15 +2503,26 @@ function ensureSceneStyles(doc) {
|
|
|
2493
2503
|
will-change: opacity, transform;
|
|
2494
2504
|
}
|
|
2495
2505
|
.markdy-footer {
|
|
2496
|
-
font-family:
|
|
2506
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
2497
2507
|
width: 100%;
|
|
2498
2508
|
box-sizing: border-box;
|
|
2509
|
+
display: flex;
|
|
2510
|
+
align-items: center;
|
|
2511
|
+
justify-content: space-between;
|
|
2512
|
+
gap: 8px;
|
|
2513
|
+
padding: 6px 12px;
|
|
2514
|
+
background: var(--md-footer-bg, rgba(15, 23, 42, 0.85));
|
|
2515
|
+
backdrop-filter: blur(16px);
|
|
2516
|
+
-webkit-backdrop-filter: blur(16px);
|
|
2517
|
+
border-top: 1px solid var(--md-footer-border, rgba(148, 163, 184, 0.15));
|
|
2518
|
+
z-index: 20;
|
|
2499
2519
|
}
|
|
2500
2520
|
.markdy-controls {
|
|
2501
2521
|
display: flex;
|
|
2502
2522
|
align-items: center;
|
|
2503
|
-
|
|
2504
|
-
|
|
2523
|
+
justify-content: flex-start;
|
|
2524
|
+
width: 100%;
|
|
2525
|
+
gap: 8px;
|
|
2505
2526
|
max-width: 100%;
|
|
2506
2527
|
overflow-x: auto;
|
|
2507
2528
|
scrollbar-width: none;
|
|
@@ -2509,65 +2530,367 @@ function ensureSceneStyles(doc) {
|
|
|
2509
2530
|
.markdy-controls::-webkit-scrollbar {
|
|
2510
2531
|
display: none;
|
|
2511
2532
|
}
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2533
|
+
.markdy-controls-group {
|
|
2534
|
+
display: inline-flex;
|
|
2535
|
+
align-items: center;
|
|
2536
|
+
gap: 4px;
|
|
2537
|
+
flex-shrink: 0;
|
|
2538
|
+
}
|
|
2539
|
+
.markdy-controls-playback {
|
|
2540
|
+
display: inline-flex;
|
|
2541
|
+
align-items: center;
|
|
2542
|
+
gap: 4px;
|
|
2543
|
+
flex-shrink: 0;
|
|
2544
|
+
}
|
|
2545
|
+
.markdy-controls-timeline {
|
|
2546
|
+
display: flex;
|
|
2547
|
+
align-items: center;
|
|
2548
|
+
gap: 8px;
|
|
2549
|
+
flex: 1 1 180px;
|
|
2550
|
+
min-width: 110px;
|
|
2551
|
+
max-width: 340px;
|
|
2552
|
+
}
|
|
2553
|
+
.markdy-controls-tools {
|
|
2554
|
+
display: inline-flex;
|
|
2555
|
+
align-items: center;
|
|
2556
|
+
gap: 4px;
|
|
2557
|
+
flex-shrink: 0;
|
|
2558
|
+
margin-left: auto;
|
|
2559
|
+
}
|
|
2560
|
+
.markdy-control-divider {
|
|
2561
|
+
width: 1px;
|
|
2562
|
+
height: 14px;
|
|
2563
|
+
background: var(--md-divider, rgba(148, 163, 184, 0.2));
|
|
2564
|
+
margin: 0 2px;
|
|
2565
|
+
flex-shrink: 0;
|
|
2518
2566
|
}
|
|
2519
2567
|
.markdy-controls button {
|
|
2520
2568
|
appearance: none;
|
|
2569
|
+
-webkit-appearance: none;
|
|
2521
2570
|
touch-action: manipulation;
|
|
2522
2571
|
user-select: none;
|
|
2523
2572
|
-webkit-user-select: none;
|
|
2524
|
-
border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.
|
|
2525
|
-
border-radius:
|
|
2526
|
-
background: var(--md-control-bg, rgba(
|
|
2527
|
-
color: var(--md-control-text, #
|
|
2573
|
+
border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.2));
|
|
2574
|
+
border-radius: 7px;
|
|
2575
|
+
background: var(--md-control-bg, rgba(255, 255, 255, 0.04));
|
|
2576
|
+
color: var(--md-control-text, #94a3b8);
|
|
2528
2577
|
cursor: pointer;
|
|
2529
|
-
font: 600
|
|
2530
|
-
|
|
2531
|
-
min-
|
|
2532
|
-
|
|
2578
|
+
font: 600 11px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
2579
|
+
height: 27px;
|
|
2580
|
+
min-width: 27px;
|
|
2581
|
+
padding: 0 6px;
|
|
2533
2582
|
display: inline-flex;
|
|
2534
2583
|
align-items: center;
|
|
2535
2584
|
justify-content: center;
|
|
2536
|
-
gap:
|
|
2585
|
+
gap: 5px;
|
|
2537
2586
|
white-space: nowrap;
|
|
2538
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.
|
|
2587
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
2539
2588
|
transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
|
|
2540
2589
|
}
|
|
2541
2590
|
.markdy-controls button:hover:not([aria-pressed="true"]) {
|
|
2542
|
-
background: var(--md-control-hover-bg,
|
|
2543
|
-
color: var(--md-control-hover-text, #
|
|
2544
|
-
border-color: var(--md-control-hover-border,
|
|
2545
|
-
|
|
2591
|
+
background: var(--md-control-hover-bg, rgba(255, 255, 255, 0.1));
|
|
2592
|
+
color: var(--md-control-hover-text, #f8fafc);
|
|
2593
|
+
border-color: var(--md-control-hover-border, rgba(148, 163, 184, 0.35));
|
|
2594
|
+
transform: translateY(-1px);
|
|
2595
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.12);
|
|
2546
2596
|
}
|
|
2547
2597
|
.markdy-controls button[aria-pressed="true"] {
|
|
2548
|
-
background: #
|
|
2598
|
+
background: var(--accent, #10b981) !important;
|
|
2549
2599
|
color: #ffffff !important;
|
|
2550
|
-
border-color: #
|
|
2551
|
-
box-shadow: 0
|
|
2600
|
+
border-color: var(--accent, #10b981) !important;
|
|
2601
|
+
box-shadow: 0 0 10px var(--accent-glow, rgba(16, 185, 129, 0.4)) !important;
|
|
2552
2602
|
}
|
|
2553
2603
|
.markdy-controls button:focus-visible {
|
|
2554
|
-
outline: 2px solid #
|
|
2604
|
+
outline: 2px solid var(--accent, #10b981);
|
|
2555
2605
|
outline-offset: 1px;
|
|
2556
2606
|
}
|
|
2557
2607
|
.markdy-controls button:active {
|
|
2558
2608
|
transform: scale(0.95);
|
|
2559
2609
|
}
|
|
2560
|
-
.markdy-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
.markdy-control-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2610
|
+
.markdy-icon {
|
|
2611
|
+
display: inline-block;
|
|
2612
|
+
flex-shrink: 0;
|
|
2613
|
+
vertical-align: middle;
|
|
2614
|
+
}
|
|
2615
|
+
.markdy-control-play {
|
|
2616
|
+
background: var(--accent, #10b981) !important;
|
|
2617
|
+
color: #ffffff !important;
|
|
2618
|
+
border-color: var(--accent, #10b981) !important;
|
|
2619
|
+
padding: 0 10px !important;
|
|
2620
|
+
font-weight: 700 !important;
|
|
2621
|
+
box-shadow: 0 2px 8px var(--accent-glow, rgba(16, 185, 129, 0.35)) !important;
|
|
2622
|
+
}
|
|
2623
|
+
.markdy-control-play:hover {
|
|
2624
|
+
filter: brightness(1.08);
|
|
2625
|
+
box-shadow: 0 2px 12px var(--accent-glow, rgba(16, 185, 129, 0.55)) !important;
|
|
2626
|
+
transform: translateY(-1px) scale(1.02);
|
|
2627
|
+
}
|
|
2628
|
+
.markdy-badge {
|
|
2629
|
+
display: inline-flex;
|
|
2630
|
+
align-items: center;
|
|
2631
|
+
gap: 4px;
|
|
2632
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
2633
|
+
font-size: 11px;
|
|
2634
|
+
font-weight: 600;
|
|
2635
|
+
color: var(--md-control-text, #94a3b8);
|
|
2636
|
+
text-decoration: none;
|
|
2637
|
+
padding: 3px 8px;
|
|
2638
|
+
border-radius: 999px;
|
|
2639
|
+
background: var(--md-control-bg, rgba(255, 255, 255, 0.05));
|
|
2640
|
+
border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.18));
|
|
2641
|
+
margin-left: auto;
|
|
2642
|
+
flex-shrink: 0;
|
|
2643
|
+
transition: all 0.15s ease;
|
|
2644
|
+
white-space: nowrap;
|
|
2645
|
+
}
|
|
2646
|
+
.markdy-badge:hover {
|
|
2647
|
+
color: var(--accent, #10b981);
|
|
2648
|
+
background: var(--accent-light, rgba(16, 185, 129, 0.12));
|
|
2649
|
+
border-color: var(--accent, #10b981);
|
|
2650
|
+
transform: translateY(-1px);
|
|
2651
|
+
}
|
|
2652
|
+
.markdy-speed-group {
|
|
2653
|
+
display: inline-flex;
|
|
2654
|
+
align-items: center;
|
|
2655
|
+
background: var(--md-segmented-bg, rgba(0, 0, 0, 0.18));
|
|
2656
|
+
border: 1px solid var(--md-control-border, rgba(148, 163, 184, 0.18));
|
|
2657
|
+
border-radius: 8px;
|
|
2658
|
+
padding: 2px;
|
|
2659
|
+
gap: 1px;
|
|
2660
|
+
}
|
|
2661
|
+
.markdy-speed-group .markdy-control-rate {
|
|
2662
|
+
border: none;
|
|
2663
|
+
background: transparent;
|
|
2664
|
+
border-radius: 5px;
|
|
2665
|
+
height: 22px;
|
|
2666
|
+
min-width: 25px;
|
|
2667
|
+
padding: 0 5px;
|
|
2668
|
+
font-size: 10px;
|
|
2669
|
+
font-weight: 700;
|
|
2670
|
+
color: var(--md-control-text, #94a3b8);
|
|
2671
|
+
box-shadow: none;
|
|
2672
|
+
}
|
|
2673
|
+
.markdy-speed-group .markdy-control-rate:hover:not([aria-pressed="true"]) {
|
|
2674
|
+
background: rgba(255, 255, 255, 0.08);
|
|
2675
|
+
color: #ffffff;
|
|
2676
|
+
transform: none;
|
|
2677
|
+
}
|
|
2678
|
+
.markdy-speed-group .markdy-control-rate[aria-pressed="true"] {
|
|
2679
|
+
background: var(--accent, #10b981) !important;
|
|
2680
|
+
color: #ffffff !important;
|
|
2681
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25) !important;
|
|
2682
|
+
}
|
|
2683
|
+
.markdy-control-seek {
|
|
2684
|
+
appearance: none;
|
|
2685
|
+
-webkit-appearance: none;
|
|
2686
|
+
width: 100%;
|
|
2687
|
+
height: 5px;
|
|
2688
|
+
border-radius: 999px;
|
|
2689
|
+
background: linear-gradient(
|
|
2690
|
+
to right,
|
|
2691
|
+
var(--accent, #10b981) 0%,
|
|
2692
|
+
var(--accent, #10b981) var(--seek-pct, 0%),
|
|
2693
|
+
rgba(148, 163, 184, 0.22) var(--seek-pct, 0%),
|
|
2694
|
+
rgba(148, 163, 184, 0.22) 100%
|
|
2695
|
+
);
|
|
2696
|
+
outline: none;
|
|
2697
|
+
cursor: pointer;
|
|
2698
|
+
margin: 0;
|
|
2699
|
+
transition: height 0.15s ease;
|
|
2700
|
+
}
|
|
2701
|
+
.markdy-control-seek:hover {
|
|
2702
|
+
height: 7px;
|
|
2703
|
+
}
|
|
2704
|
+
.markdy-control-seek::-webkit-slider-thumb {
|
|
2705
|
+
appearance: none;
|
|
2706
|
+
-webkit-appearance: none;
|
|
2707
|
+
width: 12px;
|
|
2708
|
+
height: 12px;
|
|
2709
|
+
border-radius: 50%;
|
|
2710
|
+
background: #ffffff;
|
|
2711
|
+
border: 2px solid var(--accent, #10b981);
|
|
2712
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
|
|
2713
|
+
cursor: pointer;
|
|
2714
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
2715
|
+
}
|
|
2716
|
+
.markdy-control-seek:hover::-webkit-slider-thumb {
|
|
2717
|
+
transform: scale(1.25);
|
|
2718
|
+
box-shadow: 0 0 8px var(--accent-glow, rgba(16, 185, 129, 0.6));
|
|
2719
|
+
}
|
|
2720
|
+
.markdy-control-seek::-moz-range-thumb {
|
|
2721
|
+
width: 12px;
|
|
2722
|
+
height: 12px;
|
|
2723
|
+
border-radius: 50%;
|
|
2724
|
+
background: #ffffff;
|
|
2725
|
+
border: 2px solid var(--accent, #10b981);
|
|
2726
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
|
|
2727
|
+
cursor: pointer;
|
|
2728
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
2729
|
+
}
|
|
2730
|
+
.markdy-control-seek:hover::-moz-range-thumb {
|
|
2731
|
+
transform: scale(1.25);
|
|
2732
|
+
box-shadow: 0 0 8px var(--accent-glow, rgba(16, 185, 129, 0.6));
|
|
2733
|
+
}
|
|
2734
|
+
.markdy-control-time {
|
|
2735
|
+
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
2736
|
+
font-size: 10px;
|
|
2737
|
+
font-weight: 600;
|
|
2738
|
+
color: var(--md-control-text, #94a3b8);
|
|
2739
|
+
white-space: nowrap;
|
|
2740
|
+
flex-shrink: 0;
|
|
2741
|
+
letter-spacing: -0.02em;
|
|
2742
|
+
}
|
|
2743
|
+
.markdy-btn-flashed {
|
|
2744
|
+
background: rgba(16, 185, 129, 0.2) !important;
|
|
2745
|
+
color: #10b981 !important;
|
|
2746
|
+
border-color: #10b981 !important;
|
|
2747
|
+
}
|
|
2748
|
+
/* \u2500\u2500 Code panel overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
2749
|
+
.markdy-code-panel-overlay {
|
|
2750
|
+
position: fixed;
|
|
2751
|
+
inset: 0;
|
|
2752
|
+
z-index: 9000;
|
|
2753
|
+
background: rgba(2, 6, 23, 0.55);
|
|
2754
|
+
backdrop-filter: blur(3px);
|
|
2755
|
+
-webkit-backdrop-filter: blur(3px);
|
|
2756
|
+
display: flex;
|
|
2757
|
+
align-items: center;
|
|
2758
|
+
justify-content: center;
|
|
2759
|
+
padding: 24px;
|
|
2760
|
+
box-sizing: border-box;
|
|
2761
|
+
opacity: 0;
|
|
2762
|
+
animation: markdy-fade-in 0.18s ease forwards;
|
|
2763
|
+
}
|
|
2764
|
+
.markdy-code-panel-overlay[data-closing="1"] {
|
|
2765
|
+
animation: markdy-fade-out 0.15s ease forwards;
|
|
2766
|
+
}
|
|
2767
|
+
@keyframes markdy-fade-in {
|
|
2768
|
+
from { opacity: 0; }
|
|
2769
|
+
to { opacity: 1; }
|
|
2770
|
+
}
|
|
2771
|
+
@keyframes markdy-fade-out {
|
|
2772
|
+
from { opacity: 1; }
|
|
2773
|
+
to { opacity: 0; }
|
|
2774
|
+
}
|
|
2775
|
+
.markdy-code-panel {
|
|
2776
|
+
position: relative;
|
|
2777
|
+
background: #0f172a;
|
|
2778
|
+
border: 1px solid rgba(71, 85, 105, 0.7);
|
|
2779
|
+
border-radius: 12px;
|
|
2780
|
+
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.04);
|
|
2781
|
+
width: 100%;
|
|
2782
|
+
max-width: 780px;
|
|
2783
|
+
max-height: min(680px, 82vh);
|
|
2784
|
+
display: flex;
|
|
2785
|
+
flex-direction: column;
|
|
2786
|
+
overflow: hidden;
|
|
2787
|
+
transform: translateY(10px) scale(0.98);
|
|
2788
|
+
animation: markdy-panel-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
|
2789
|
+
}
|
|
2790
|
+
.markdy-code-panel-overlay[data-closing="1"] .markdy-code-panel {
|
|
2791
|
+
animation: markdy-panel-out 0.15s ease forwards;
|
|
2792
|
+
}
|
|
2793
|
+
@keyframes markdy-panel-in {
|
|
2794
|
+
from { transform: translateY(12px) scale(0.97); opacity: 0; }
|
|
2795
|
+
to { transform: translateY(0) scale(1); opacity: 1; }
|
|
2796
|
+
}
|
|
2797
|
+
@keyframes markdy-panel-out {
|
|
2798
|
+
from { transform: translateY(0) scale(1); opacity: 1; }
|
|
2799
|
+
to { transform: translateY(8px) scale(0.98); opacity: 0; }
|
|
2800
|
+
}
|
|
2801
|
+
.markdy-code-panel__header {
|
|
2802
|
+
display: flex;
|
|
2803
|
+
align-items: center;
|
|
2804
|
+
justify-content: space-between;
|
|
2805
|
+
padding: 12px 16px 10px;
|
|
2806
|
+
border-bottom: 1px solid rgba(71, 85, 105, 0.4);
|
|
2807
|
+
flex-shrink: 0;
|
|
2808
|
+
}
|
|
2809
|
+
.markdy-code-panel__title {
|
|
2810
|
+
font: 600 12px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
2811
|
+
color: #94a3b8;
|
|
2812
|
+
letter-spacing: 0.06em;
|
|
2813
|
+
text-transform: uppercase;
|
|
2814
|
+
}
|
|
2815
|
+
.markdy-code-panel__actions {
|
|
2816
|
+
display: flex;
|
|
2817
|
+
align-items: center;
|
|
2818
|
+
gap: 6px;
|
|
2819
|
+
}
|
|
2820
|
+
.markdy-code-panel__copy,
|
|
2821
|
+
.markdy-code-panel__playground,
|
|
2822
|
+
.markdy-code-panel__close {
|
|
2823
|
+
appearance: none;
|
|
2824
|
+
border: 1px solid rgba(71, 85, 105, 0.55);
|
|
2825
|
+
border-radius: 6px;
|
|
2826
|
+
background: rgba(30, 41, 59, 0.8);
|
|
2827
|
+
color: #94a3b8;
|
|
2828
|
+
cursor: pointer;
|
|
2829
|
+
font: 600 10.5px/1.2 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
2830
|
+
text-decoration: none;
|
|
2831
|
+
padding: 3px 9px;
|
|
2832
|
+
min-height: 24px;
|
|
2833
|
+
display: inline-flex;
|
|
2834
|
+
align-items: center;
|
|
2835
|
+
gap: 4px;
|
|
2836
|
+
transition: all 0.15s ease;
|
|
2837
|
+
white-space: nowrap;
|
|
2838
|
+
}
|
|
2839
|
+
.markdy-code-panel__playground {
|
|
2840
|
+
background: var(--accent-light, rgba(16, 185, 129, 0.15));
|
|
2841
|
+
color: var(--accent, #10b981);
|
|
2842
|
+
border-color: var(--accent, #10b981);
|
|
2843
|
+
font-weight: 700;
|
|
2844
|
+
}
|
|
2845
|
+
.markdy-code-panel__playground:hover {
|
|
2846
|
+
background: var(--accent, #10b981);
|
|
2847
|
+
color: #ffffff;
|
|
2848
|
+
border-color: var(--accent, #10b981);
|
|
2849
|
+
transform: translateY(-1px);
|
|
2850
|
+
}
|
|
2851
|
+
.markdy-code-panel__copy:hover,
|
|
2852
|
+
.markdy-code-panel__close:hover {
|
|
2853
|
+
background: rgba(51, 65, 85, 0.95);
|
|
2854
|
+
color: #e2e8f0;
|
|
2855
|
+
border-color: #64748b;
|
|
2856
|
+
}
|
|
2857
|
+
.markdy-code-panel__copy:focus-visible,
|
|
2858
|
+
.markdy-code-panel__playground:focus-visible,
|
|
2859
|
+
.markdy-code-panel__close:focus-visible {
|
|
2860
|
+
outline: 2px solid #3b82f6;
|
|
2861
|
+
outline-offset: 1px;
|
|
2862
|
+
}
|
|
2863
|
+
.markdy-code-panel__body {
|
|
2864
|
+
overflow-y: auto;
|
|
2865
|
+
flex: 1 1 auto;
|
|
2866
|
+
padding: 16px 20px;
|
|
2867
|
+
scrollbar-width: thin;
|
|
2868
|
+
scrollbar-color: rgba(71, 85, 105, 0.5) transparent;
|
|
2869
|
+
}
|
|
2870
|
+
.markdy-code-panel__body::-webkit-scrollbar {
|
|
2871
|
+
width: 5px;
|
|
2872
|
+
}
|
|
2873
|
+
.markdy-code-panel__body::-webkit-scrollbar-track {
|
|
2874
|
+
background: transparent;
|
|
2875
|
+
}
|
|
2876
|
+
.markdy-code-panel__body::-webkit-scrollbar-thumb {
|
|
2877
|
+
background: rgba(71, 85, 105, 0.5);
|
|
2878
|
+
border-radius: 9999px;
|
|
2879
|
+
}
|
|
2880
|
+
.markdy-code-panel__pre {
|
|
2881
|
+
margin: 0;
|
|
2882
|
+
font: 400 12.5px/1.65 "JetBrains Mono", ui-monospace, "Cascadia Code", "Fira Code", monospace;
|
|
2883
|
+
color: #e2e8f0;
|
|
2884
|
+
white-space: pre;
|
|
2885
|
+
tab-size: 2;
|
|
2886
|
+
overflow-x: auto;
|
|
2887
|
+
}
|
|
2888
|
+
/* Syntax tinting \u2014 purely decorative, lightweight regex-free colorization */
|
|
2889
|
+
.markdy-code-panel__pre .t-keyword { color: #7dd3fc; }
|
|
2890
|
+
.markdy-code-panel__pre .t-string { color: #86efac; }
|
|
2891
|
+
.markdy-code-panel__pre .t-comment { color: #64748b; font-style: italic; }
|
|
2892
|
+
.markdy-code-panel__pre .t-edge { color: #f9a8d4; }
|
|
2893
|
+
.markdy-code-panel__pre .t-number { color: #fcd34d; }
|
|
2571
2894
|
.markdy-control-rate {
|
|
2572
2895
|
font-family: "JetBrains Mono", monospace, system-ui;
|
|
2573
2896
|
font-size: 9px;
|
|
@@ -2839,7 +3162,9 @@ function createDiagram(opts) {
|
|
|
2839
3162
|
resetView: resetViewButton,
|
|
2840
3163
|
fullscreen: fullscreenButton,
|
|
2841
3164
|
svg: svgButton,
|
|
2842
|
-
share: shareButton
|
|
3165
|
+
share: shareButton,
|
|
3166
|
+
code: codeButton,
|
|
3167
|
+
theme: themeButton
|
|
2843
3168
|
} = player.controls;
|
|
2844
3169
|
const copyright = player.chrome.badge;
|
|
2845
3170
|
const progressMode = player.chrome.progress;
|
|
@@ -2916,22 +3241,13 @@ function createDiagram(opts) {
|
|
|
2916
3241
|
let badge = null;
|
|
2917
3242
|
if (copyright) {
|
|
2918
3243
|
badge = document.createElement("a");
|
|
3244
|
+
badge.className = "markdy-badge";
|
|
2919
3245
|
badge.href = `${MARKDY_PLAYGROUND_URL}#code=${encodeCodeForPlaygroundHash(code)}`;
|
|
2920
3246
|
badge.target = "_blank";
|
|
2921
3247
|
badge.rel = "noopener noreferrer";
|
|
2922
|
-
badge.
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
alignItems: "center",
|
|
2926
|
-
textAlign: "right",
|
|
2927
|
-
fontSize: "10px",
|
|
2928
|
-
fontFamily: "system-ui, sans-serif",
|
|
2929
|
-
color: "#999",
|
|
2930
|
-
textDecoration: "none",
|
|
2931
|
-
padding: "0",
|
|
2932
|
-
opacity: "0.7",
|
|
2933
|
-
marginLeft: "auto"
|
|
2934
|
-
});
|
|
3248
|
+
badge.title = "Open and edit in Markdy Playground";
|
|
3249
|
+
badge.style.marginLeft = "auto";
|
|
3250
|
+
badge.innerHTML = `<span style="opacity:0.9">\u26A1</span> Markdy`;
|
|
2935
3251
|
ensureFooter().appendChild(badge);
|
|
2936
3252
|
}
|
|
2937
3253
|
ensureSceneStyles(document);
|
|
@@ -2973,7 +3289,7 @@ function createDiagram(opts) {
|
|
|
2973
3289
|
Object.assign(structuralEdgeHost.style, {
|
|
2974
3290
|
position: "absolute",
|
|
2975
3291
|
inset: "0",
|
|
2976
|
-
zIndex: "
|
|
3292
|
+
zIndex: "55",
|
|
2977
3293
|
pointerEvents: "none"
|
|
2978
3294
|
});
|
|
2979
3295
|
cameraLayer.appendChild(structuralEdgeHost);
|
|
@@ -3159,8 +3475,24 @@ function createDiagram(opts) {
|
|
|
3159
3475
|
let controlsPlayButton = null;
|
|
3160
3476
|
let controlsRateButtons = [];
|
|
3161
3477
|
let controlsSeekBar = null;
|
|
3478
|
+
let controlsTimeEl = null;
|
|
3162
3479
|
let controlsFitButton = null;
|
|
3163
3480
|
let fitViewActive = false;
|
|
3481
|
+
const ICONS2 = {
|
|
3482
|
+
play: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>',
|
|
3483
|
+
pause: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>',
|
|
3484
|
+
restart: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>',
|
|
3485
|
+
prevBeat: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 6h2v12H6zm3.5 6 8.5 6V6z"/></svg>',
|
|
3486
|
+
nextBeat: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>',
|
|
3487
|
+
fit: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg>',
|
|
3488
|
+
resetView: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg>',
|
|
3489
|
+
fullscreen: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>',
|
|
3490
|
+
svg: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>',
|
|
3491
|
+
share: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>',
|
|
3492
|
+
code: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>',
|
|
3493
|
+
theme: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 3v18"/><path d="M12 3a9 9 0 0 1 0 18z" fill="currentColor"/></svg>',
|
|
3494
|
+
check: '<svg class="markdy-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>'
|
|
3495
|
+
};
|
|
3164
3496
|
function applyViewportTransform() {
|
|
3165
3497
|
viewportTransform.style.transform = `translate(${viewportPanX}px, ${viewportPanY}px) scale(${viewportScale})`;
|
|
3166
3498
|
}
|
|
@@ -3247,7 +3579,7 @@ function createDiagram(opts) {
|
|
|
3247
3579
|
function syncControls() {
|
|
3248
3580
|
if (controlsPlayButton) {
|
|
3249
3581
|
const playing = isPlaying;
|
|
3250
|
-
controlsPlayButton.
|
|
3582
|
+
controlsPlayButton.innerHTML = `${playing ? ICONS2.pause : ICONS2.play}${playing ? "Pause" : "Play"}`;
|
|
3251
3583
|
const playLabel = playing ? "Pause diagram" : "Play diagram";
|
|
3252
3584
|
controlsPlayButton.setAttribute("aria-label", playLabel);
|
|
3253
3585
|
controlsPlayButton.title = playLabel;
|
|
@@ -3257,7 +3589,16 @@ function createDiagram(opts) {
|
|
|
3257
3589
|
const active = Math.abs(rate - playbackRate) < 1e-3;
|
|
3258
3590
|
button.setAttribute("aria-pressed", active ? "true" : "false");
|
|
3259
3591
|
}
|
|
3260
|
-
if (controlsSeekBar)
|
|
3592
|
+
if (controlsSeekBar) {
|
|
3593
|
+
controlsSeekBar.value = String(sceneMs / 1e3);
|
|
3594
|
+
const pct = totalDurationMs > 0 ? sceneMs / totalDurationMs * 100 : 0;
|
|
3595
|
+
controlsSeekBar.style.setProperty("--seek-pct", `${pct}%`);
|
|
3596
|
+
}
|
|
3597
|
+
if (controlsTimeEl) {
|
|
3598
|
+
const cur = (sceneMs / 1e3).toFixed(1);
|
|
3599
|
+
const tot = durationSeconds.toFixed(1);
|
|
3600
|
+
controlsTimeEl.textContent = `${cur}s / ${tot}s`;
|
|
3601
|
+
}
|
|
3261
3602
|
if (controlsFitButton) {
|
|
3262
3603
|
controlsFitButton.setAttribute("aria-pressed", fitViewActive ? "true" : "false");
|
|
3263
3604
|
}
|
|
@@ -3367,17 +3708,21 @@ function createDiagram(opts) {
|
|
|
3367
3708
|
diagram.play();
|
|
3368
3709
|
}
|
|
3369
3710
|
}
|
|
3370
|
-
function makeControlButton(label, ariaLabel) {
|
|
3711
|
+
function makeControlButton(label, ariaLabel, iconSvg) {
|
|
3371
3712
|
const button = document.createElement("button");
|
|
3372
3713
|
button.type = "button";
|
|
3373
|
-
button.textContent = label;
|
|
3374
3714
|
button.setAttribute("aria-label", ariaLabel);
|
|
3375
3715
|
button.title = ariaLabel;
|
|
3716
|
+
if (iconSvg) {
|
|
3717
|
+
button.innerHTML = `${iconSvg}${label}`;
|
|
3718
|
+
} else {
|
|
3719
|
+
button.textContent = label;
|
|
3720
|
+
}
|
|
3376
3721
|
return button;
|
|
3377
3722
|
}
|
|
3378
3723
|
function mountPlayControl(toolbar) {
|
|
3379
3724
|
if (!playButton) return;
|
|
3380
|
-
controlsPlayButton = makeControlButton("Play", "Play diagram");
|
|
3725
|
+
controlsPlayButton = makeControlButton("Play", "Play diagram", ICONS2.play);
|
|
3381
3726
|
controlsPlayButton.className = "markdy-control-play";
|
|
3382
3727
|
controlsPlayButton.addEventListener("click", togglePlayback);
|
|
3383
3728
|
toolbar.appendChild(controlsPlayButton);
|
|
@@ -3386,14 +3731,15 @@ function createDiagram(opts) {
|
|
|
3386
3731
|
const wanted = position === "prev" ? prevBeatButton : nextBeatButton;
|
|
3387
3732
|
if (!wanted || plan.beats.length < 2) return;
|
|
3388
3733
|
const label = position === "prev" ? "Prev" : "Next";
|
|
3389
|
-
const
|
|
3734
|
+
const icon = position === "prev" ? ICONS2.prevBeat : ICONS2.nextBeat;
|
|
3735
|
+
const button = makeControlButton(label, `${label === "Prev" ? "Previous" : "Next"} beat`, icon);
|
|
3390
3736
|
button.className = `markdy-control-${position}-beat`;
|
|
3391
3737
|
button.addEventListener("click", () => position === "prev" ? diagram.prevBeat() : diagram.nextBeat());
|
|
3392
3738
|
toolbar.appendChild(button);
|
|
3393
3739
|
}
|
|
3394
3740
|
function mountRestartControl(toolbar) {
|
|
3395
3741
|
if (!restartButton) return;
|
|
3396
|
-
const button = makeControlButton("Restart", "Restart diagram");
|
|
3742
|
+
const button = makeControlButton("Restart", "Restart diagram", ICONS2.restart);
|
|
3397
3743
|
button.className = "markdy-control-restart";
|
|
3398
3744
|
button.addEventListener("click", () => {
|
|
3399
3745
|
diagram.seek(0);
|
|
@@ -3413,6 +3759,10 @@ function createDiagram(opts) {
|
|
|
3413
3759
|
controlsSeekBar.setAttribute("aria-label", "Seek diagram timeline");
|
|
3414
3760
|
controlsSeekBar.addEventListener("input", () => diagram.seek(Number(controlsSeekBar?.value ?? 0)));
|
|
3415
3761
|
toolbar.appendChild(controlsSeekBar);
|
|
3762
|
+
controlsTimeEl = document.createElement("span");
|
|
3763
|
+
controlsTimeEl.className = "markdy-control-time";
|
|
3764
|
+
controlsTimeEl.textContent = `${(sceneMs / 1e3).toFixed(1)}s / ${durationSeconds.toFixed(1)}s`;
|
|
3765
|
+
toolbar.appendChild(controlsTimeEl);
|
|
3416
3766
|
}
|
|
3417
3767
|
function mountSpeedControls(toolbar) {
|
|
3418
3768
|
if (!speedControls) return;
|
|
@@ -3427,11 +3777,14 @@ function createDiagram(opts) {
|
|
|
3427
3777
|
});
|
|
3428
3778
|
}
|
|
3429
3779
|
function flashControlLabel(button, message) {
|
|
3430
|
-
const
|
|
3431
|
-
|
|
3780
|
+
const originalHtml = button.innerHTML;
|
|
3781
|
+
const isSuccess = !message.toLowerCase().includes("fail");
|
|
3782
|
+
button.innerHTML = isSuccess ? `${ICONS2.check}${message}` : message;
|
|
3783
|
+
button.classList.add("markdy-btn-flashed");
|
|
3432
3784
|
setTimeout(() => {
|
|
3433
|
-
button.
|
|
3434
|
-
|
|
3785
|
+
button.innerHTML = originalHtml;
|
|
3786
|
+
button.classList.remove("markdy-btn-flashed");
|
|
3787
|
+
}, 1500);
|
|
3435
3788
|
}
|
|
3436
3789
|
function downloadFile(filename, contents, type) {
|
|
3437
3790
|
const blob = new Blob([contents], { type });
|
|
@@ -3447,7 +3800,7 @@ function createDiagram(opts) {
|
|
|
3447
3800
|
}
|
|
3448
3801
|
function mountSvgControl(toolbar) {
|
|
3449
3802
|
if (!svgButton) return;
|
|
3450
|
-
const button = makeControlButton("SVG", "Export diagram as SVG");
|
|
3803
|
+
const button = makeControlButton("SVG", "Export diagram as SVG", ICONS2.svg);
|
|
3451
3804
|
button.className = "markdy-control-svg";
|
|
3452
3805
|
button.addEventListener("click", async () => {
|
|
3453
3806
|
const resumeAt = sceneMs;
|
|
@@ -3459,6 +3812,7 @@ function createDiagram(opts) {
|
|
|
3459
3812
|
const svg = exportDiagramAsVectorSvg2(container);
|
|
3460
3813
|
const name = (plan.title || "markdy-diagram").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
3461
3814
|
downloadFile(`${name || "markdy-diagram"}.svg`, svg, "image/svg+xml");
|
|
3815
|
+
flashControlLabel(button, "Saved");
|
|
3462
3816
|
} catch (error) {
|
|
3463
3817
|
onWarning({ severity: "warning", message: `SVG export failed: ${String(error)}`, line: 0 });
|
|
3464
3818
|
flashControlLabel(button, "Failed");
|
|
@@ -3471,7 +3825,7 @@ function createDiagram(opts) {
|
|
|
3471
3825
|
}
|
|
3472
3826
|
function mountShareControl(toolbar) {
|
|
3473
3827
|
if (!shareButton) return;
|
|
3474
|
-
const button = makeControlButton("Share", "Copy a share link for this diagram");
|
|
3828
|
+
const button = makeControlButton("Share", "Copy a share link for this diagram", ICONS2.share);
|
|
3475
3829
|
button.className = "markdy-control-share";
|
|
3476
3830
|
button.addEventListener("click", async () => {
|
|
3477
3831
|
try {
|
|
@@ -3486,9 +3840,132 @@ function createDiagram(opts) {
|
|
|
3486
3840
|
});
|
|
3487
3841
|
toolbar.appendChild(button);
|
|
3488
3842
|
}
|
|
3843
|
+
function mountThemeControl(toolbar) {
|
|
3844
|
+
if (!themeButton) return;
|
|
3845
|
+
const button = makeControlButton("Theme", "Toggle dark/light theme palette", ICONS2.theme);
|
|
3846
|
+
button.className = "markdy-control-theme";
|
|
3847
|
+
button.addEventListener("click", () => {
|
|
3848
|
+
const darkThemes = ["midnight", "blueprint", "graphite", "nebula", "terminal"];
|
|
3849
|
+
const lightThemes = ["paper", "editorial", "sketchy"];
|
|
3850
|
+
const currentName = plan.theme.name || "paper";
|
|
3851
|
+
const isDark = darkThemes.includes(currentName);
|
|
3852
|
+
const targetThemes = isDark ? lightThemes : darkThemes;
|
|
3853
|
+
const nextTheme = targetThemes[Math.floor(Math.random() * targetThemes.length)];
|
|
3854
|
+
flashControlLabel(button, nextTheme);
|
|
3855
|
+
container.dispatchEvent(
|
|
3856
|
+
new CustomEvent("markdy-theme-switch", {
|
|
3857
|
+
bubbles: true,
|
|
3858
|
+
detail: { theme: nextTheme, isDark: !isDark }
|
|
3859
|
+
})
|
|
3860
|
+
);
|
|
3861
|
+
});
|
|
3862
|
+
toolbar.appendChild(button);
|
|
3863
|
+
}
|
|
3864
|
+
function tintCode(raw) {
|
|
3865
|
+
return raw.split("\n").map((line) => {
|
|
3866
|
+
if (/^\s*\/\//.test(line)) {
|
|
3867
|
+
return `<span class="t-comment">${escHtml(line)}</span>`;
|
|
3868
|
+
}
|
|
3869
|
+
line = line.replace(/(->|<-|~>|--|<~)/g, '<span class="t-edge">$1</span>');
|
|
3870
|
+
line = line.replace(/"([^"]*)"/g, '"<span class="t-string">$1</span>"');
|
|
3871
|
+
line = line.replace(
|
|
3872
|
+
/^(\s*)(scene|beat|group|player|show|frame|glow|focus|layout|edge|annotation|start|end|decision|service|browser|gateway|database|cache|queue|worker|function|pod|user|client|hub|station|metric|mobile)\b/,
|
|
3873
|
+
'$1<span class="t-keyword">$2</span>'
|
|
3874
|
+
);
|
|
3875
|
+
line = line.replace(/\b(\d[\d.]*(?:ms|px|s)?)\b/g, '<span class="t-number">$1</span>');
|
|
3876
|
+
return line;
|
|
3877
|
+
}).join("\n");
|
|
3878
|
+
}
|
|
3879
|
+
function escHtml(str) {
|
|
3880
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
3881
|
+
}
|
|
3882
|
+
function mountCodeControl(toolbar) {
|
|
3883
|
+
if (!codeButton) return;
|
|
3884
|
+
const button = makeControlButton("Code", "View MarkdyScript source");
|
|
3885
|
+
button.className = "markdy-control-code";
|
|
3886
|
+
button.setAttribute("aria-haspopup", "dialog");
|
|
3887
|
+
button.addEventListener("click", () => {
|
|
3888
|
+
const overlay = document.createElement("div");
|
|
3889
|
+
overlay.className = "markdy-code-panel-overlay";
|
|
3890
|
+
overlay.setAttribute("role", "dialog");
|
|
3891
|
+
overlay.setAttribute("aria-modal", "true");
|
|
3892
|
+
overlay.setAttribute("aria-label", "MarkdyScript source code");
|
|
3893
|
+
const panel = document.createElement("div");
|
|
3894
|
+
panel.className = "markdy-code-panel";
|
|
3895
|
+
const header = document.createElement("div");
|
|
3896
|
+
header.className = "markdy-code-panel__header";
|
|
3897
|
+
const title = document.createElement("div");
|
|
3898
|
+
title.className = "markdy-code-panel__title";
|
|
3899
|
+
title.textContent = "MarkdyScript source";
|
|
3900
|
+
const actions = document.createElement("div");
|
|
3901
|
+
actions.className = "markdy-code-panel__actions";
|
|
3902
|
+
const copyBtn = document.createElement("button");
|
|
3903
|
+
copyBtn.type = "button";
|
|
3904
|
+
copyBtn.className = "markdy-code-panel__copy";
|
|
3905
|
+
copyBtn.textContent = "Copy";
|
|
3906
|
+
copyBtn.setAttribute("aria-label", "Copy source code to clipboard");
|
|
3907
|
+
copyBtn.addEventListener("click", async () => {
|
|
3908
|
+
try {
|
|
3909
|
+
await navigator.clipboard.writeText(code);
|
|
3910
|
+
copyBtn.textContent = "Copied \u2713";
|
|
3911
|
+
setTimeout(() => {
|
|
3912
|
+
copyBtn.textContent = "Copy";
|
|
3913
|
+
}, 1800);
|
|
3914
|
+
} catch {
|
|
3915
|
+
copyBtn.textContent = "Failed";
|
|
3916
|
+
setTimeout(() => {
|
|
3917
|
+
copyBtn.textContent = "Copy";
|
|
3918
|
+
}, 1800);
|
|
3919
|
+
}
|
|
3920
|
+
});
|
|
3921
|
+
const playgroundBtn = document.createElement("a");
|
|
3922
|
+
playgroundBtn.className = "markdy-code-panel__playground";
|
|
3923
|
+
playgroundBtn.href = `${shareUrl ?? MARKDY_PLAYGROUND_URL}#code=${encodeCodeForPlaygroundHash(code)}`;
|
|
3924
|
+
playgroundBtn.target = "_blank";
|
|
3925
|
+
playgroundBtn.rel = "noopener noreferrer";
|
|
3926
|
+
playgroundBtn.textContent = "Open in Studio \u2197";
|
|
3927
|
+
playgroundBtn.setAttribute("aria-label", "Open diagram in Markdy Studio playground");
|
|
3928
|
+
const closeBtn = document.createElement("button");
|
|
3929
|
+
closeBtn.type = "button";
|
|
3930
|
+
closeBtn.className = "markdy-code-panel__close";
|
|
3931
|
+
closeBtn.textContent = "\u2715 Close";
|
|
3932
|
+
closeBtn.setAttribute("aria-label", "Close code panel");
|
|
3933
|
+
actions.append(copyBtn, playgroundBtn, closeBtn);
|
|
3934
|
+
header.append(title, actions);
|
|
3935
|
+
const body = document.createElement("div");
|
|
3936
|
+
body.className = "markdy-code-panel__body";
|
|
3937
|
+
const pre = document.createElement("pre");
|
|
3938
|
+
pre.className = "markdy-code-panel__pre";
|
|
3939
|
+
pre.innerHTML = tintCode(code);
|
|
3940
|
+
body.appendChild(pre);
|
|
3941
|
+
panel.append(header, body);
|
|
3942
|
+
overlay.appendChild(panel);
|
|
3943
|
+
document.body.appendChild(overlay);
|
|
3944
|
+
closeBtn.focus();
|
|
3945
|
+
function closePanel() {
|
|
3946
|
+
overlay.dataset.closing = "1";
|
|
3947
|
+
overlay.addEventListener("animationend", () => overlay.remove(), { once: true });
|
|
3948
|
+
}
|
|
3949
|
+
closeBtn.addEventListener("click", closePanel);
|
|
3950
|
+
overlay.addEventListener("click", (e) => {
|
|
3951
|
+
if (e.target === overlay) closePanel();
|
|
3952
|
+
});
|
|
3953
|
+
function handleEscape(e) {
|
|
3954
|
+
if (e.key === "Escape") {
|
|
3955
|
+
closePanel();
|
|
3956
|
+
document.removeEventListener("keydown", handleEscape);
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
document.addEventListener("keydown", handleEscape);
|
|
3960
|
+
overlay.addEventListener("animationend", () => {
|
|
3961
|
+
if (overlay.dataset.closing === "1") document.removeEventListener("keydown", handleEscape);
|
|
3962
|
+
}, { once: true });
|
|
3963
|
+
});
|
|
3964
|
+
toolbar.appendChild(button);
|
|
3965
|
+
}
|
|
3489
3966
|
function mountFitControl(toolbar) {
|
|
3490
3967
|
if (!fitViewButton) return;
|
|
3491
|
-
controlsFitButton = makeControlButton("Fit", "Fit all items in view and ignore camera zoom");
|
|
3968
|
+
controlsFitButton = makeControlButton("Fit", "Fit all items in view and ignore camera zoom", ICONS2.fit);
|
|
3492
3969
|
controlsFitButton.className = "markdy-control-fit";
|
|
3493
3970
|
controlsFitButton.setAttribute("aria-pressed", "false");
|
|
3494
3971
|
controlsFitButton.addEventListener("click", toggleFitView);
|
|
@@ -3496,14 +3973,14 @@ function createDiagram(opts) {
|
|
|
3496
3973
|
}
|
|
3497
3974
|
function mountResetViewControl(toolbar) {
|
|
3498
3975
|
if (!resetViewButton) return;
|
|
3499
|
-
const button = makeControlButton("Reset", "Reset diagram view");
|
|
3976
|
+
const button = makeControlButton("Reset", "Reset diagram view", ICONS2.resetView);
|
|
3500
3977
|
button.className = "markdy-control-reset-view";
|
|
3501
3978
|
button.addEventListener("click", resetViewportTransform);
|
|
3502
3979
|
toolbar.appendChild(button);
|
|
3503
3980
|
}
|
|
3504
3981
|
function mountFullscreenControl(toolbar) {
|
|
3505
3982
|
if (!fullscreenButton) return;
|
|
3506
|
-
const button = makeControlButton("Full", "Toggle fullscreen view");
|
|
3983
|
+
const button = makeControlButton("Full", "Toggle fullscreen view", ICONS2.fullscreen);
|
|
3507
3984
|
button.className = "markdy-control-fullscreen";
|
|
3508
3985
|
button.setAttribute("aria-pressed", "false");
|
|
3509
3986
|
const host = container.parentElement ?? container;
|
|
@@ -3584,17 +4061,49 @@ function createDiagram(opts) {
|
|
|
3584
4061
|
for (const eventName of ["click", "dblclick", "pointerdown", "pointermove", "pointerup", "wheel"]) {
|
|
3585
4062
|
toolbar.addEventListener(eventName, (event) => event.stopPropagation());
|
|
3586
4063
|
}
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
4064
|
+
const playbackGroup = document.createElement("div");
|
|
4065
|
+
playbackGroup.className = "markdy-controls-group markdy-controls-playback";
|
|
4066
|
+
mountPlayControl(playbackGroup);
|
|
4067
|
+
mountBeatNavControls(playbackGroup, "prev");
|
|
4068
|
+
mountBeatNavControls(playbackGroup, "next");
|
|
4069
|
+
mountRestartControl(playbackGroup);
|
|
4070
|
+
if (playbackGroup.children.length > 0) toolbar.appendChild(playbackGroup);
|
|
4071
|
+
if (seekBar) {
|
|
4072
|
+
const timelineGroup = document.createElement("div");
|
|
4073
|
+
timelineGroup.className = "markdy-controls-group markdy-controls-timeline";
|
|
4074
|
+
mountSeekControl(timelineGroup);
|
|
4075
|
+
toolbar.appendChild(timelineGroup);
|
|
4076
|
+
}
|
|
4077
|
+
const toolsGroup = document.createElement("div");
|
|
4078
|
+
toolsGroup.className = "markdy-controls-group markdy-controls-tools";
|
|
4079
|
+
if (speedControls) {
|
|
4080
|
+
const speedGroup = document.createElement("div");
|
|
4081
|
+
speedGroup.className = "markdy-speed-group";
|
|
4082
|
+
mountSpeedControls(speedGroup);
|
|
4083
|
+
toolsGroup.appendChild(speedGroup);
|
|
4084
|
+
}
|
|
4085
|
+
if (fitViewButton || resetViewButton || fullscreenButton) {
|
|
4086
|
+
if (toolsGroup.children.length > 0) {
|
|
4087
|
+
const divider = document.createElement("div");
|
|
4088
|
+
divider.className = "markdy-control-divider";
|
|
4089
|
+
toolsGroup.appendChild(divider);
|
|
4090
|
+
}
|
|
4091
|
+
mountFitControl(toolsGroup);
|
|
4092
|
+
mountResetViewControl(toolsGroup);
|
|
4093
|
+
mountFullscreenControl(toolsGroup);
|
|
4094
|
+
}
|
|
4095
|
+
if (svgButton || shareButton || codeButton || themeButton) {
|
|
4096
|
+
if (toolsGroup.children.length > 0) {
|
|
4097
|
+
const divider = document.createElement("div");
|
|
4098
|
+
divider.className = "markdy-control-divider";
|
|
4099
|
+
toolsGroup.appendChild(divider);
|
|
4100
|
+
}
|
|
4101
|
+
mountThemeControl(toolsGroup);
|
|
4102
|
+
mountSvgControl(toolsGroup);
|
|
4103
|
+
mountShareControl(toolsGroup);
|
|
4104
|
+
mountCodeControl(toolsGroup);
|
|
4105
|
+
}
|
|
4106
|
+
if (toolsGroup.children.length > 0) toolbar.appendChild(toolsGroup);
|
|
3598
4107
|
ensureFooter().insertBefore(toolbar, badge ?? null);
|
|
3599
4108
|
syncControls();
|
|
3600
4109
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"description": "Browser renderer for diagram-native animated MarkdyScript architecture diagrams, built on the Web Animations API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"html2canvas": "^1.4.1",
|
|
48
|
-
"@markdy/core": "1.0.
|
|
48
|
+
"@markdy/core": "1.0.14"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"jsdom": "^29.1.1",
|
|
52
52
|
"tsup": "^8.5.1",
|
|
53
53
|
"typescript": "^5.9.3",
|
|
54
54
|
"vitest": "^4.1.7",
|
|
55
|
-
"@markdy/stdlib-systems": "1.0.
|
|
55
|
+
"@markdy/stdlib-systems": "1.0.14"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsup",
|