@veolab/discoverylab 1.4.2 → 1.4.4
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/{chunk-MDKX7CCB.js → chunk-2UUMLAVR.js} +71 -8695
- package/dist/{chunk-34KRJWZL.js → chunk-34GGYFXX.js} +1 -1
- package/dist/{chunk-DGXAP477.js → chunk-3ERJNXYM.js} +1 -1
- package/dist/{chunk-VYYAP5G5.js → chunk-6GK5K6CS.js} +2 -2
- package/dist/{chunk-DKAX5RCX.js → chunk-7R5YNOXE.js} +1 -1
- package/dist/{chunk-RCY26WEK.js → chunk-CUBQRT5L.js} +2 -2
- package/dist/{chunk-EU63HPKT.js → chunk-GRU332L4.js} +1 -1
- package/dist/{chunk-YNLUOZSZ.js → chunk-HB3YPWF3.js} +6 -6
- package/dist/{chunk-SWZIBO2R.js → chunk-ILDZMFOR.js} +1 -1
- package/dist/{chunk-QMUEC6B5.js → chunk-PMCXEA7J.js} +2 -2
- package/dist/chunk-R5U7XKVJ.js +16 -0
- package/dist/{chunk-XAMA3JJG.js → chunk-YYOK2RF7.js} +1 -1
- package/dist/cli.js +29 -29
- package/dist/{db-745LC5YC.js → db-5ECN3O7F.js} +2 -2
- package/dist/{document-AE4XI2CP.js → document-64X4JTLM.js} +1 -1
- package/dist/{esvp-4LIAU76K.js → esvp-DKZXSABS.js} +3 -3
- package/dist/{esvp-mobile-FKFHDS5Q.js → esvp-mobile-TMNCSWHF.js} +4 -4
- package/dist/{frames-RCNLSDD6.js → frames-2NFCSKXQ.js} +3 -3
- package/dist/{gridCompositor-VUWBZXYL.js → gridCompositor-WC4KSGSQ.js} +1 -1
- package/dist/index.js +12 -12
- package/dist/{notion-api-OXSWOJPZ.js → notion-api-ZHGIYCQU.js} +1 -1
- package/dist/{ocr-FXRLEP66.js → ocr-YUYGFUKU.js} +1 -1
- package/dist/{playwright-GYKUH34L.js → playwright-JXLD4CM5.js} +3 -3
- package/dist/{renderer-D22GCMMD.js → renderer-KHPDJF5E.js} +4 -4
- package/dist/{server-NTT2XGCC.js → server-OVOACIOJ.js} +1 -1
- package/dist/server-QFNKZCOJ.js +24 -0
- package/dist/{setup-O6WQQAGP.js → setup-6JJYKKBS.js} +3 -3
- package/dist/{tools-FVVWKEGC.js → tools-Q7OZO732.js} +9 -9
- package/dist/visualizations/app-flow-map.html +177 -0
- package/dist/visualizations/device-showcase.html +150 -0
- package/dist/visualizations/flow-diagram.html +181 -0
- package/dist/visualizations/metrics-dashboard.html +263 -0
- package/package.json +3 -3
- package/dist/chunk-4VNS5WPM.js +0 -42
- package/dist/server-3DEELYXB.js +0 -24
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
setupInstallTool,
|
|
5
5
|
setupStatusTool,
|
|
6
6
|
setupTools
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CUBQRT5L.js";
|
|
8
8
|
import "./chunk-XKX6NBHF.js";
|
|
9
9
|
import "./chunk-6EGBXRDK.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-YYOK2RF7.js";
|
|
11
|
+
import "./chunk-R5U7XKVJ.js";
|
|
12
12
|
export {
|
|
13
13
|
setupCheckTool,
|
|
14
14
|
setupInitTool,
|
|
@@ -107,25 +107,25 @@ import {
|
|
|
107
107
|
uiStatusTool,
|
|
108
108
|
uiTools,
|
|
109
109
|
videoInfoTool
|
|
110
|
-
} from "./chunk-
|
|
111
|
-
import "./chunk-
|
|
110
|
+
} from "./chunk-HB3YPWF3.js";
|
|
111
|
+
import "./chunk-PMCXEA7J.js";
|
|
112
112
|
import {
|
|
113
113
|
setupCheckTool,
|
|
114
114
|
setupInitTool,
|
|
115
115
|
setupStatusTool,
|
|
116
116
|
setupTools
|
|
117
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-CUBQRT5L.js";
|
|
118
118
|
import "./chunk-XKX6NBHF.js";
|
|
119
|
-
import "./chunk-
|
|
120
|
-
import "./chunk-
|
|
121
|
-
import "./chunk-
|
|
119
|
+
import "./chunk-34GGYFXX.js";
|
|
120
|
+
import "./chunk-7R5YNOXE.js";
|
|
121
|
+
import "./chunk-3ERJNXYM.js";
|
|
122
122
|
import "./chunk-LB3RNE3O.js";
|
|
123
|
-
import "./chunk-
|
|
123
|
+
import "./chunk-GRU332L4.js";
|
|
124
124
|
import "./chunk-6EGBXRDK.js";
|
|
125
125
|
import "./chunk-SLNJEF32.js";
|
|
126
|
-
import "./chunk-
|
|
126
|
+
import "./chunk-YYOK2RF7.js";
|
|
127
127
|
import "./chunk-XFVDP332.js";
|
|
128
|
-
import "./chunk-
|
|
128
|
+
import "./chunk-R5U7XKVJ.js";
|
|
129
129
|
export {
|
|
130
130
|
analyzeScreenshotTool,
|
|
131
131
|
analyzeTools,
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>App Flow Map</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: #1a1a2e;
|
|
11
|
+
color: #e0e0e0;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
padding: 32px;
|
|
15
|
+
overflow-x: hidden;
|
|
16
|
+
}
|
|
17
|
+
.map { max-width: 900px; margin: 0 auto; }
|
|
18
|
+
.map-header {
|
|
19
|
+
text-align: center; margin-bottom: 36px;
|
|
20
|
+
opacity: 0; animation: fadeIn 0.6s 0.1s forwards;
|
|
21
|
+
}
|
|
22
|
+
.map-header h1 { font-size: 24px; font-weight: 700; color: #fff; }
|
|
23
|
+
.map-header p { font-size: 13px; color: rgba(255,255,255,0.45); margin-top: 6px; }
|
|
24
|
+
@keyframes fadeIn { to { opacity: 1; } }
|
|
25
|
+
@keyframes slideUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
|
|
26
|
+
|
|
27
|
+
/* Phase blocks */
|
|
28
|
+
.phase {
|
|
29
|
+
border-radius: 16px;
|
|
30
|
+
padding: 20px;
|
|
31
|
+
margin-bottom: 0;
|
|
32
|
+
opacity: 0;
|
|
33
|
+
animation: slideUp 0.5s forwards;
|
|
34
|
+
position: relative;
|
|
35
|
+
}
|
|
36
|
+
.phase-title { font-size: 16px; font-weight: 700; color: #fff; margin-bottom: 4px; }
|
|
37
|
+
.phase-desc { font-size: 12px; opacity: 0.6; margin-bottom: 14px; }
|
|
38
|
+
|
|
39
|
+
/* Phase color themes */
|
|
40
|
+
.phase-0 { background: rgba(34, 197, 94, 0.12); border: 1px solid rgba(34, 197, 94, 0.25); }
|
|
41
|
+
.phase-0 .phase-title { color: #86efac; }
|
|
42
|
+
.phase-1 { background: rgba(99, 102, 241, 0.12); border: 1px solid rgba(99, 102, 241, 0.25); }
|
|
43
|
+
.phase-1 .phase-title { color: #a5b4fc; }
|
|
44
|
+
.phase-2 { background: rgba(234, 179, 8, 0.12); border: 1px solid rgba(234, 179, 8, 0.25); }
|
|
45
|
+
.phase-2 .phase-title { color: #fde047; }
|
|
46
|
+
.phase-3 { background: rgba(236, 72, 153, 0.12); border: 1px solid rgba(236, 72, 153, 0.25); }
|
|
47
|
+
.phase-3 .phase-title { color: #f9a8d4; }
|
|
48
|
+
.phase-4 { background: rgba(14, 165, 233, 0.12); border: 1px solid rgba(14, 165, 233, 0.25); }
|
|
49
|
+
.phase-4 .phase-title { color: #7dd3fc; }
|
|
50
|
+
|
|
51
|
+
/* Screen cards inside phases */
|
|
52
|
+
.phase-screens {
|
|
53
|
+
display: flex; gap: 10px; overflow-x: auto; padding: 4px 0;
|
|
54
|
+
}
|
|
55
|
+
.screen-card {
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
background: rgba(255,255,255,0.06);
|
|
58
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
59
|
+
border-radius: 10px;
|
|
60
|
+
padding: 8px;
|
|
61
|
+
min-width: 130px;
|
|
62
|
+
max-width: 160px;
|
|
63
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
|
64
|
+
}
|
|
65
|
+
.screen-card:hover {
|
|
66
|
+
transform: translateY(-2px);
|
|
67
|
+
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
|
|
68
|
+
}
|
|
69
|
+
.screen-card-img {
|
|
70
|
+
width: 100%; height: 180px;
|
|
71
|
+
border-radius: 6px; overflow: hidden;
|
|
72
|
+
background: #000; margin-bottom: 6px;
|
|
73
|
+
}
|
|
74
|
+
.screen-card-img img { width: 100%; height: 100%; object-fit: contain; }
|
|
75
|
+
.screen-card-label { font-size: 11px; font-weight: 600; color: rgba(255,255,255,0.85); }
|
|
76
|
+
.screen-card-detail { font-size: 10px; color: rgba(255,255,255,0.4); margin-top: 2px; }
|
|
77
|
+
|
|
78
|
+
/* Arrow connector between phases */
|
|
79
|
+
.arrow-connector {
|
|
80
|
+
display: flex; align-items: center; justify-content: center;
|
|
81
|
+
height: 40px;
|
|
82
|
+
opacity: 0; animation: fadeIn 0.3s forwards;
|
|
83
|
+
}
|
|
84
|
+
.arrow-connector svg {
|
|
85
|
+
stroke: rgba(255,255,255,0.2); fill: none; stroke-width: 2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Insight callout */
|
|
89
|
+
.insight {
|
|
90
|
+
margin-top: 6px; padding: 8px 12px;
|
|
91
|
+
background: rgba(255,255,255,0.04);
|
|
92
|
+
border-left: 3px solid rgba(255,255,255,0.15);
|
|
93
|
+
border-radius: 0 8px 8px 0;
|
|
94
|
+
font-size: 11px; color: rgba(255,255,255,0.55);
|
|
95
|
+
line-height: 1.5;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.footer {
|
|
99
|
+
text-align: center; margin-top: 32px;
|
|
100
|
+
font-size: 10px; color: rgba(255,255,255,0.2);
|
|
101
|
+
}
|
|
102
|
+
.model-label {
|
|
103
|
+
position: fixed; bottom: 10px; right: 14px;
|
|
104
|
+
font-size: 9px; color: rgba(255,255,255,0.2);
|
|
105
|
+
background: rgba(0,0,0,0.3);
|
|
106
|
+
padding: 2px 8px; border-radius: 4px;
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
109
|
+
</head>
|
|
110
|
+
<body>
|
|
111
|
+
<div class="map">
|
|
112
|
+
<div class="map-header">
|
|
113
|
+
<h1 id="mapTitle">App Flow Map</h1>
|
|
114
|
+
<p id="mapSubtitle"></p>
|
|
115
|
+
</div>
|
|
116
|
+
<div id="mapContent"></div>
|
|
117
|
+
<div class="footer" id="mapFooter">Generated by DiscoveryLab</div>
|
|
118
|
+
<div class="model-label" id="modelLabel"></div>
|
|
119
|
+
</div>
|
|
120
|
+
<script>
|
|
121
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
122
|
+
const phases = DATA.phases || [];
|
|
123
|
+
|
|
124
|
+
if (DATA.title) document.getElementById('mapTitle').textContent = DATA.title;
|
|
125
|
+
if (DATA.subtitle) document.getElementById('mapSubtitle').textContent = DATA.subtitle;
|
|
126
|
+
if (DATA.providerName) document.getElementById('modelLabel').textContent = DATA.providerName;
|
|
127
|
+
|
|
128
|
+
const container = document.getElementById('mapContent');
|
|
129
|
+
let animDelay = 0.3;
|
|
130
|
+
|
|
131
|
+
phases.forEach((phase, phaseIdx) => {
|
|
132
|
+
// Arrow between phases
|
|
133
|
+
if (phaseIdx > 0) {
|
|
134
|
+
const arrow = document.createElement('div');
|
|
135
|
+
arrow.className = 'arrow-connector';
|
|
136
|
+
arrow.style.animationDelay = animDelay + 's';
|
|
137
|
+
arrow.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24"><path d="M12 5v14M5 12l7 7 7-7" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
138
|
+
container.appendChild(arrow);
|
|
139
|
+
animDelay += 0.15;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const phaseEl = document.createElement('div');
|
|
143
|
+
phaseEl.className = `phase phase-${phaseIdx % 5}`;
|
|
144
|
+
phaseEl.style.animationDelay = animDelay + 's';
|
|
145
|
+
|
|
146
|
+
let html = `
|
|
147
|
+
<div class="phase-title">${phase.title || 'Phase ' + (phaseIdx + 1)}</div>
|
|
148
|
+
<div class="phase-desc">${phase.description || ''}</div>
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
// Screen cards
|
|
152
|
+
if (phase.screens && phase.screens.length > 0) {
|
|
153
|
+
html += '<div class="phase-screens">';
|
|
154
|
+
phase.screens.forEach(screen => {
|
|
155
|
+
html += `
|
|
156
|
+
<div class="screen-card">
|
|
157
|
+
${screen.imageUrl ? `<div class="screen-card-img"><img src="${screen.imageUrl}" alt="" loading="lazy"></div>` : ''}
|
|
158
|
+
<div class="screen-card-label">${screen.label || ''}</div>
|
|
159
|
+
${screen.detail ? `<div class="screen-card-detail">${screen.detail}</div>` : ''}
|
|
160
|
+
</div>
|
|
161
|
+
`;
|
|
162
|
+
});
|
|
163
|
+
html += '</div>';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Insight
|
|
167
|
+
if (phase.insight) {
|
|
168
|
+
html += `<div class="insight">${phase.insight}</div>`;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
phaseEl.innerHTML = html;
|
|
172
|
+
container.appendChild(phaseEl);
|
|
173
|
+
animDelay += 0.3;
|
|
174
|
+
});
|
|
175
|
+
</script>
|
|
176
|
+
</body>
|
|
177
|
+
</html>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Device Showcase</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: linear-gradient(135deg, #0c0c1d, #1e1e3f, #0c0c1d);
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
}
|
|
20
|
+
.header { text-align: center; margin-bottom: 32px; z-index: 10; }
|
|
21
|
+
.header h1 { font-size: 28px; font-weight: 700; }
|
|
22
|
+
.header p { font-size: 13px; color: rgba(255,255,255,0.5); margin-top: 4px; }
|
|
23
|
+
.carousel-wrapper {
|
|
24
|
+
perspective: 1200px;
|
|
25
|
+
width: 100%;
|
|
26
|
+
max-width: 800px;
|
|
27
|
+
height: 500px;
|
|
28
|
+
position: relative;
|
|
29
|
+
}
|
|
30
|
+
.carousel {
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
position: relative;
|
|
34
|
+
transform-style: preserve-3d;
|
|
35
|
+
animation: spin 20s linear infinite;
|
|
36
|
+
animation-play-state: running;
|
|
37
|
+
}
|
|
38
|
+
.carousel:hover { animation-play-state: paused; }
|
|
39
|
+
@keyframes spin { to { transform: rotateY(360deg); } }
|
|
40
|
+
.device {
|
|
41
|
+
position: absolute;
|
|
42
|
+
width: 200px;
|
|
43
|
+
left: 50%;
|
|
44
|
+
top: 50%;
|
|
45
|
+
margin-left: -100px;
|
|
46
|
+
margin-top: -200px;
|
|
47
|
+
transform-style: preserve-3d;
|
|
48
|
+
transition: transform 0.5s, box-shadow 0.5s;
|
|
49
|
+
}
|
|
50
|
+
.device-frame {
|
|
51
|
+
background: #111;
|
|
52
|
+
border-radius: 24px;
|
|
53
|
+
padding: 8px;
|
|
54
|
+
box-shadow: 0 20px 60px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1);
|
|
55
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
56
|
+
}
|
|
57
|
+
.device-screen {
|
|
58
|
+
border-radius: 16px;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
background: #000;
|
|
61
|
+
}
|
|
62
|
+
.device-screen img {
|
|
63
|
+
width: 100%;
|
|
64
|
+
height: auto;
|
|
65
|
+
display: block;
|
|
66
|
+
}
|
|
67
|
+
.device-label {
|
|
68
|
+
text-align: center;
|
|
69
|
+
font-size: 11px;
|
|
70
|
+
color: rgba(255,255,255,0.5);
|
|
71
|
+
margin-top: 12px;
|
|
72
|
+
}
|
|
73
|
+
.glow {
|
|
74
|
+
position: absolute;
|
|
75
|
+
width: 300px; height: 300px;
|
|
76
|
+
background: radial-gradient(circle, rgba(99,102,241,0.15) 0%, transparent 70%);
|
|
77
|
+
top: 50%; left: 50%;
|
|
78
|
+
transform: translate(-50%, -50%);
|
|
79
|
+
pointer-events: none;
|
|
80
|
+
}
|
|
81
|
+
.footer {
|
|
82
|
+
position: fixed; bottom: 16px;
|
|
83
|
+
font-size: 11px; color: rgba(255,255,255,0.25);
|
|
84
|
+
}
|
|
85
|
+
.nav-dots {
|
|
86
|
+
display: flex; gap: 8px; margin-top: 24px; z-index: 10;
|
|
87
|
+
}
|
|
88
|
+
.nav-dot {
|
|
89
|
+
width: 8px; height: 8px; border-radius: 50%;
|
|
90
|
+
background: rgba(255,255,255,0.2);
|
|
91
|
+
cursor: pointer;
|
|
92
|
+
transition: background 0.3s;
|
|
93
|
+
}
|
|
94
|
+
.nav-dot.active { background: #6366f1; }
|
|
95
|
+
</style>
|
|
96
|
+
</head>
|
|
97
|
+
<body>
|
|
98
|
+
<div class="header">
|
|
99
|
+
<h1 id="vizTitle">Device Showcase</h1>
|
|
100
|
+
<p id="vizSubtitle"></p>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="carousel-wrapper">
|
|
103
|
+
<div class="glow"></div>
|
|
104
|
+
<div class="carousel" id="carousel"></div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="nav-dots" id="navDots"></div>
|
|
107
|
+
<div class="footer" id="vizFooter">Generated by DiscoveryLab</div>
|
|
108
|
+
<script>
|
|
109
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
110
|
+
const screens = DATA.screens || [];
|
|
111
|
+
|
|
112
|
+
if (DATA.title) document.getElementById('vizTitle').textContent = DATA.title;
|
|
113
|
+
if (DATA.subtitle) document.getElementById('vizSubtitle').textContent = DATA.subtitle;
|
|
114
|
+
|
|
115
|
+
const carousel = document.getElementById('carousel');
|
|
116
|
+
const dotsContainer = document.getElementById('navDots');
|
|
117
|
+
const n = screens.length || 1;
|
|
118
|
+
const angleStep = 360 / n;
|
|
119
|
+
const radius = Math.max(250, n * 60);
|
|
120
|
+
|
|
121
|
+
screens.forEach((screen, i) => {
|
|
122
|
+
const angle = angleStep * i;
|
|
123
|
+
const device = document.createElement('div');
|
|
124
|
+
device.className = 'device';
|
|
125
|
+
device.style.transform = `rotateY(${angle}deg) translateZ(${radius}px)`;
|
|
126
|
+
device.innerHTML = `
|
|
127
|
+
<div class="device-frame">
|
|
128
|
+
<div class="device-screen">
|
|
129
|
+
<img src="${screen.imageUrl}" alt="Screen ${i + 1}" loading="lazy">
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="device-label">${screen.label || `Screen ${i + 1}`}</div>
|
|
133
|
+
`;
|
|
134
|
+
carousel.appendChild(device);
|
|
135
|
+
|
|
136
|
+
const dot = document.createElement('div');
|
|
137
|
+
dot.className = `nav-dot ${i === 0 ? 'active' : ''}`;
|
|
138
|
+
dot.addEventListener('click', () => {
|
|
139
|
+
carousel.style.animation = 'none';
|
|
140
|
+
carousel.offsetHeight; // reflow
|
|
141
|
+
carousel.style.transform = `rotateY(${-angle}deg)`;
|
|
142
|
+
carousel.style.transition = 'transform 0.8s ease';
|
|
143
|
+
dotsContainer.querySelectorAll('.nav-dot').forEach(d => d.classList.remove('active'));
|
|
144
|
+
dot.classList.add('active');
|
|
145
|
+
});
|
|
146
|
+
dotsContainer.appendChild(dot);
|
|
147
|
+
});
|
|
148
|
+
</script>
|
|
149
|
+
</body>
|
|
150
|
+
</html>
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Flow Diagram</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
background: linear-gradient(160deg, #0f0f23, #1a1a3e);
|
|
11
|
+
color: #fff;
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
}
|
|
17
|
+
.container {
|
|
18
|
+
flex: 1;
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
padding: 24px;
|
|
22
|
+
max-width: 100%;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
.header { text-align: center; margin-bottom: 20px; flex-shrink: 0; }
|
|
26
|
+
.header h1 { font-size: 22px; font-weight: 700; margin-bottom: 4px; }
|
|
27
|
+
.header p { font-size: 13px; color: rgba(255,255,255,0.5); }
|
|
28
|
+
.flow {
|
|
29
|
+
flex: 1;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
align-items: center;
|
|
33
|
+
justify-content: center;
|
|
34
|
+
gap: 0;
|
|
35
|
+
padding: 10px 0;
|
|
36
|
+
min-height: 0;
|
|
37
|
+
}
|
|
38
|
+
.flow.vertical {
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
overflow-y: auto;
|
|
41
|
+
overflow-x: hidden;
|
|
42
|
+
}
|
|
43
|
+
.step {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
align-items: center;
|
|
47
|
+
flex-shrink: 1;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
max-width: 220px;
|
|
50
|
+
opacity: 0;
|
|
51
|
+
transform: translateY(20px);
|
|
52
|
+
animation: fadeInUp 0.5s forwards;
|
|
53
|
+
/* delay set dynamically via JS for correct sequential order */
|
|
54
|
+
}
|
|
55
|
+
@keyframes fadeInUp {
|
|
56
|
+
to { opacity: 1; transform: translateY(0); }
|
|
57
|
+
}
|
|
58
|
+
.step-badge {
|
|
59
|
+
width: 28px; height: 28px; border-radius: 50%;
|
|
60
|
+
background: #6366f1; color: #fff;
|
|
61
|
+
display: flex; align-items: center; justify-content: center;
|
|
62
|
+
font-size: 12px; font-weight: 700;
|
|
63
|
+
margin-bottom: 8px;
|
|
64
|
+
box-shadow: 0 3px 10px rgba(99,102,241,0.4);
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
}
|
|
67
|
+
.step-screenshot {
|
|
68
|
+
width: 100%;
|
|
69
|
+
max-height: 55vh;
|
|
70
|
+
border-radius: 10px;
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
|
|
73
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
74
|
+
transition: transform 0.3s, box-shadow 0.3s;
|
|
75
|
+
flex-shrink: 1;
|
|
76
|
+
}
|
|
77
|
+
.step-screenshot:hover {
|
|
78
|
+
transform: scale(1.03);
|
|
79
|
+
box-shadow: 0 10px 30px rgba(99,102,241,0.25);
|
|
80
|
+
}
|
|
81
|
+
.step-screenshot img {
|
|
82
|
+
width: 100%;
|
|
83
|
+
height: auto;
|
|
84
|
+
display: block;
|
|
85
|
+
max-height: 55vh;
|
|
86
|
+
object-fit: contain;
|
|
87
|
+
}
|
|
88
|
+
.step-label {
|
|
89
|
+
font-size: 11px;
|
|
90
|
+
color: rgba(255,255,255,0.7);
|
|
91
|
+
margin-top: 8px;
|
|
92
|
+
text-align: center;
|
|
93
|
+
max-width: 100%;
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
text-overflow: ellipsis;
|
|
96
|
+
white-space: nowrap;
|
|
97
|
+
flex-shrink: 0;
|
|
98
|
+
}
|
|
99
|
+
.arrow {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
flex-shrink: 0;
|
|
104
|
+
padding: 0 4px;
|
|
105
|
+
opacity: 0;
|
|
106
|
+
animation: fadeInArrow 0.3s forwards;
|
|
107
|
+
/* delay set dynamically via JS */
|
|
108
|
+
}
|
|
109
|
+
@keyframes fadeInArrow { to { opacity: 1; } }
|
|
110
|
+
.arrow svg {
|
|
111
|
+
width: 20px; height: 20px;
|
|
112
|
+
stroke: rgba(255,255,255,0.35);
|
|
113
|
+
fill: none;
|
|
114
|
+
stroke-width: 2;
|
|
115
|
+
}
|
|
116
|
+
.flow.vertical .arrow { transform: rotate(90deg); }
|
|
117
|
+
.footer {
|
|
118
|
+
text-align: center;
|
|
119
|
+
padding: 12px;
|
|
120
|
+
font-size: 10px;
|
|
121
|
+
color: rgba(255,255,255,0.25);
|
|
122
|
+
flex-shrink: 0;
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
125
|
+
</head>
|
|
126
|
+
<body>
|
|
127
|
+
<div class="container">
|
|
128
|
+
<div class="header">
|
|
129
|
+
<h1 id="vizTitle">App Flow</h1>
|
|
130
|
+
<p id="vizSubtitle"></p>
|
|
131
|
+
</div>
|
|
132
|
+
<div class="flow" id="flowContainer"></div>
|
|
133
|
+
<div class="footer" id="vizFooter">Generated by DiscoveryLab</div>
|
|
134
|
+
</div>
|
|
135
|
+
<script>
|
|
136
|
+
const DATA = window.__VISUALIZATION_DATA__ || {};
|
|
137
|
+
const steps = DATA.steps || [];
|
|
138
|
+
const direction = DATA.direction || 'horizontal';
|
|
139
|
+
const count = steps.length;
|
|
140
|
+
|
|
141
|
+
if (DATA.title) document.getElementById('vizTitle').textContent = DATA.title;
|
|
142
|
+
if (DATA.subtitle) document.getElementById('vizSubtitle').textContent = DATA.subtitle;
|
|
143
|
+
|
|
144
|
+
const container = document.getElementById('flowContainer');
|
|
145
|
+
if (direction === 'vertical') container.classList.add('vertical');
|
|
146
|
+
|
|
147
|
+
// Auto-size steps based on count and viewport
|
|
148
|
+
const maxStepWidth = Math.min(220, Math.floor((window.innerWidth - 80 - (count - 1) * 28) / count));
|
|
149
|
+
|
|
150
|
+
// Sequential animation: step1 → arrow1 → step2 → arrow2 → step3 ...
|
|
151
|
+
const baseDelay = 0.2; // seconds
|
|
152
|
+
const stepDuration = 0.3; // time between each element appearing
|
|
153
|
+
|
|
154
|
+
steps.forEach((step, i) => {
|
|
155
|
+
const elementIndex = i * 2; // step0=0, arrow0=1, step1=2, arrow1=3, step2=4...
|
|
156
|
+
|
|
157
|
+
if (i > 0) {
|
|
158
|
+
const arrowIndex = (i * 2) - 1;
|
|
159
|
+
const arrow = document.createElement('div');
|
|
160
|
+
arrow.className = 'arrow';
|
|
161
|
+
arrow.style.animationDelay = (baseDelay + arrowIndex * stepDuration) + 's';
|
|
162
|
+
arrow.innerHTML = '<svg viewBox="0 0 24 24"><path d="M5 12h14M12 5l7 7-7 7" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
163
|
+
container.appendChild(arrow);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const el = document.createElement('div');
|
|
167
|
+
el.className = 'step';
|
|
168
|
+
el.style.maxWidth = maxStepWidth + 'px';
|
|
169
|
+
el.style.animationDelay = (baseDelay + elementIndex * stepDuration) + 's';
|
|
170
|
+
el.innerHTML = `
|
|
171
|
+
<div class="step-badge">${step.number || i + 1}</div>
|
|
172
|
+
<div class="step-screenshot">
|
|
173
|
+
<img src="${step.imageUrl}" alt="Step ${i + 1}">
|
|
174
|
+
</div>
|
|
175
|
+
<div class="step-label">${step.label || ''}</div>
|
|
176
|
+
`;
|
|
177
|
+
container.appendChild(el);
|
|
178
|
+
});
|
|
179
|
+
</script>
|
|
180
|
+
</body>
|
|
181
|
+
</html>
|