coursecode 0.1.41 → 0.1.43
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/framework/css/02-layout.css +4 -4
- package/framework/css/components/audio-player.css +1 -1
- package/framework/css/components/footer.css +2 -2
- package/framework/css/design-tokens.css +17 -10
- package/framework/css/layouts/base.css +8 -0
- package/framework/css/layouts/focused.css +3 -3
- package/framework/css/layouts/presentation.css +1 -1
- package/framework/css/responsive-structure.css +10 -2
- package/framework/index.html +2 -2
- package/framework/js/core/event-bus.js +1 -1
- package/framework/js/drivers/scorm-2004-driver.js +12 -14
- package/framework/js/utilities/view-manager.js +35 -4
- package/framework/js/vendor/pipwerks.js +4 -8
- package/framework/scripts/generate-narration.js +11 -3
- package/lib/stub-player/config-panel.js +1 -1
- package/package.json +1 -1
- package/template/.narration-cache.json +6 -0
- package/template/course/assets/audio/example-ui-showcase--compact-player.mp3 +0 -0
- package/template/course/assets/audio/example-ui-showcase--demo-modal.mp3 +0 -0
- package/template/course/assets/audio/example-ui-showcase--full-player.mp3 +0 -0
- package/template/course/assets/audio/example-welcome.mp3 +0 -0
- package/template/course/course-config.js +5 -0
- package/template/course/slides/example-ui-showcase.js +6 -6
- package/template/course/slides/example-welcome.js +10 -0
- package/template/course/theme.css +11 -0
- package/template/course/assets/audio/example-intro.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--compact-player.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--demo-modal.mp3 +0 -0
- package/template/course/assets/audio/example-ui-demo--full-player.mp3 +0 -0
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
/* App Layout - Fixed Frame Structure */
|
|
33
33
|
#app {
|
|
34
|
-
max-width:
|
|
34
|
+
max-width: var(--course-shell-max-width);
|
|
35
35
|
margin: 0 auto;
|
|
36
36
|
background: var(--bg-surface);
|
|
37
37
|
box-shadow: var(--shadow-md);
|
|
@@ -325,19 +325,19 @@ main#content>section {
|
|
|
325
325
|
while max-width constrains the upper bound. */
|
|
326
326
|
.content-narrow {
|
|
327
327
|
width: 100%;
|
|
328
|
-
max-width:
|
|
328
|
+
max-width: var(--content-width-narrow);
|
|
329
329
|
margin: 0 auto;
|
|
330
330
|
}
|
|
331
331
|
|
|
332
332
|
.content-medium {
|
|
333
333
|
width: 100%;
|
|
334
|
-
max-width:
|
|
334
|
+
max-width: var(--content-width-medium);
|
|
335
335
|
margin: 0 auto;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
.content-wide {
|
|
339
339
|
width: 100%;
|
|
340
|
-
max-width:
|
|
340
|
+
max-width: var(--content-width-wide);
|
|
341
341
|
margin: 0 auto;
|
|
342
342
|
}
|
|
343
343
|
|
|
@@ -185,7 +185,7 @@ footer[data-footer-layout="floating"] .nav-controls {
|
|
|
185
185
|
[data-layout="focused"] footer {
|
|
186
186
|
position: fixed;
|
|
187
187
|
bottom: var(--space-4);
|
|
188
|
-
right: var(--
|
|
188
|
+
right: var(--course-edge-inset);
|
|
189
189
|
left: auto;
|
|
190
190
|
width: auto;
|
|
191
191
|
background: var(--layout-floating-nav-bg);
|
|
@@ -247,7 +247,7 @@ footer[data-footer-layout="floating"] .nav-controls {
|
|
|
247
247
|
display: flex;
|
|
248
248
|
align-items: center;
|
|
249
249
|
justify-content: space-between;
|
|
250
|
-
padding: 0 calc(var(--
|
|
250
|
+
padding: 0 calc(var(--course-edge-inset) + env(safe-area-inset-left, 0px)) 0 calc(var(--course-edge-inset) + env(safe-area-inset-right, 0px));
|
|
251
251
|
pointer-events: none;
|
|
252
252
|
}
|
|
253
253
|
|
|
@@ -492,16 +492,23 @@
|
|
|
492
492
|
--btn-transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-interactive), transform var(--transition-interactive), opacity var(--transition-fast), filter var(--transition-fast);
|
|
493
493
|
--btn-hover-translate-y: var(--motion-lift-sm); /* Shared hover lift for button variants */
|
|
494
494
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
495
|
+
/* Layout spacing defaults - overridden by responsive breakpoint classes */
|
|
496
|
+
--course-shell-max-width: 1400px;
|
|
497
|
+
--course-shell-max-width-large: 1440px;
|
|
498
|
+
--course-edge-base: var(--space-4);
|
|
499
|
+
--content-width-narrow: 700px;
|
|
500
|
+
--content-width-medium: 900px;
|
|
501
|
+
--content-width-wide: 1200px;
|
|
502
|
+
--focused-content-max-width: 1000px;
|
|
503
|
+
--content-padding: var(--space-10);
|
|
504
|
+
--section-padding: var(--space-8);
|
|
505
|
+
--header-padding-x: var(--space-6);
|
|
506
|
+
--header-padding-y: var(--space-3);
|
|
507
|
+
--header-height: 72px;
|
|
508
|
+
--footer-padding-x: var(--space-6);
|
|
509
|
+
--footer-padding-y: var(--space-3);
|
|
510
|
+
--nav-padding-x: var(--space-6);
|
|
511
|
+
--nav-padding-y: var(--space-2);
|
|
505
512
|
|
|
506
513
|
/* Input System - Unified styling */
|
|
507
514
|
--input-padding-y: var(--space-3);
|
|
@@ -21,6 +21,14 @@
|
|
|
21
21
|
--layout-floating-nav-bg: var(--footer-floating-bg);
|
|
22
22
|
--layout-floating-nav-border: 1px solid var(--footer-floating-border);
|
|
23
23
|
--layout-floating-nav-shadow: var(--footer-floating-shadow);
|
|
24
|
+
|
|
25
|
+
/* Edge inset for floating UI (audio player, footer pill, FAB toggles,
|
|
26
|
+
edge nav arrows). On wide viewports, add the centered app gutter before
|
|
27
|
+
applying the normal in-frame edge padding. */
|
|
28
|
+
--course-edge-inset: max(
|
|
29
|
+
var(--course-edge-base),
|
|
30
|
+
calc(((100vw - var(--course-shell-max-width)) / 2) + var(--course-edge-base))
|
|
31
|
+
);
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
/* Default layout is traditional if not specified */
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
--header-border: var(--nav-edge-border);
|
|
61
61
|
position: fixed;
|
|
62
62
|
top: var(--space-4);
|
|
63
|
-
left: var(--
|
|
63
|
+
left: var(--course-edge-inset);
|
|
64
64
|
z-index: var(--z-fixed);
|
|
65
65
|
width: var(--nav-edge-control-size);
|
|
66
66
|
height: var(--nav-edge-control-size);
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
[data-layout="focused"] main#content>section {
|
|
106
|
-
max-width:
|
|
106
|
+
max-width: var(--focused-content-max-width);
|
|
107
107
|
width: 100%;
|
|
108
108
|
border: none;
|
|
109
109
|
box-shadow: none;
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
|
|
113
113
|
/* Slide container centered */
|
|
114
114
|
[data-layout="focused"] #slide-container {
|
|
115
|
-
max-width:
|
|
115
|
+
max-width: var(--focused-content-max-width);
|
|
116
116
|
margin: 0 auto;
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
--header-border: var(--nav-edge-border);
|
|
64
64
|
position: fixed;
|
|
65
65
|
top: calc(var(--space-4) + env(safe-area-inset-top, 0px));
|
|
66
|
-
left: calc(var(--
|
|
66
|
+
left: calc(var(--course-edge-inset) + env(safe-area-inset-left, 0px));
|
|
67
67
|
z-index: var(--z-fixed);
|
|
68
68
|
width: var(--nav-edge-control-size);
|
|
69
69
|
height: var(--nav-edge-control-size);
|
|
@@ -17,21 +17,29 @@
|
|
|
17
17
|
============================================================================ */
|
|
18
18
|
|
|
19
19
|
html.bp-min-large-desktop #app {
|
|
20
|
-
max-width:
|
|
20
|
+
max-width: var(--course-shell-max-width);
|
|
21
21
|
height: 100%;
|
|
22
22
|
margin: 0 auto;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
html.bp-min-large-desktop {
|
|
26
|
+
--course-shell-max-width: var(--course-shell-max-width-large);
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
/* ============================================================================
|
|
26
30
|
DESKTOP (<= 1439px)
|
|
27
31
|
============================================================================ */
|
|
28
32
|
|
|
29
33
|
html.bp-max-desktop #app {
|
|
30
34
|
margin: 0;
|
|
31
|
-
max-width:
|
|
35
|
+
max-width: var(--course-shell-max-width);
|
|
32
36
|
height: 100%;
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
html.bp-max-desktop {
|
|
40
|
+
--course-shell-max-width: 100vw;
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
/* ============================================================================
|
|
36
44
|
TABLET PORTRAIT (<= 1023px)
|
|
37
45
|
============================================================================ */
|
package/framework/index.html
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
8
|
<meta name="description" id="page-description" content="" />
|
|
9
9
|
<link rel="stylesheet" href="css/framework.css" />
|
|
10
|
-
<link rel="stylesheet" href="../course/theme.css" />
|
|
10
|
+
<link rel="stylesheet" href="../template/course/theme.css" />
|
|
11
11
|
<!-- Skip link is styled via framework.css for accessibility -->
|
|
12
12
|
</head>
|
|
13
13
|
|
|
@@ -172,4 +172,4 @@
|
|
|
172
172
|
<script type="module" src="./js/main.js"></script>
|
|
173
173
|
</body>
|
|
174
174
|
|
|
175
|
-
</html>
|
|
175
|
+
</html>
|
|
@@ -120,7 +120,7 @@ class EventBus {
|
|
|
120
120
|
// suppress to prevent infinite cascade
|
|
121
121
|
if (isErrorEvent) {
|
|
122
122
|
if (this._emittingError) {
|
|
123
|
-
|
|
123
|
+
logger.warn(`[EventBus] Suppressed recursive error event: ${event}`);
|
|
124
124
|
return false;
|
|
125
125
|
}
|
|
126
126
|
this._emittingError = true;
|
|
@@ -507,8 +507,7 @@ export class Scorm2004Driver extends ScormDriverBase {
|
|
|
507
507
|
const value = this._scorm.get(key);
|
|
508
508
|
const errorCode = this._scorm.debug.getCode();
|
|
509
509
|
|
|
510
|
-
|
|
511
|
-
if (errorCode === 403) {
|
|
510
|
+
if (this._isOptionalReadError(errorCode)) {
|
|
512
511
|
return null;
|
|
513
512
|
}
|
|
514
513
|
|
|
@@ -561,18 +560,12 @@ export class Scorm2004Driver extends ScormDriverBase {
|
|
|
561
560
|
* Populates the CMI cache at init time. Single LMS read pass.
|
|
562
561
|
*/
|
|
563
562
|
_populateCache() {
|
|
564
|
-
//
|
|
565
|
-
//
|
|
566
|
-
// SCORM
|
|
567
|
-
//
|
|
563
|
+
// Startup cache hydration reads LMS state opportunistically. Some LMS
|
|
564
|
+
// adapters report supported-but-empty or unavailable optional fields as
|
|
565
|
+
// SCORM errors, so use the optional read path here and keep strict reads
|
|
566
|
+
// for required operations.
|
|
568
567
|
const getOrDefault = (key, fallback) => {
|
|
569
|
-
|
|
570
|
-
return this._getValue(key) || fallback;
|
|
571
|
-
} catch (e) {
|
|
572
|
-
const code = this._scorm.debug.getCode();
|
|
573
|
-
if (code === 403) return fallback;
|
|
574
|
-
throw e;
|
|
575
|
-
}
|
|
568
|
+
return this._getValueOptional(key) || fallback;
|
|
576
569
|
};
|
|
577
570
|
|
|
578
571
|
// Read-only scalars (may be uninitialized on first launch)
|
|
@@ -712,6 +705,11 @@ export class Scorm2004Driver extends ScormDriverBase {
|
|
|
712
705
|
throw new Error(msg);
|
|
713
706
|
}
|
|
714
707
|
|
|
708
|
+
_isOptionalReadError(code) {
|
|
709
|
+
const numericCode = Number(code);
|
|
710
|
+
return numericCode === 401 || numericCode === 403;
|
|
711
|
+
}
|
|
712
|
+
|
|
715
713
|
// --- Recovery Mode Helpers ---
|
|
716
714
|
|
|
717
715
|
_getValueRecovered(key) {
|
|
@@ -739,7 +737,7 @@ export class Scorm2004Driver extends ScormDriverBase {
|
|
|
739
737
|
const value = api.GetValue(key);
|
|
740
738
|
const errCode = api.GetLastError ? parseInt(api.GetLastError(), 10) : 0;
|
|
741
739
|
|
|
742
|
-
if (errCode
|
|
740
|
+
if (this._isOptionalReadError(errCode)) {
|
|
743
741
|
return null;
|
|
744
742
|
}
|
|
745
743
|
|
|
@@ -111,12 +111,25 @@ export function createViewManager(container, scope = 'local') {
|
|
|
111
111
|
return element;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
const contentWidthValues = new Set(['narrow', 'medium', 'wide', 'full']);
|
|
115
|
+
|
|
116
|
+
// Check for per-slide override via data-content-width attribute. Slide
|
|
117
|
+
// modules commonly return a neutral container with the authored slide as
|
|
118
|
+
// its only child, so support the root and that first slide element.
|
|
119
|
+
const slideConfigWidth = getContentWidthOverride(element);
|
|
120
|
+
if (slideConfigWidth && !contentWidthValues.has(slideConfigWidth)) {
|
|
121
|
+
logger.warn(`[ViewManager] Ignoring invalid data-content-width="${slideConfigWidth}". Expected narrow, medium, wide, or full.`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const globalConfigWidth = courseConfig?.slideDefaults?.contentWidth;
|
|
125
|
+
if (!slideConfigWidth && globalConfigWidth && !contentWidthValues.has(globalConfigWidth)) {
|
|
126
|
+
logger.warn(`[ViewManager] Ignoring invalid slideDefaults.contentWidth="${globalConfigWidth}". Expected narrow, medium, wide, or full.`);
|
|
127
|
+
}
|
|
117
128
|
|
|
118
129
|
// Determine which width to use: per-slide override > global config > no wrapping
|
|
119
|
-
const configWidth = slideConfigWidth
|
|
130
|
+
const configWidth = contentWidthValues.has(slideConfigWidth)
|
|
131
|
+
? slideConfigWidth
|
|
132
|
+
: (contentWidthValues.has(globalConfigWidth) ? globalConfigWidth : null);
|
|
120
133
|
|
|
121
134
|
if (!configWidth) {
|
|
122
135
|
// No wrapping configured
|
|
@@ -136,6 +149,24 @@ export function createViewManager(container, scope = 'local') {
|
|
|
136
149
|
return wrapper;
|
|
137
150
|
}
|
|
138
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Gets a per-slide content width override from the rendered root or from
|
|
154
|
+
* the single authored slide element inside a neutral wrapper.
|
|
155
|
+
* @param {HTMLElement} element - The rendered element
|
|
156
|
+
* @returns {string|null} The requested width, if present
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
function getContentWidthOverride(element) {
|
|
160
|
+
const rootOverride = element.getAttribute('data-content-width');
|
|
161
|
+
if (rootOverride) return rootOverride;
|
|
162
|
+
|
|
163
|
+
if (element.children?.length === 1) {
|
|
164
|
+
return element.firstElementChild?.getAttribute('data-content-width');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
139
170
|
/**
|
|
140
171
|
* Checks if an element or its children already have a content-width class.
|
|
141
172
|
* @param {HTMLElement} element - The element to check
|
|
@@ -31,13 +31,9 @@ further modified by Philip Hutchison
|
|
|
31
31
|
if (typeof define === 'function' && define.amd) {
|
|
32
32
|
// AMD. Register as an anonymous module.
|
|
33
33
|
define([], factory);
|
|
34
|
-
} else if (typeof module === 'object' && module.exports) {
|
|
35
|
-
// Node. Does not work with strict CommonJS, but
|
|
36
|
-
// only CommonJS-like environments that support module.exports,
|
|
37
|
-
// like Node.
|
|
38
|
-
module.exports = factory();
|
|
39
34
|
} else {
|
|
40
|
-
// Browser
|
|
35
|
+
// Browser/global object. CourseCode imports this vendored copy as ESM,
|
|
36
|
+
// so avoid CommonJS export branches that modern bundlers warn about.
|
|
41
37
|
root.pipwerks = factory();
|
|
42
38
|
}
|
|
43
39
|
}(typeof globalThis !== 'undefined' ? globalThis : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : this, function () {
|
|
@@ -927,5 +923,5 @@ further modified by Philip Hutchison
|
|
|
927
923
|
// ESM Export for Vite/modern bundlers
|
|
928
924
|
// Added to enable ES module imports while keeping original UMD intact
|
|
929
925
|
// =============================================================================
|
|
930
|
-
export default
|
|
931
|
-
export const SCORM =
|
|
926
|
+
export default globalThis.pipwerks;
|
|
927
|
+
export const SCORM = globalThis.pipwerks?.SCORM;
|
|
@@ -43,15 +43,22 @@ import {
|
|
|
43
43
|
|
|
44
44
|
const __filename = fileURLToPath(import.meta.url);
|
|
45
45
|
const __dirname = path.dirname(__filename);
|
|
46
|
-
// __dirname = framework/scripts, go up two levels to reach
|
|
46
|
+
// __dirname = framework/scripts, go up two levels to reach the course project
|
|
47
|
+
// root. Real authored courses use ./course; this framework repo keeps its
|
|
48
|
+
// development fixture at ./template/course.
|
|
47
49
|
const SCORM_TEMPLATE_DIR = path.resolve(__dirname, '../..');
|
|
48
50
|
const ROOT_DIR = path.resolve(SCORM_TEMPLATE_DIR, '..');
|
|
49
|
-
const
|
|
51
|
+
const DEFAULT_COURSE_DIR = path.join(SCORM_TEMPLATE_DIR, 'course');
|
|
52
|
+
const FRAMEWORK_DEV_COURSE_DIR = path.join(SCORM_TEMPLATE_DIR, 'template', 'course');
|
|
53
|
+
const COURSE_DIR = fs.existsSync(DEFAULT_COURSE_DIR)
|
|
54
|
+
? DEFAULT_COURSE_DIR
|
|
55
|
+
: (fs.existsSync(FRAMEWORK_DEV_COURSE_DIR) ? FRAMEWORK_DEV_COURSE_DIR : DEFAULT_COURSE_DIR);
|
|
56
|
+
const COURSE_ROOT_DIR = path.dirname(COURSE_DIR);
|
|
50
57
|
const ASSETS_DIR = path.join(COURSE_DIR, 'assets');
|
|
51
58
|
const AUDIO_DIR = path.join(ASSETS_DIR, 'audio');
|
|
52
59
|
|
|
53
60
|
const SLIDES_DIR = path.join(COURSE_DIR, 'slides');
|
|
54
|
-
const CACHE_FILE = path.join(
|
|
61
|
+
const CACHE_FILE = path.join(COURSE_ROOT_DIR, '.narration-cache.json');
|
|
55
62
|
|
|
56
63
|
// Parse command line arguments
|
|
57
64
|
const args = process.argv.slice(2);
|
|
@@ -73,6 +80,7 @@ const REBUILD_CACHE = args.includes('--rebuild-cache');
|
|
|
73
80
|
function loadEnv() {
|
|
74
81
|
const searchPaths = [
|
|
75
82
|
path.join(process.cwd(), '.env'), // Current working directory (most common)
|
|
83
|
+
path.join(COURSE_ROOT_DIR, '.env'), // Course project or framework dev template
|
|
76
84
|
path.join(SCORM_TEMPLATE_DIR, '.env'), // Template directory
|
|
77
85
|
path.join(ROOT_DIR, '.env') // Root directory
|
|
78
86
|
];
|
|
@@ -161,7 +161,7 @@ export function createConfigPanelHandlers(context) {
|
|
|
161
161
|
<select data-path="slideDefaults.contentWidth" ${['focused', 'presentation', 'canvas'].includes(configData.layout) ? 'disabled' : ''}>
|
|
162
162
|
${widths.map(w => `<option value="${w}" ${configData.slideDefaults?.contentWidth === w ? 'selected' : ''}>${w}</option>`).join('')}
|
|
163
163
|
</select>
|
|
164
|
-
${['focused', 'presentation', 'canvas'].includes(configData.layout) ? `<span class="config-override-hint" title="${configData.layout === 'focused' ? 'Focused layout uses
|
|
164
|
+
${['focused', 'presentation', 'canvas'].includes(configData.layout) ? `<span class="config-override-hint" title="${configData.layout === 'focused' ? 'Focused layout uses --focused-content-max-width' : configData.layout === 'canvas' ? 'Canvas layout has no framework chrome' : 'Presentation layout uses full viewport'}">override</span>` : ''}
|
|
165
165
|
</div>
|
|
166
166
|
</div>
|
|
167
167
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@slides/example-welcome.js": "91d353d330166293491f0c34ef8c4f6a",
|
|
3
|
+
"@slides/example-ui-showcase.js#demo-modal": "4f7f4e4b846ec06f86a664ae809192aa",
|
|
4
|
+
"@slides/example-ui-showcase.js#full-player": "4349b331452acab4b97f46d9655cb006",
|
|
5
|
+
"@slides/example-ui-showcase.js#compact-player": "9ab41cdd6b1be5248fb446cee91cd0a2"
|
|
6
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -833,7 +833,7 @@ export const slide = {
|
|
|
833
833
|
data-title="Demo Modal"
|
|
834
834
|
data-body="#demo-modal-body"
|
|
835
835
|
data-footer="#demo-modal-footer"
|
|
836
|
-
data-audio-src="
|
|
836
|
+
data-audio-src="@slides/example-ui-showcase.js#demo-modal"
|
|
837
837
|
data-audio-required="false">
|
|
838
838
|
Launch Modal with Audio
|
|
839
839
|
</button>
|
|
@@ -1497,7 +1497,7 @@ export const slide = {
|
|
|
1497
1497
|
<h4 class="font-bold mb-2">Full Size Player</h4>
|
|
1498
1498
|
<p class="text-sm mb-3">Complete controls with progress bar, time display, and all playback options.</p>
|
|
1499
1499
|
<div class="mt-2" data-component="audio-player"
|
|
1500
|
-
data-audio-src="
|
|
1500
|
+
data-audio-src="@slides/example-ui-showcase.js#full-player"
|
|
1501
1501
|
data-audio-id="full-player-demo">
|
|
1502
1502
|
</div>
|
|
1503
1503
|
</div>
|
|
@@ -1507,7 +1507,7 @@ export const slide = {
|
|
|
1507
1507
|
<h4 class="font-bold mb-2">Compact Player</h4>
|
|
1508
1508
|
<p class="text-sm mb-3">Minimal controls (play/pause, restart, mute) - same style used in modals.</p>
|
|
1509
1509
|
<div class="mt-2" data-component="audio-player"
|
|
1510
|
-
data-audio-src="
|
|
1510
|
+
data-audio-src="@slides/example-ui-showcase.js#compact-player"
|
|
1511
1511
|
data-audio-id="compact-player-demo"
|
|
1512
1512
|
data-audio-compact="true">
|
|
1513
1513
|
</div>
|
|
@@ -1765,9 +1765,9 @@ export const slide = {
|
|
|
1765
1765
|
* - course/assets/audio/example-ui-showcase--compact-player.mp3
|
|
1766
1766
|
*
|
|
1767
1767
|
* Reference in slide HTML:
|
|
1768
|
-
* - Modal audio: data-audio-src="
|
|
1769
|
-
* - Full player: data-audio-src="
|
|
1770
|
-
* - Compact player: data-audio-src="
|
|
1768
|
+
* - Modal audio: data-audio-src="@slides/example-ui-showcase.js#demo-modal"
|
|
1769
|
+
* - Full player: data-audio-src="@slides/example-ui-showcase.js#full-player"
|
|
1770
|
+
* - Compact player: data-audio-src="@slides/example-ui-showcase.js#compact-player"
|
|
1771
1771
|
*/
|
|
1772
1772
|
export const narration = {
|
|
1773
1773
|
'demo-modal': `
|
|
@@ -121,3 +121,13 @@ export const slide = {
|
|
|
121
121
|
return container;
|
|
122
122
|
}
|
|
123
123
|
};
|
|
124
|
+
|
|
125
|
+
export const narration = `
|
|
126
|
+
Welcome to CourseCode.
|
|
127
|
+
|
|
128
|
+
This opening slide introduces the template course and the main workflow it demonstrates.
|
|
129
|
+
|
|
130
|
+
CourseCode helps training teams, instructional designers, and subject matter experts build interactive learning experiences with AI assistance.
|
|
131
|
+
|
|
132
|
+
Use this course to explore the authoring workflow, preview tools, reusable components, theming options, and LMS-ready publishing process.
|
|
133
|
+
`;
|
|
@@ -109,6 +109,17 @@
|
|
|
109
109
|
Adjust height, padding, and width of structural UI areas.
|
|
110
110
|
*/
|
|
111
111
|
|
|
112
|
+
/* Course shell sizing */
|
|
113
|
+
/* --course-shell-max-width: 1400px; */ /* Outer app frame max width */
|
|
114
|
+
/* --course-shell-max-width-large: 1440px; */ /* Outer app frame max width on large desktop */
|
|
115
|
+
/* --course-edge-base: 1rem; */ /* Floating UI inset within the app frame */
|
|
116
|
+
|
|
117
|
+
/* Slide content widths */
|
|
118
|
+
/* --content-width-narrow: 700px; */ /* .content-narrow max width */
|
|
119
|
+
/* --content-width-medium: 900px; */ /* .content-medium max width */
|
|
120
|
+
/* --content-width-wide: 1200px; */ /* .content-wide max width */
|
|
121
|
+
/* --focused-content-max-width: 1000px; */ /* Focused layout viewport-fit content cap */
|
|
122
|
+
|
|
112
123
|
/* Header sizing */
|
|
113
124
|
/* --header-height: 72px; */ /* Header bar height */
|
|
114
125
|
/* --header-padding-x: 1.5rem; */ /* Header horizontal padding */
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|