project-list: distinguish Quarto PDF vs Quarto Slides in format badge
Build and Deploy Verso / deploy (push) Successful in 9m30s

Add a quartoFlavor field ('revealjs' | 'pdf') to the Project model.
After each successful Quarto compile, CompileController detects the output
type (output.html → revealjs, otherwise pdf) and persists it.
ProjectListController includes it in the projection and serialization so
it reaches the frontend without an extra round-trip.

Badge variants:
  - quartoFlavor unset (new/uncompiled) → "Quarto PDF" #447099
  - quartoFlavor 'pdf'                  → "Quarto PDF" #447099 (Quarto blue)
  - quartoFlavor 'revealjs'             → "Quarto Slides" #7e56c2 (purple)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
claude
2026-06-10 07:55:45 +00:00
parent eada1e9979
commit bbf532d282
6 changed files with 31 additions and 6 deletions
@@ -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,
@@ -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,
}))
}
+1
View File
@@ -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: '' },
@@ -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 (
<span
@@ -407,7 +407,11 @@ ul.project-list-filters {
white-space: nowrap;
&.project-format-badge-quarto {
background-color: #447099;
background-color: #447099; // Quarto blue (PDF output)
}
&.project-format-badge-quarto-slides {
background-color: #7e56c2; // purple presentation feel, blends Quarto + RevealJS
}
&.project-format-badge-typst {
+1
View File
@@ -53,6 +53,7 @@ export type ProjectApi = {
accessLevel: ProjectAccessLevel
source: Source
compiler?: ProjectCompiler
quartoFlavor?: 'revealjs' | 'pdf'
}
export type Project = MergeAndOverride<