feat: productionize learning engine and classroom

This commit is contained in:
inman
2026-08-16 21:44:52 +08:00
parent 2d04197f3f
commit ba35adfbfa
124 changed files with 9071 additions and 796 deletions

View File

@@ -109,7 +109,7 @@ const ERROR_CAPTURE_SHIM = `<script data-iframe-error-shim>
* placed first so they run before the page's own scripts (error capture first, so
* it also observes the storage shim).
*/
export function patchHtmlForIframe(html: string): string {
export function patchHtmlForIframe(html: string, options: { offline?: boolean } = {}): string {
const iframeCss = `<style data-iframe-patch>
html, body {
width: 100%;
@@ -124,7 +124,14 @@ export function patchHtmlForIframe(html: string): string {
body { min-height: 100vh; }
</style>`;
const injection = '\n' + ERROR_CAPTURE_SHIM + '\n' + STORAGE_SHIM + '\n' + iframeCss;
// Desktop course packages are frozen before publication. Their interactive
// pages must therefore be self-contained: the local player blocks every
// network, parent, plugin and nested-frame capability while preserving inline
// scripts/styles, data/blob media and the existing sandboxed interaction UI.
const offlineCsp = options.offline
? `<meta data-makelore-offline-csp http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'unsafe-inline' data:; img-src data: blob:; font-src data:; media-src data: blob:; worker-src blob:; connect-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'">`
: '';
const injection = `\n${[offlineCsp, ERROR_CAPTURE_SHIM, STORAGE_SHIM, iframeCss].filter(Boolean).join('\n')}`;
return injectIntoDocumentHead(html, injection);
}