@pie-players/pie-assessment-toolkit 0.2.0

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.
Files changed (194) hide show
  1. package/README.md +520 -0
  2. package/dist/attempt/TestSession.d.ts +90 -0
  3. package/dist/attempt/TestSession.d.ts.map +1 -0
  4. package/dist/attempt/TestSession.js +174 -0
  5. package/dist/attempt/TestSession.js.map +1 -0
  6. package/dist/core/TypedEventBus.d.ts +48 -0
  7. package/dist/core/TypedEventBus.d.ts.map +1 -0
  8. package/dist/core/TypedEventBus.js +63 -0
  9. package/dist/core/TypedEventBus.js.map +1 -0
  10. package/dist/index.d.ts +37 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +44 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/item-loader.d.ts +45 -0
  15. package/dist/item-loader.d.ts.map +1 -0
  16. package/dist/item-loader.js +62 -0
  17. package/dist/item-loader.js.map +1 -0
  18. package/dist/player/AssessmentPlayer.d.ts +388 -0
  19. package/dist/player/AssessmentPlayer.d.ts.map +1 -0
  20. package/dist/player/AssessmentPlayer.js +965 -0
  21. package/dist/player/AssessmentPlayer.js.map +1 -0
  22. package/dist/player/index.d.ts +17 -0
  23. package/dist/player/index.d.ts.map +1 -0
  24. package/dist/player/index.js +15 -0
  25. package/dist/player/index.js.map +1 -0
  26. package/dist/player/navigation-types.d.ts +63 -0
  27. package/dist/player/navigation-types.d.ts.map +1 -0
  28. package/dist/player/navigation-types.js +7 -0
  29. package/dist/player/navigation-types.js.map +1 -0
  30. package/dist/player/qti-navigation.d.ts +29 -0
  31. package/dist/player/qti-navigation.d.ts.map +1 -0
  32. package/dist/player/qti-navigation.js +160 -0
  33. package/dist/player/qti-navigation.js.map +1 -0
  34. package/dist/reference-layout/index.d.ts +19 -0
  35. package/dist/reference-layout/index.d.ts.map +1 -0
  36. package/dist/reference-layout/index.js +20 -0
  37. package/dist/reference-layout/index.js.map +1 -0
  38. package/dist/services/AccessibilityCatalogResolver.d.ts +141 -0
  39. package/dist/services/AccessibilityCatalogResolver.d.ts.map +1 -0
  40. package/dist/services/AccessibilityCatalogResolver.js +249 -0
  41. package/dist/services/AccessibilityCatalogResolver.js.map +1 -0
  42. package/dist/services/AssessmentAuthoringService.d.ts +60 -0
  43. package/dist/services/AssessmentAuthoringService.d.ts.map +1 -0
  44. package/dist/services/AssessmentAuthoringService.js +183 -0
  45. package/dist/services/AssessmentAuthoringService.js.map +1 -0
  46. package/dist/services/ContextVariableStore.d.ts +114 -0
  47. package/dist/services/ContextVariableStore.d.ts.map +1 -0
  48. package/dist/services/ContextVariableStore.js +207 -0
  49. package/dist/services/ContextVariableStore.js.map +1 -0
  50. package/dist/services/ElementToolStateStore.d.ts +125 -0
  51. package/dist/services/ElementToolStateStore.d.ts.map +1 -0
  52. package/dist/services/ElementToolStateStore.js +200 -0
  53. package/dist/services/ElementToolStateStore.js.map +1 -0
  54. package/dist/services/HighlightCoordinator.d.ts +179 -0
  55. package/dist/services/HighlightCoordinator.d.ts.map +1 -0
  56. package/dist/services/HighlightCoordinator.js +446 -0
  57. package/dist/services/HighlightCoordinator.js.map +1 -0
  58. package/dist/services/I18nService.d.ts +121 -0
  59. package/dist/services/I18nService.d.ts.map +1 -0
  60. package/dist/services/I18nService.js +276 -0
  61. package/dist/services/I18nService.js.map +1 -0
  62. package/dist/services/PNPMapper.d.ts +71 -0
  63. package/dist/services/PNPMapper.d.ts.map +1 -0
  64. package/dist/services/PNPMapper.js +98 -0
  65. package/dist/services/PNPMapper.js.map +1 -0
  66. package/dist/services/PNPToolResolver.d.ts +127 -0
  67. package/dist/services/PNPToolResolver.d.ts.map +1 -0
  68. package/dist/services/PNPToolResolver.js +222 -0
  69. package/dist/services/PNPToolResolver.js.map +1 -0
  70. package/dist/services/SSMLExtractor.d.ts +61 -0
  71. package/dist/services/SSMLExtractor.d.ts.map +1 -0
  72. package/dist/services/SSMLExtractor.js +181 -0
  73. package/dist/services/SSMLExtractor.js.map +1 -0
  74. package/dist/services/TTSService.d.ts +162 -0
  75. package/dist/services/TTSService.d.ts.map +1 -0
  76. package/dist/services/TTSService.js +465 -0
  77. package/dist/services/TTSService.js.map +1 -0
  78. package/dist/services/ThemeProvider.d.ts +95 -0
  79. package/dist/services/ThemeProvider.d.ts.map +1 -0
  80. package/dist/services/ThemeProvider.js +299 -0
  81. package/dist/services/ThemeProvider.js.map +1 -0
  82. package/dist/services/ToolConfigResolver.d.ts +162 -0
  83. package/dist/services/ToolConfigResolver.d.ts.map +1 -0
  84. package/dist/services/ToolConfigResolver.js +230 -0
  85. package/dist/services/ToolConfigResolver.js.map +1 -0
  86. package/dist/services/ToolCoordinator.d.ts +137 -0
  87. package/dist/services/ToolCoordinator.d.ts.map +1 -0
  88. package/dist/services/ToolCoordinator.js +318 -0
  89. package/dist/services/ToolCoordinator.js.map +1 -0
  90. package/dist/services/ToolkitCoordinator.d.ts +188 -0
  91. package/dist/services/ToolkitCoordinator.d.ts.map +1 -0
  92. package/dist/services/ToolkitCoordinator.js +252 -0
  93. package/dist/services/ToolkitCoordinator.js.map +1 -0
  94. package/dist/services/interfaces.d.ts +391 -0
  95. package/dist/services/interfaces.d.ts.map +1 -0
  96. package/dist/services/interfaces.js +12 -0
  97. package/dist/services/interfaces.js.map +1 -0
  98. package/dist/services/tool-providers/DesmosToolProvider.d.ts +103 -0
  99. package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +1 -0
  100. package/dist/services/tool-providers/DesmosToolProvider.js +127 -0
  101. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -0
  102. package/dist/services/tool-providers/IToolProvider.d.ts +137 -0
  103. package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -0
  104. package/dist/services/tool-providers/IToolProvider.js +13 -0
  105. package/dist/services/tool-providers/IToolProvider.js.map +1 -0
  106. package/dist/services/tool-providers/TIToolProvider.d.ts +107 -0
  107. package/dist/services/tool-providers/TIToolProvider.d.ts.map +1 -0
  108. package/dist/services/tool-providers/TIToolProvider.js +123 -0
  109. package/dist/services/tool-providers/TIToolProvider.js.map +1 -0
  110. package/dist/services/tool-providers/TTSToolProvider.d.ts +143 -0
  111. package/dist/services/tool-providers/TTSToolProvider.d.ts.map +1 -0
  112. package/dist/services/tool-providers/TTSToolProvider.js +168 -0
  113. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -0
  114. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +165 -0
  115. package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +1 -0
  116. package/dist/services/tool-providers/ToolProviderRegistry.js +240 -0
  117. package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -0
  118. package/dist/services/tool-providers/index.d.ts +18 -0
  119. package/dist/services/tool-providers/index.d.ts.map +1 -0
  120. package/dist/services/tool-providers/index.js +15 -0
  121. package/dist/services/tool-providers/index.js.map +1 -0
  122. package/dist/services/tts/browser-provider.d.ts +24 -0
  123. package/dist/services/tts/browser-provider.d.ts.map +1 -0
  124. package/dist/services/tts/browser-provider.js +177 -0
  125. package/dist/services/tts/browser-provider.js.map +1 -0
  126. package/dist/services/tts/provider-interface.d.ts +131 -0
  127. package/dist/services/tts/provider-interface.d.ts.map +1 -0
  128. package/dist/services/tts/provider-interface.js +10 -0
  129. package/dist/services/tts/provider-interface.js.map +1 -0
  130. package/dist/tools/calculators/desmos-provider.d.ts +54 -0
  131. package/dist/tools/calculators/desmos-provider.d.ts.map +1 -0
  132. package/dist/tools/calculators/desmos-provider.js +384 -0
  133. package/dist/tools/calculators/desmos-provider.js.map +1 -0
  134. package/dist/tools/calculators/mathjs-provider.d.ts +50 -0
  135. package/dist/tools/calculators/mathjs-provider.d.ts.map +1 -0
  136. package/dist/tools/calculators/mathjs-provider.js +660 -0
  137. package/dist/tools/calculators/mathjs-provider.js.map +1 -0
  138. package/dist/tools/calculators/ti-provider.d.ts +122 -0
  139. package/dist/tools/calculators/ti-provider.d.ts.map +1 -0
  140. package/dist/tools/calculators/ti-provider.js +587 -0
  141. package/dist/tools/calculators/ti-provider.js.map +1 -0
  142. package/dist/tools/client.d.ts +17 -0
  143. package/dist/tools/client.d.ts.map +1 -0
  144. package/dist/tools/client.js +26 -0
  145. package/dist/tools/client.js.map +1 -0
  146. package/dist/tools/index.d.ts +8 -0
  147. package/dist/tools/index.d.ts.map +1 -0
  148. package/dist/tools/index.js +10 -0
  149. package/dist/tools/index.js.map +1 -0
  150. package/dist/tools/library-loader.d.ts +63 -0
  151. package/dist/tools/library-loader.d.ts.map +1 -0
  152. package/dist/tools/library-loader.js +292 -0
  153. package/dist/tools/library-loader.js.map +1 -0
  154. package/dist/tools/response-discovery.d.ts +72 -0
  155. package/dist/tools/response-discovery.d.ts.map +1 -0
  156. package/dist/tools/response-discovery.js +183 -0
  157. package/dist/tools/response-discovery.js.map +1 -0
  158. package/dist/tools/tool-coordinator.d.ts +76 -0
  159. package/dist/tools/tool-coordinator.d.ts.map +1 -0
  160. package/dist/tools/tool-coordinator.js +197 -0
  161. package/dist/tools/tool-coordinator.js.map +1 -0
  162. package/dist/tools/types.d.ts +427 -0
  163. package/dist/tools/types.d.ts.map +1 -0
  164. package/dist/tools/types.js +13 -0
  165. package/dist/tools/types.js.map +1 -0
  166. package/dist/tools/variant-resolver.d.ts +48 -0
  167. package/dist/tools/variant-resolver.d.ts.map +1 -0
  168. package/dist/tools/variant-resolver.js +214 -0
  169. package/dist/tools/variant-resolver.js.map +1 -0
  170. package/dist/types/events.d.ts +157 -0
  171. package/dist/types/events.d.ts.map +1 -0
  172. package/dist/types/events.js +11 -0
  173. package/dist/types/events.js.map +1 -0
  174. package/dist/utils/logger.d.ts +7 -0
  175. package/dist/utils/logger.d.ts.map +1 -0
  176. package/dist/utils/logger.js +11 -0
  177. package/dist/utils/logger.js.map +1 -0
  178. package/package.json +71 -0
  179. package/src/README.md +626 -0
  180. package/src/components/QuestionToolBar.svelte +406 -0
  181. package/src/player/AssessmentLayout.svelte +68 -0
  182. package/src/player/README.md +154 -0
  183. package/src/reference-layout/README.md +135 -0
  184. package/src/reference-layout/ReferenceLayout.svelte +209 -0
  185. package/src/reference-layout/components/AssessmentContent.svelte +259 -0
  186. package/src/reference-layout/components/AssessmentFooter.svelte +89 -0
  187. package/src/reference-layout/components/AssessmentHeader.svelte +250 -0
  188. package/src/reference-layout/components/AssessmentNavigation.svelte +134 -0
  189. package/src/reference-layout/components/AssessmentToolsBar.svelte +176 -0
  190. package/src/reference-layout/components/ItemPanel.svelte +200 -0
  191. package/src/reference-layout/components/NotesPanel.svelte +179 -0
  192. package/src/reference-layout/components/PassagePanel.svelte +76 -0
  193. package/src/tools/README.md +616 -0
  194. package/src/tools/calculators/README.md +395 -0
@@ -0,0 +1,200 @@
1
+ <script lang="ts">
2
+ import type { ItemConfig, ItemEntity } from '@pie-players/pie-players-shared';
3
+ import type { ToolCoordinator } from '../../services/ToolCoordinator';
4
+ import type { ITTSService, IHighlightCoordinator, IElementToolStateStore } from '../../services/interfaces';
5
+ import '$lib/tags/pie-iife-player/PieIifePlayer.svelte';
6
+ import PiePlayerStyles from '$lib/components/PiePlayerStyles.svelte';
7
+ import '../../components/QuestionToolBar.svelte';
8
+
9
+ // NOTE: Parent applications using ItemPanel with showHeader=true must import tool web components:
10
+ // import '@pie-players/pie-tool-answer-eliminator';
11
+ // import '@pie-players/pie-tool-tts-inline';
12
+ // import '@pie-players/pie-tool-calculator-inline';
13
+ // import '@pie-players/pie-tool-calculator';
14
+
15
+ let {
16
+ currentItem,
17
+ config,
18
+ session,
19
+ bundleHost,
20
+ env,
21
+ assessmentId = '',
22
+ sectionId = '',
23
+ toolCoordinator,
24
+ ttsService,
25
+ highlightCoordinator,
26
+ catalogResolver,
27
+ elementToolStateStore,
28
+ showHeader = false,
29
+ isLoading = false
30
+ }: {
31
+ currentItem: ItemEntity | null;
32
+ config: ItemConfig | null;
33
+ session: { id: string; data: any[] };
34
+ bundleHost?: string;
35
+ env: { mode: string; role: string };
36
+ assessmentId?: string;
37
+ sectionId?: string;
38
+ toolCoordinator?: ToolCoordinator;
39
+ ttsService?: ITTSService;
40
+ highlightCoordinator?: IHighlightCoordinator;
41
+ catalogResolver?: any;
42
+ elementToolStateStore?: IElementToolStateStore;
43
+ showHeader?: boolean;
44
+ isLoading?: boolean;
45
+ } = $props();
46
+
47
+ let piePlayerElement = $state<HTMLElement | null>(null);
48
+ let itemContentElement = $state<HTMLElement | null>(null);
49
+ let questionToolbarElement = $state<HTMLElement | null>(null);
50
+ let toolbarServicesBound = $state(false);
51
+ let calculatorElement = $state<HTMLElement | null>(null);
52
+ let calculatorVisible = $state(false);
53
+
54
+ // Bind services, scope, and IDs to question toolbar (must be JS properties)
55
+ $effect(() => {
56
+ if (questionToolbarElement && !toolbarServicesBound && showHeader) {
57
+ if (toolCoordinator) {
58
+ (questionToolbarElement as any).toolCoordinator = toolCoordinator;
59
+ }
60
+ if (ttsService) {
61
+ (questionToolbarElement as any).ttsService = ttsService;
62
+ }
63
+ if (highlightCoordinator) {
64
+ (questionToolbarElement as any).highlightCoordinator = highlightCoordinator;
65
+ }
66
+ if (itemContentElement) {
67
+ (questionToolbarElement as any).scopeElement = itemContentElement;
68
+ }
69
+ if (elementToolStateStore) {
70
+ (questionToolbarElement as any).elementToolStateStore = elementToolStateStore;
71
+ }
72
+ if (assessmentId) {
73
+ (questionToolbarElement as any).assessmentId = assessmentId;
74
+ }
75
+ if (sectionId) {
76
+ (questionToolbarElement as any).sectionId = sectionId;
77
+ }
78
+
79
+ toolbarServicesBound = true;
80
+ }
81
+ });
82
+
83
+ // Bind coordinator to calculator tool
84
+ $effect(() => {
85
+ if (calculatorElement && toolCoordinator) {
86
+ (calculatorElement as any).coordinator = toolCoordinator;
87
+ }
88
+ });
89
+
90
+ // Subscribe to calculator visibility changes
91
+ $effect(() => {
92
+ if (!showHeader || !toolCoordinator || !currentItem) return;
93
+
94
+ const unsubscribe = toolCoordinator.subscribe(() => {
95
+ calculatorVisible = toolCoordinator.isToolVisible(`calculator-${currentItem.id}`);
96
+ });
97
+
98
+ // Initial update
99
+ calculatorVisible = toolCoordinator.isToolVisible(`calculator-${currentItem.id}`);
100
+
101
+ return unsubscribe;
102
+ });
103
+ </script>
104
+
105
+ <div
106
+ class="item-panel"
107
+ data-assessment-id={assessmentId}
108
+ data-section-id={sectionId}
109
+ data-item-id={currentItem?.id}
110
+ >
111
+ {#if isLoading}
112
+ <div class="loading-container">
113
+ <span class="loading loading-spinner loading-lg"></span>
114
+ </div>
115
+ {:else if config}
116
+ <!-- Optional Question Header with Toolbar -->
117
+ {#if showHeader && currentItem}
118
+ <div class="item-header">
119
+ <h4 class="item-title">{currentItem.name || 'Question'}</h4>
120
+ <pie-question-toolbar
121
+ bind:this={questionToolbarElement}
122
+ item-id={currentItem.id}
123
+ catalog-id={currentItem.id}
124
+ tools="tts,answerEliminator,calculator"
125
+ size="md"
126
+ language="en-US"
127
+ ></pie-question-toolbar>
128
+ </div>
129
+ {/if}
130
+
131
+ <div class="item-content" bind:this={itemContentElement}>
132
+ <PiePlayerStyles>
133
+ <pie-iife-player
134
+ bind:this={piePlayerElement}
135
+ config={config}
136
+ env={env}
137
+ session={session}
138
+ hosted={false}
139
+ show-bottom-border={false}
140
+ bundle-host={bundleHost}
141
+ ></pie-iife-player>
142
+ </PiePlayerStyles>
143
+ </div>
144
+ {:else}
145
+ <div class="empty-container">
146
+ <p class="empty-message">Question could not be loaded.</p>
147
+ </div>
148
+ {/if}
149
+
150
+ <!-- Calculator Tool Instance (rendered outside panel for floating overlay) -->
151
+ {#if showHeader && currentItem}
152
+ <pie-tool-calculator
153
+ bind:this={calculatorElement}
154
+ visible={calculatorVisible}
155
+ tool-id="calculator-{currentItem.id}"
156
+ ></pie-tool-calculator>
157
+ {/if}
158
+ </div>
159
+
160
+ <style>
161
+ .item-panel {
162
+ height: 100%;
163
+ padding: 1rem;
164
+ overflow-y: auto;
165
+ overflow-x: hidden;
166
+ }
167
+
168
+ .item-header {
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: space-between;
172
+ padding: 0.75rem 0;
173
+ margin-bottom: 0.5rem;
174
+ }
175
+
176
+ .item-title {
177
+ margin: 0;
178
+ font-size: 0.95rem;
179
+ font-weight: 600;
180
+ color: var(--pie-primary, #1976d2);
181
+ }
182
+
183
+ .item-content {
184
+ position: relative;
185
+ }
186
+
187
+ .loading-container,
188
+ .empty-container {
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: center;
192
+ height: 100%;
193
+ }
194
+
195
+ .empty-message {
196
+ color: var(--pie-text-secondary, #666);
197
+ font-style: italic;
198
+ }
199
+ </style>
200
+
@@ -0,0 +1,179 @@
1
+ <script lang="ts">
2
+ import { onMount } from "svelte";
3
+
4
+ let {
5
+ itemId,
6
+ itemLabel,
7
+ onClose,
8
+ }: {
9
+ itemId: string;
10
+ itemLabel?: string;
11
+ onClose?: () => void;
12
+ } = $props();
13
+
14
+ let text = $state("");
15
+ let status = $state<"idle" | "saved">("idle");
16
+
17
+ function storageKey(id: string) {
18
+ return `schoolcity-notes:${id || "unknown"}`;
19
+ }
20
+
21
+ function load() {
22
+ if (!itemId) {
23
+ text = "";
24
+ return;
25
+ }
26
+ try {
27
+ const v = localStorage.getItem(storageKey(itemId));
28
+ text = v ?? "";
29
+ } catch {
30
+ // ignore
31
+ }
32
+ }
33
+
34
+ function save() {
35
+ if (!itemId) return;
36
+ try {
37
+ localStorage.setItem(storageKey(itemId), text);
38
+ status = "saved";
39
+ window.setTimeout(() => {
40
+ status = "idle";
41
+ }, 800);
42
+ } catch {
43
+ // ignore
44
+ }
45
+ }
46
+
47
+ $effect(() => {
48
+ // reload when item changes
49
+ load();
50
+ });
51
+
52
+ onMount(() => {
53
+ load();
54
+ });
55
+ </script>
56
+
57
+ <div class="notes-panel">
58
+ <div class="notes-header">
59
+ <div class="notes-title">
60
+ <span class="title">Notes</span>
61
+ {#if itemLabel}
62
+ <span class="subtitle">{itemLabel}</span>
63
+ {/if}
64
+ </div>
65
+ <button class="icon-button" onclick={() => onClose?.()} aria-label="Close notes">
66
+ ×
67
+ </button>
68
+ </div>
69
+
70
+ <div class="notes-body">
71
+ <textarea
72
+ class="notes-textarea"
73
+ bind:value={text}
74
+ placeholder="Write notes for this question..."
75
+ onblur={save}
76
+ ></textarea>
77
+ </div>
78
+
79
+ <div class="notes-footer">
80
+ <button class="save-button" onclick={save}>
81
+ Save Note
82
+ </button>
83
+ {#if status === "saved"}
84
+ <span class="saved">Saved</span>
85
+ {/if}
86
+ </div>
87
+ </div>
88
+
89
+ <style>
90
+ .notes-panel {
91
+ display: grid;
92
+ grid-template-rows: auto 1fr auto;
93
+ height: 100%;
94
+ border-left: 1px solid var(--pie-border, #e0e0e0);
95
+ background-color: var(--pie-background, #ffffff);
96
+ }
97
+
98
+ .notes-header {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: space-between;
102
+ padding: 0.75rem 0.75rem 0.5rem;
103
+ border-bottom: 1px solid var(--pie-border, #e0e0e0);
104
+ }
105
+
106
+ .notes-title {
107
+ display: flex;
108
+ flex-direction: column;
109
+ gap: 0.125rem;
110
+ }
111
+
112
+ .title {
113
+ font-weight: 600;
114
+ font-size: 0.95rem;
115
+ color: var(--pie-text, #000);
116
+ }
117
+
118
+ .subtitle {
119
+ font-size: 0.8rem;
120
+ color: var(--pie-text-secondary, #666);
121
+ }
122
+
123
+ .icon-button {
124
+ border: 1px solid var(--pie-border, #e0e0e0);
125
+ background: transparent;
126
+ border-radius: 4px;
127
+ padding: 0.25rem 0.5rem;
128
+ cursor: pointer;
129
+ font-size: 1rem;
130
+ line-height: 1;
131
+ }
132
+
133
+ .icon-button:hover {
134
+ background-color: var(--pie-secondary-background, #f5f5f5);
135
+ }
136
+
137
+ .notes-body {
138
+ padding: 0.75rem;
139
+ min-height: 0;
140
+ }
141
+
142
+ .notes-textarea {
143
+ width: 100%;
144
+ height: 100%;
145
+ resize: none;
146
+ border: 1px solid var(--pie-border, #e0e0e0);
147
+ border-radius: 6px;
148
+ padding: 0.5rem;
149
+ font-size: 0.875rem;
150
+ font-family: inherit;
151
+ }
152
+
153
+ .notes-footer {
154
+ display: flex;
155
+ align-items: center;
156
+ justify-content: space-between;
157
+ padding: 0.5rem 0.75rem 0.75rem;
158
+ border-top: 1px solid var(--pie-border, #e0e0e0);
159
+ }
160
+
161
+ .save-button {
162
+ padding: 0.5rem 0.75rem;
163
+ background-color: var(--pie-background, #ffffff);
164
+ border: 1px solid var(--pie-border, #e0e0e0);
165
+ border-radius: 4px;
166
+ cursor: pointer;
167
+ font-size: 0.875rem;
168
+ }
169
+
170
+ .save-button:hover {
171
+ background-color: var(--pie-secondary-background, #f5f5f5);
172
+ }
173
+
174
+ .saved {
175
+ font-size: 0.8rem;
176
+ color: var(--pie-text-secondary, #666);
177
+ }
178
+ </style>
179
+
@@ -0,0 +1,76 @@
1
+ <script lang="ts">
2
+ import type { PassageEntity, RubricBlock } from '@pie-players/pie-players-shared/types';
3
+ import '$lib/tags/pie-iife-player/PieIifePlayer.svelte';
4
+ import PiePlayerStyles from '$lib/components/PiePlayerStyles.svelte';
5
+
6
+ let {
7
+ passage,
8
+ rubricBlocks = [],
9
+ bundleHost,
10
+ env
11
+ }: {
12
+ passage: PassageEntity | null;
13
+ rubricBlocks?: RubricBlock[];
14
+ bundleHost?: string;
15
+ env: { mode: string; role: string };
16
+ } = $props();
17
+
18
+ const passageConfig = $derived(passage?.config || null);
19
+ const blocks = $derived((rubricBlocks ?? []).filter((b) => !!b?.content));
20
+ </script>
21
+
22
+ {#if blocks.length}
23
+ <div class="passage-panel">
24
+ {#each blocks as block, idx (idx)}
25
+ <div class="rubric-block prose max-w-none">
26
+ {@html block.content}
27
+ </div>
28
+ {#if idx < blocks.length - 1}
29
+ <hr class="separator" />
30
+ {/if}
31
+ {/each}
32
+ </div>
33
+ {:else if passageConfig}
34
+ <div class="passage-panel">
35
+ <PiePlayerStyles>
36
+ <pie-iife-player
37
+ config={passageConfig}
38
+ env={env}
39
+ session={{ id: '', data: [] }}
40
+ hosted={false}
41
+ show-bottom-border={false}
42
+ bundle-host={bundleHost}
43
+ ></pie-iife-player>
44
+ </PiePlayerStyles>
45
+ </div>
46
+ {:else}
47
+ <div class="passage-panel empty">
48
+ <p class="empty-message">No passage available for this item.</p>
49
+ </div>
50
+ {/if}
51
+
52
+ <style>
53
+ .passage-panel {
54
+ height: 100%;
55
+ padding: 1rem;
56
+ overflow-y: auto;
57
+ }
58
+
59
+ .separator {
60
+ border: none;
61
+ border-top: 1px solid var(--pie-border, #e0e0e0);
62
+ margin: 1rem 0;
63
+ }
64
+
65
+ .passage-panel.empty {
66
+ display: flex;
67
+ align-items: center;
68
+ justify-content: center;
69
+ color: var(--pie-text-secondary, #666);
70
+ }
71
+
72
+ .empty-message {
73
+ font-style: italic;
74
+ }
75
+ </style>
76
+