Appearance
Ghost Mode Translation Indicators ​
Problem Statement ​
Ghost Mode displays draft and multilingual CMS content inside the TV preview. Editors need a compact way to identify draft content and estimate translation completion without opening each content modal.
Solution Overview ​
The display app shows two Ghost Mode-only indicators:
TranslationProgressBadgeshows the language code and fills its background according to translation completion.DiagonalRibbonmarks draft content with aBROUILLONribbon.
The indicators are read-only. Directus mutations still happen only through the CMS visual editor handlers.
Translation Progress Rules ​
Progress is computed in src/lib/utils/translationProgress.ts.
Per-content carousel tooltip badges use the content translations directly:
- Counted fields:
title,content. excerptis counted only when the content is attached to a carousel item.link_titleis ignored because falling back to the content title is acceptable in many cases.
The sidebar global progress uses all facility contents and applies stricter filtering:
- Included: content attached to the current facility, non-archived, non-universal, and
multilingual: true. - Excluded:
archivedcontents. - Excluded: monolingual contents (
multilingualfalse, null, or missing). - Excluded universal types:
app,app-prelaunch,meteo. - Counted fields for each included content:
title,content,excerpt. - Ignored field:
link_title.
The global score is field-based:
text
completion = translatedFieldsForLocale / totalExpectedFields
totalExpectedFields = includedContents * 3Locale matching is normalized so fr, fr-FR, and fr_FR are treated as the same language family.
Draft Ribbons ​
Draft content is visible in CMS preview because the preview URL sets preview=true. The display mappers include draft items when preview mode is active.
Draft ribbons are shown only in Ghost Mode:
- Carousel dock slide cards:
GhostSlideCard.svelte. - Carousel hover tooltip:
GhostSlidePreviewTooltip.svelte. - Sidebar menu items:
Sidebar.svelte.
The reusable component is src/lib/components/ui/DiagonalRibbon.svelte. It is generic and can also be used for environment indicators such as DEVMODE or DEBUGMODE.
Implementation Guide ​
Use TranslationProgressBadge when the caller already has completion data:
svelte
<TranslationProgressBadge
locale={progress.locale}
label={progress.label}
completedFields={progress.completedFields}
totalFields={progress.totalFields}
completion={progress.completion}
/>Use getFacilityTranslationProgress() for a facility-wide summary:
ts
const progress = getFacilityTranslationProgress(facility, { locales });Use DiagonalRibbon for a non-interactive diagonal label:
svelte
<DiagonalRibbon text="BROUILLON" color="amber" size="xs" position="top-left" />Compatibility ​
These indicators are Ghost Mode and preview UI only. They do not affect normal TV runtime behavior, focus navigation, or Directus writes.
CMS and display must keep universal content type rules aligned. meteo is currently universal alongside app and app-prelaunch.
Reference Files ​
src/lib/components/translation/TranslationProgressBadge.sveltesrc/lib/components/ui/DiagonalRibbon.sveltesrc/lib/utils/translationProgress.tssrc/lib/sidebar/Sidebar.sveltesrc/lib/components/ghost/GhostSlideCard.sveltesrc/lib/components/ghost/GhostSlidePreviewTooltip.svelte