Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/api/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ app.route("/api", createTextCatalogRoutes(booksDir))
app.route("/api", createTTSRoutes(booksDir))
app.route("/api", createStepRoutes(stepService, pipelineService, booksDir, promptsDir, configPath))
app.route("/api", createPresetRoutes(configPath))
app.route("/api", createAdtPreviewRoutes(booksDir, webAssetsDir))
app.route("/api", createAdtPreviewRoutes(booksDir, webAssetsDir, configPath))
app.route("/api", createSpeechConfigRoutes(configPath))

export default app
8 changes: 8 additions & 0 deletions apps/api/src/routes/adt-preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
buildQuizAnswers,
buildTextCatalog,
pad3,
loadBookConfig,
} from "@adt/pipeline"

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -212,6 +213,7 @@ function buildPreviewConfig(storage: Storage, language: string) {
export function createAdtPreviewRoutes(
booksDir: string,
webAssetsDir: string,
configPath?: string,
): Hono {
const app = new Hono()

Expand Down Expand Up @@ -441,6 +443,10 @@ export function createAdtPreviewRoutes(
if (!filename.endsWith(".html")) throw new HTTPException(404, { message: "Not found" })
const pageId = filename.replace(/\.html$/, "")

const safeLabel = parseBookLabel(label)
const config = loadBookConfig(safeLabel, booksDir, configPath)
const applyBodyBackground = config.apply_body_background

return withStorage(label, (storage) => {
const title = getBookTitle(storage)
const language = getBookLanguage(storage)
Expand Down Expand Up @@ -471,6 +477,7 @@ export function createAdtPreviewRoutes(
hasMath: false,
bundleVersion: "1",
skipContentWrapper: true,
applyBodyBackground,
})

c.header("Content-Type", "text/html; charset=utf-8")
Expand Down Expand Up @@ -503,6 +510,7 @@ export function createAdtPreviewRoutes(
activityAnswers,
hasMath: false,
bundleVersion: "1",
applyBodyBackground,
})

c.header("Content-Type", "text/html; charset=utf-8")
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/routes/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export function createPackageRoutes(
outputLanguages,
title,
webAssetsDir,
applyBodyBackground: config.apply_body_background,
})

return c.json({ status: "completed", label: safeLabel })
Expand Down
1 change: 1 addition & 0 deletions apps/api/src/services/export-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export async function exportBook(
outputLanguages,
title,
webAssetsDir,
applyBodyBackground: config.apply_body_background,
})
}

Expand Down
13 changes: 12 additions & 1 deletion apps/studio/src/components/pipeline/stages/BookPreviewFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface BookPreviewFrameProps {
onSelectElement?: (dataId: string, rect: DOMRect) => void
/** Called when a text element is edited (blur/Enter after contenteditable) */
onTextChanged?: (dataId: string, newText: string, fullHtml: string) => void
/** When true (default), applies data-background-color to the iframe body */
applyBodyBackground?: boolean
}

/**
Expand All @@ -41,6 +43,7 @@ export const BookPreviewFrame = forwardRef<BookPreviewFrameHandle, BookPreviewFr
changedElements,
onSelectElement,
onTextChanged,
applyBodyBackground,
}, ref) {
const iframeRef = useRef<HTMLIFrameElement>(null)

Expand Down Expand Up @@ -241,6 +244,14 @@ ${interactiveScript}
doc.body.appendChild(scriptEl)
}

// Apply data-background-color from content to iframe body
if (applyBodyBackground !== false) {
const bgEl = doc.querySelector("[data-background-color]")
doc.body.style.backgroundColor = bgEl?.getAttribute("data-background-color") ?? ""
} else {
doc.body.style.backgroundColor = ""
}

// Measure multiple times to catch late reflows from Tailwind CDN, fonts, and images.
// Wait one frame so the browser queues font loads for the new content,
// then wait for fonts.ready so we measure the final layout.
Expand Down Expand Up @@ -275,7 +286,7 @@ ${interactiveScript}
// When html prop changes, update the body directly (no iframe reload)
useEffect(() => {
if (readyRef.current) injectAndMeasure(sanitizedHtml)
}, [sanitizedHtml])
}, [sanitizedHtml, applyBodyBackground])

// Inject/update pruned element styles into the iframe
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"
import { api } from "@/api/client"
import type { PageDetail, VersionEntry } from "@/api/client"
import { useApiKey } from "@/hooks/use-api-key"
import { useActiveConfig } from "@/hooks/use-debug"
import { useStepHeader } from "../StepViewRouter"
import { BookPreviewFrame, type BookPreviewFrameHandle } from "./BookPreviewFrame"
import { SectionEditToolbar } from "./SectionEditToolbar"
Expand Down Expand Up @@ -314,6 +315,8 @@ export function StoryboardSectionDetail({
const queryClient = useQueryClient()
const { apiKey, hasApiKey } = useApiKey()
const { headerSlotEl } = useStepHeader()
const { data: activeConfigData } = useActiveConfig(bookLabel)
const applyBodyBackground = (activeConfigData?.merged as Record<string, unknown> | undefined)?.apply_body_background !== false

const [saving, setSaving] = useState(false)
const [rerendering, setRerendering] = useState(false)
Expand Down Expand Up @@ -1265,6 +1268,7 @@ export function StoryboardSectionDetail({
changedElements={changedElements}
onSelectElement={handleSelectElement}
onTextChanged={handleTextChanged}
applyBodyBackground={applyBodyBackground}
/>
) : (
<div className="p-4 text-sm text-muted-foreground border rounded">
Expand Down
25 changes: 25 additions & 0 deletions apps/studio/src/components/pipeline/stages/StoryboardSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export function StoryboardSettings({ bookLabel, headerTarget, tab = "general" }:
const [renderingTemplateName, setRenderingTemplateName] = useState("")
const [renderingTemperature, setRenderingTemperature] = useState("")
const [styleguide, setStyleguide] = useState("")
const [applyBodyBackground, setApplyBodyBackground] = useState(true)
const [sectioningPromptDraft, setSectioningPromptDraft] = useState<string | null>(null)
const [renderingPromptDraft, setRenderingPromptDraft] = useState<string | null>(null)
const [renderingTemplateDraft, setRenderingTemplateDraft] = useState<string | null>(null)
Expand Down Expand Up @@ -174,6 +175,8 @@ export function StoryboardSettings({ bookLabel, headerTarget, tab = "general" }:
}
// Styleguide
setStyleguide(typeof merged.styleguide === "string" ? merged.styleguide : "")
// Body background
setApplyBodyBackground(merged.apply_body_background !== false)
// Rendering config comes from the default render strategy
if (merged.render_strategies && merged.default_render_strategy) {
const strategies = merged.render_strategies as Record<string, { render_type?: string; config?: { model?: string; prompt?: string; template?: string; temperature?: number } }>
Expand Down Expand Up @@ -295,6 +298,9 @@ export function StoryboardSettings({ bookLabel, headerTarget, tab = "general" }:
if (shouldWrite("styleguide")) {
overrides.styleguide = styleguide || undefined
}
if (shouldWrite("apply_body_background")) {
overrides.apply_body_background = applyBodyBackground
}
// Write rendering temperature into the default render strategy config
if (shouldWrite("rendering_temperature") && defaultRenderStrategy) {
const existingStrategies = (overrides.render_strategies ?? merged?.render_strategies ?? {}) as Record<string, Record<string, unknown>>
Expand Down Expand Up @@ -681,6 +687,25 @@ export function StoryboardSettings({ bookLabel, headerTarget, tab = "general" }:
Lower values produce more consistent styling across pages.
</p>
</div>

<div>
<h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2">
Display
</h3>
<div className="flex items-center gap-3">
<Switch
id="apply-body-background"
checked={applyBodyBackground}
onCheckedChange={(v) => { setApplyBodyBackground(v); markDirty("apply_body_background") }}
/>
<Label htmlFor="apply-body-background" className="text-sm font-normal">
Apply page background colors
</Label>
</div>
<p className="text-xs text-muted-foreground mt-1.5">
When enabled, background colors from the styleguide are applied to the full page body.
</p>
</div>
</div>

{/* Prompt editor */}
Expand Down
20 changes: 20 additions & 0 deletions apps/studio/src/routes/books.new.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ function AddBookPage() {
const [textGroupTypes, setTextGroupTypes] = useState<Record<string, string>>({})
const [sectionTypes, setSectionTypes] = useState<Record<string, string>>({})
const [sectioningMode, setSectioningMode] = useState("section")
const [applyBodyBackground, setApplyBodyBackground] = useState(true)

// Styleguide preview
const [styleguidePreviewOpen, setStyleguidePreviewOpen] = useState(false)
Expand Down Expand Up @@ -314,6 +315,9 @@ function AddBookPage() {
// Styleguide from preset
setStyleguide(typeof config.styleguide === "string" ? config.styleguide : "")

// Body background from preset
setApplyBodyBackground(config.apply_body_background !== false)

// Custom layout auto-expands advanced panel
if (layoutType === "custom") {
setShowAdvancedLayout(true)
Expand Down Expand Up @@ -412,6 +416,7 @@ function AddBookPage() {
configOverrides.output_languages = Array.from(outputLanguages)
}
configOverrides.spread_mode = spreadMode
configOverrides.apply_body_background = applyBodyBackground
if (parsedStartPage !== undefined) {
configOverrides.start_page = parsedStartPage
}
Expand Down Expand Up @@ -756,6 +761,21 @@ function AddBookPage() {
Merge facing pages as spreads (cover + page pairs).
</p>
</div>
<div className="space-y-1.5">
<div className="flex items-center gap-2">
<Switch
id="apply-body-background"
checked={applyBodyBackground}
onCheckedChange={setApplyBodyBackground}
/>
<Label htmlFor="apply-body-background" className="text-xs">
Apply page background colors
</Label>
</div>
<p className="text-xs text-muted-foreground">
When enabled, background colors from the styleguide are applied to the full page body.
</p>
</div>
<AdvancedLayoutPanel
defaultRenderStrategy={defaultRenderStrategy}
onDefaultRenderStrategyChange={setDefaultRenderStrategy}
Expand Down
Loading