Add HTML/RevealJS preview alongside existing PDF preview
Build and Deploy Verso / deploy (push) Successful in 11m0s
Build and Deploy Verso / deploy (push) Successful in 11m0s
clsi-nginx.conf: the types{} block was overriding all nginx defaults,
leaving HTML/CSS/JS/fonts as application/octet-stream. Add the full
set of web MIME types so RevealJS assets are served correctly. Also
needed for X-Content-Type-Options: nosniff to pass.
CompileController.js: success was hardcoded to require output.pdf.
Also accept output.html so a RevealJS compile is reported as
'success' rather than 'failure'.
QuartoRunner.js: remove hardcoded --to typst --output output.pdf.
Instead run `quarto render` without --to/--output so the YAML
frontmatter decides the format (typst → PDF, revealjs → HTML, etc.).
Pass --embed-resources so HTML output is self-contained (flag is
silently ignored by the typst backend). After render, rename
main.pdf → output.pdf or main.html → output.html so the pipeline
finds the standard canonical filename.
output-files.ts: handleOutputFiles now falls back to output.html when
output.pdf is absent. Download URL uses outputFile.path instead of
the hardcoded 'output.pdf' string.
pdf-viewer.tsx: when pdfUrl contains output.html, bypass PDF.js
entirely and render a sandboxed iframe (allow-scripts for RevealJS
interactivity, allow-presentation for fullscreen).
Usage: set `format: revealjs` in the .qmd YAML frontmatter to get
an HTML presentation preview; set `format: typst` for PDF.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,8 +25,19 @@ server {
|
||||
gzip_types text/plain;
|
||||
gzip_proxied any;
|
||||
types {
|
||||
text/plain log blg aux stdout stderr;
|
||||
application/pdf pdf;
|
||||
text/html html htm;
|
||||
text/css css;
|
||||
application/javascript js;
|
||||
application/json json;
|
||||
image/svg+xml svg svgz;
|
||||
image/png png;
|
||||
image/jpeg jpeg jpg;
|
||||
image/gif gif;
|
||||
image/webp webp;
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
application/pdf pdf;
|
||||
text/plain log blg aux stdout stderr txt;
|
||||
}
|
||||
# handle output files for specific users
|
||||
location ~ ^/project/([0-9a-f]+)/user/([0-9a-f]+)/build/([0-9a-f-]+)/output/(.+)$ {
|
||||
|
||||
@@ -90,7 +90,10 @@ function compile(req, res, next) {
|
||||
} else {
|
||||
if (
|
||||
outputFiles.some(
|
||||
file => file.path === 'output.pdf' && file.size > 0
|
||||
file =>
|
||||
(file.path === 'output.pdf' ||
|
||||
file.path === 'output.html') &&
|
||||
file.size > 0
|
||||
)
|
||||
) {
|
||||
status = 'success'
|
||||
|
||||
@@ -50,11 +50,21 @@ function runQuarto(compileName, options, callback) {
|
||||
|
||||
function _buildQuartoCommand(mainFile) {
|
||||
// Run through a POSIX shell so stderr is merged into stdout (2>&1).
|
||||
// Quarto writes all progress and error messages to stderr; without this
|
||||
// the log panel would be empty on failure.
|
||||
// LocalCommandRunner replaces $COMPILE_DIR before the shell sees it.
|
||||
//
|
||||
// We do NOT pass --to or --output: let the YAML frontmatter decide the
|
||||
// output format (typst → output.pdf, revealjs → output.html, etc.).
|
||||
// --embed-resources makes HTML output self-contained (ignored for typst).
|
||||
// After render we rename the produced file to the canonical output name
|
||||
// expected by the rest of the pipeline.
|
||||
const inputPath = `$COMPILE_DIR/${mainFile}`
|
||||
const cmd = `quarto render ${inputPath} --to typst --output output.pdf 2>&1`
|
||||
const baseName = mainFile.replace(/\.[^/.]+$/, '') // strip extension
|
||||
const pdfOut = `$COMPILE_DIR/${baseName}.pdf`
|
||||
const htmlOut = `$COMPILE_DIR/${baseName}.html`
|
||||
const cmd =
|
||||
`quarto render ${inputPath} --embed-resources 2>&1 && ` +
|
||||
`(mv ${pdfOut} $COMPILE_DIR/output.pdf 2>/dev/null || ` +
|
||||
`mv ${htmlOut} $COMPILE_DIR/output.html 2>/dev/null)`
|
||||
return ['/bin/sh', '-c', cmd]
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,19 @@ function PdfViewer() {
|
||||
return null
|
||||
}
|
||||
|
||||
// HTML outputs (RevealJS, etc.) must always use the native iframe;
|
||||
// PDF.js cannot render HTML.
|
||||
if (pdfUrl.includes('output.html')) {
|
||||
return (
|
||||
<iframe
|
||||
title="Presentation Preview"
|
||||
src={pdfUrl}
|
||||
style={{ width: '100%', height: '100%', border: 'none' }}
|
||||
sandbox="allow-scripts allow-same-origin allow-presentation allow-popups"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
switch (pdfViewer) {
|
||||
case 'native':
|
||||
return <iframe title="PDF Preview" src={pdfUrl} />
|
||||
|
||||
@@ -24,7 +24,9 @@ export function handleOutputFiles(
|
||||
projectId: string,
|
||||
data: CompileResponseData
|
||||
): PDFFile | null {
|
||||
const outputFile = outputFiles.get('output.pdf')
|
||||
// Accept either a PDF or an HTML output (e.g. RevealJS presentation)
|
||||
const outputFile =
|
||||
outputFiles.get('output.pdf') ?? outputFiles.get('output.html')
|
||||
if (!outputFile) return null
|
||||
|
||||
outputFile.editorId = outputFile.editorId || EDITOR_SESSION_ID
|
||||
@@ -54,7 +56,7 @@ export function handleOutputFiles(
|
||||
params.set('popupDownload', 'true') // save PDF download as file
|
||||
params.set('editorId', outputFile.editorId)
|
||||
|
||||
outputFile.pdfDownloadUrl = `/download/project/${projectId}/build/${outputFile.build}/output/output.pdf?${params}`
|
||||
outputFile.pdfDownloadUrl = `/download/project/${projectId}/build/${outputFile.build}/output/${outputFile.path}?${params}`
|
||||
}
|
||||
|
||||
return outputFile
|
||||
|
||||
Reference in New Issue
Block a user