coursecode 0.1.28 → 0.1.29
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.
|
@@ -41,6 +41,7 @@ export function createOutlineModeHandlers(context) {
|
|
|
41
41
|
let isVisible = false;
|
|
42
42
|
let courseLoaded = false;
|
|
43
43
|
let viewingStage = null; // Which stage the dashboard is showing
|
|
44
|
+
const calloutDismissed = localStorage.getItem('coursecode-walkthroughCalloutDismissed') === 'true';
|
|
44
45
|
|
|
45
46
|
async function checkStage() {
|
|
46
47
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -133,6 +134,9 @@ export function createOutlineModeHandlers(context) {
|
|
|
133
134
|
// Stage stepper
|
|
134
135
|
parts.push(renderStepper(detectedStage, viewingStage));
|
|
135
136
|
|
|
137
|
+
// Walkthrough callout (dismissable, shown below stepper)
|
|
138
|
+
parts.push(renderWalkthroughCallout());
|
|
139
|
+
|
|
136
140
|
// Stage header — contextual button text
|
|
137
141
|
const hasSlides = stageData.checklist?.hasSlides;
|
|
138
142
|
let skipLabel;
|
|
@@ -511,6 +515,39 @@ export function createOutlineModeHandlers(context) {
|
|
|
511
515
|
`;
|
|
512
516
|
}
|
|
513
517
|
|
|
518
|
+
// ── Walkthrough Callout ───────────────────────────────────
|
|
519
|
+
|
|
520
|
+
function renderWalkthroughCallout() {
|
|
521
|
+
if (calloutDismissed) return '';
|
|
522
|
+
|
|
523
|
+
const hasSlides = stageData?.checklist?.hasSlides;
|
|
524
|
+
let skipLabel;
|
|
525
|
+
if (courseLoaded) {
|
|
526
|
+
skipLabel = '← Back to Course';
|
|
527
|
+
} else if (hasSlides) {
|
|
528
|
+
skipLabel = 'View Course ▸';
|
|
529
|
+
} else {
|
|
530
|
+
skipLabel = 'Skip to Course ▸';
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return `
|
|
534
|
+
<div class="outline-walkthrough-callout" id="outline-walkthrough-callout">
|
|
535
|
+
<div class="outline-callout-content">
|
|
536
|
+
<div class="outline-callout-icon">💡</div>
|
|
537
|
+
<div class="outline-callout-text">
|
|
538
|
+
<strong>This is an optional walkthrough.</strong>
|
|
539
|
+
It guides you through building a course step-by-step, but you can skip it at any time.
|
|
540
|
+
Close with the <span class="outline-callout-kbd">✕</span> in the top-right corner, or return anytime from the course preview toolbar.
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
<div class="outline-callout-actions">
|
|
544
|
+
<button id="outline-callout-skip-btn" class="outline-callout-skip-btn">${skipLabel}</button>
|
|
545
|
+
<button id="outline-callout-dismiss-btn" class="outline-callout-dismiss-btn">Got it</button>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
`;
|
|
549
|
+
}
|
|
550
|
+
|
|
514
551
|
// ── Shared Components ────────────────────────────────────
|
|
515
552
|
|
|
516
553
|
function renderChecklist() {
|
|
@@ -587,6 +624,17 @@ export function createOutlineModeHandlers(context) {
|
|
|
587
624
|
// Skip / Back button
|
|
588
625
|
document.getElementById('stub-player-skip-outline-btn')?.addEventListener('click', dismissDashboard);
|
|
589
626
|
|
|
627
|
+
// Walkthrough callout handlers
|
|
628
|
+
document.getElementById('outline-callout-skip-btn')?.addEventListener('click', dismissDashboard);
|
|
629
|
+
document.getElementById('outline-callout-dismiss-btn')?.addEventListener('click', () => {
|
|
630
|
+
localStorage.setItem('coursecode-walkthroughCalloutDismissed', 'true');
|
|
631
|
+
const callout = document.getElementById('outline-walkthrough-callout');
|
|
632
|
+
if (callout) {
|
|
633
|
+
callout.classList.add('dismissing');
|
|
634
|
+
callout.addEventListener('animationend', () => callout.remove(), { once: true });
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
590
638
|
// Stepper clicks
|
|
591
639
|
outlineContent.querySelectorAll('.stepper-step').forEach(btn => {
|
|
592
640
|
btn.addEventListener('click', () => {
|
|
@@ -147,6 +147,116 @@
|
|
|
147
147
|
margin-top: 20px;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/* ── Walkthrough Callout ────────────────── */
|
|
151
|
+
|
|
152
|
+
.outline-walkthrough-callout {
|
|
153
|
+
margin-bottom: 24px;
|
|
154
|
+
padding: 16px 20px;
|
|
155
|
+
background: rgba(74, 111, 165, 0.1);
|
|
156
|
+
border: 1px solid rgba(74, 111, 165, 0.25);
|
|
157
|
+
border-left: 3px solid var(--color-info);
|
|
158
|
+
border-radius: 8px;
|
|
159
|
+
animation: callout-slide-in 0.3s ease-out;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@keyframes callout-slide-in {
|
|
163
|
+
from { opacity: 0; transform: translateY(-8px); }
|
|
164
|
+
to { opacity: 1; transform: translateY(0); }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.outline-walkthrough-callout.dismissing {
|
|
168
|
+
animation: callout-slide-out 0.25s ease-in forwards;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@keyframes callout-slide-out {
|
|
172
|
+
from { opacity: 1; transform: translateY(0); max-height: 200px; margin-bottom: 24px; }
|
|
173
|
+
to { opacity: 0; transform: translateY(-8px); max-height: 0; margin-bottom: 0; padding: 0 20px; overflow: hidden; }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.outline-callout-content {
|
|
177
|
+
display: flex;
|
|
178
|
+
gap: 12px;
|
|
179
|
+
align-items: flex-start;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.outline-callout-icon {
|
|
183
|
+
font-size: 20px;
|
|
184
|
+
line-height: 1;
|
|
185
|
+
flex-shrink: 0;
|
|
186
|
+
margin-top: 1px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.outline-callout-text {
|
|
190
|
+
font-size: 13px;
|
|
191
|
+
line-height: 1.6;
|
|
192
|
+
color: var(--color-gray-400);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.outline-callout-text strong {
|
|
196
|
+
color: var(--color-white);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.outline-callout-kbd {
|
|
200
|
+
display: inline-flex;
|
|
201
|
+
align-items: center;
|
|
202
|
+
justify-content: center;
|
|
203
|
+
width: 18px;
|
|
204
|
+
height: 18px;
|
|
205
|
+
background: rgba(0, 0, 0, 0.3);
|
|
206
|
+
border: 1px solid var(--color-primary-panel);
|
|
207
|
+
border-radius: 4px;
|
|
208
|
+
font-size: 10px;
|
|
209
|
+
color: var(--color-gray-400);
|
|
210
|
+
vertical-align: middle;
|
|
211
|
+
line-height: 1;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.outline-callout-actions {
|
|
215
|
+
display: flex;
|
|
216
|
+
gap: 8px;
|
|
217
|
+
margin-top: 14px;
|
|
218
|
+
padding-left: 32px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.outline-callout-skip-btn {
|
|
222
|
+
background: var(--color-info);
|
|
223
|
+
color: var(--color-white);
|
|
224
|
+
border: none;
|
|
225
|
+
padding: 7px 16px;
|
|
226
|
+
border-radius: 6px;
|
|
227
|
+
font-size: 12px;
|
|
228
|
+
font-weight: 600;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
transition: background 0.15s, transform 0.1s;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.outline-callout-skip-btn:hover {
|
|
234
|
+
background: color-mix(in srgb, var(--color-info) 80%, var(--color-white));
|
|
235
|
+
transform: translateY(-1px);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.outline-callout-skip-btn:active {
|
|
239
|
+
transform: translateY(0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.outline-callout-dismiss-btn {
|
|
243
|
+
background: none;
|
|
244
|
+
color: var(--color-gray-600);
|
|
245
|
+
border: 1px solid var(--color-primary-panel);
|
|
246
|
+
padding: 7px 14px;
|
|
247
|
+
border-radius: 6px;
|
|
248
|
+
font-size: 12px;
|
|
249
|
+
font-weight: 500;
|
|
250
|
+
cursor: pointer;
|
|
251
|
+
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.outline-callout-dismiss-btn:hover {
|
|
255
|
+
background: var(--color-primary-panel);
|
|
256
|
+
color: var(--color-gray-200);
|
|
257
|
+
border-color: var(--color-info);
|
|
258
|
+
}
|
|
259
|
+
|
|
150
260
|
/* ── Stage Header ───────────────────────── */
|
|
151
261
|
|
|
152
262
|
.outline-stage-header {
|