diff --git a/services/web/app/src/Features/Compile/CompileController.mjs b/services/web/app/src/Features/Compile/CompileController.mjs index 41c2cf42ae..12609b055d 100644 --- a/services/web/app/src/Features/Compile/CompileController.mjs +++ b/services/web/app/src/Features/Compile/CompileController.mjs @@ -1,6 +1,7 @@ import { pipeline } from 'node:stream/promises' import Metrics from '@overleaf/metrics' import ProjectGetter from '../Project/ProjectGetter.mjs' +import { Project } from '../models/Project.mjs' import CompileManager from './CompileManager.mjs' import ClsiManager from './ClsiManager.mjs' import logger from '@overleaf/logger' @@ -300,6 +301,16 @@ const _CompileController = { ? getOutputFilesArchiveSpecification(projectId, userId, buildId) : null + // Persist quarto output flavor so the project-list badge can distinguish + // RevealJS presentations from PDF documents without needing a compile. + if (status === 'success' && options.compiler === 'quarto') { + const isHtml = outputFiles.some(f => f.path === 'output.html') + Project.updateOne( + { _id: projectId }, + { quartoFlavor: isHtml ? 'revealjs' : 'pdf' } + ).exec().catch(() => {}) + } + res.json({ status, outputFiles, diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index e65138186a..a298ea74a0 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -681,7 +681,7 @@ async function _getProjects( const results = await Promise.all([ ProjectGetter.promises.findAllUsersProjects( userId, - 'name lastUpdated lastUpdatedBy publicAccesLevel archived trashed owner_ref tokens compiler' + 'name lastUpdated lastUpdatedBy publicAccesLevel archived trashed owner_ref tokens compiler quartoFlavor' ), TagsHandler.promises.getAllTags(userId), ]) @@ -826,6 +826,7 @@ function _formatProjectInfo(project, accessLevel, source, userId) { archived, trashed, compiler: project.compiler, + quartoFlavor: project.quartoFlavor, } } @@ -880,6 +881,7 @@ async function _injectProjectUsers(projects) { : users[project.owner_ref.toString()], owner_ref: undefined, compiler: project.compiler, + quartoFlavor: project.quartoFlavor, })) } diff --git a/services/web/app/src/models/Project.mjs b/services/web/app/src/models/Project.mjs index ffa49dc6ed..8415fb4fda 100644 --- a/services/web/app/src/models/Project.mjs +++ b/services/web/app/src/models/Project.mjs @@ -38,6 +38,7 @@ export const ProjectSchema = new Schema( version: { type: Number }, // incremented for every change in the project structure (folders and filenames) publicAccesLevel: { type: String, default: 'private' }, compiler: { type: String, default: settings.defaultLatexCompiler }, + quartoFlavor: { type: String, enum: ['revealjs', 'pdf', null] }, spellCheckLanguage: { type: String, default: 'en' }, deletedByExternalDataSource: { type: Boolean, default: false }, description: { type: String, default: '' }, diff --git a/services/web/frontend/js/features/project-list/components/table/cells/format-cell.tsx b/services/web/frontend/js/features/project-list/components/table/cells/format-cell.tsx index 213cf3b8bf..604c3323de 100644 --- a/services/web/frontend/js/features/project-list/components/table/cells/format-cell.tsx +++ b/services/web/frontend/js/features/project-list/components/table/cells/format-cell.tsx @@ -4,13 +4,19 @@ import { ProjectCompiler } from '../../../../../../../types/project-settings' // Map the stored compiler engine to the document format the project produces. // CLSI dispatches the real engine from the root file's extension, but the // compiler field is a faithful, cheap proxy for the project's format. -function formatLabel(compiler: ProjectCompiler | undefined): { +function formatLabel( + compiler: ProjectCompiler | undefined, + quartoFlavor: 'revealjs' | 'pdf' | undefined +): { label: string - variant: 'quarto' | 'typst' | 'latex' + variant: 'quarto-slides' | 'quarto' | 'typst' | 'latex' } { switch (compiler) { case 'quarto': - return { label: 'Quarto', variant: 'quarto' } + if (quartoFlavor === 'revealjs') { + return { label: 'Quarto Slides', variant: 'quarto-slides' } + } + return { label: 'Quarto PDF', variant: 'quarto' } case 'typst': return { label: 'Typst', variant: 'typst' } default: @@ -24,7 +30,7 @@ type FormatCellProps = { } export default function FormatCell({ project }: FormatCellProps) { - const { label, variant } = formatLabel(project.compiler) + const { label, variant } = formatLabel(project.compiler, project.quartoFlavor) return (