Skip to content

Improve default slide generation styling - #4598

Merged
steve8708 merged 12 commits into
mainfrom
steve8708/changes-7130
Sep 9, 2026
Merged

Improve default slide generation styling#4598
steve8708 merged 12 commits into
mainfrom
steve8708/changes-7130

Conversation

@steve8708

Copy link
Copy Markdown
Contributor

Summary

  • replace the generic dark slide fallback with a light, padded presentation style
  • carry the fallback direction through MCP action descriptions and generation prompts
  • add renderer and padding regression coverage

Validation

  • pnpm guard:no-raw-colors
  • node_modules/.bin/vitest --run app/components/deck/SlideRenderer.test.tsx app/hooks/use-deck-design-system.test.ts app/lib/normalize-slide-padding.test.ts --maxWorkers=1
  • node_modules/.bin/vitest --run actions/create-deck.test.ts actions/add-slide.test.ts app/lib/create-deck-generation.test.ts --maxWorkers=1
  • pnpm guards (one initial raw-color exception fixed and rechecked)

Visual browser proof was unavailable because the local CUA service failed to start; the local Slides app shell did serve successfully.

@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 2 potential issues 🟡

Review Details

Incremental Code Review Summary

The latest changes add regression assertions for the light Markdown palette and updated padding, but the production implementation still has the previously reported export, background, contrast, sanitization, and editor-token findings; those open comments were not reposted. The new review identified two additional regressions in the standalone export and imported-slide rendering paths.

New Findings

  • 🟡 MEDIUM — Standalone HTML export now declares Inter/design-system fonts without loading or embedding them, so exported decks silently fall back to generic/local fonts and can reflow or clip text.
  • 🟡 MEDIUM — Applying the new padding to every .fmd-slide also affects source-preserving imported PPTX/PDF wrappers, shifting the autofit coordinate system for absolute-positioned source elements and potentially triggering false overflow/transforms.

The fallback styling direction and added tests are useful, and the focused changed-slide tests pass according to the reviewers. However, the export needs a deliberate font-loading strategy and imported source canvases need to remain full-coordinate-space. This remains standard risk due to shared rendering/export behavior.

🧪 Browser testing: Will run after this review (PR touches UI code).

Comment on lines 107 to +110
width: 100%; height: 100%;
background: #111;
overflow: hidden;
font-family: 'Poppins', sans-serif;
font-family: 'Inter', sans-serif;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Provide the selected font in standalone HTML exports

The generated export now declares Inter or a design-system font family, but it no longer loads or embeds any font resource (the previous Poppins stylesheet was removed). On machines without those fonts, the file falls back to a generic sans-serif, changing line wrapping and potentially causing fit/clipping differences from the editor. Load a supported fallback font or provide a deliberate self-host/embed path for selected design-system fonts.

Additional Info
Found independently by 2 review agents.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4d991c3. Standalone exports load supported selected Google Fonts, with the existing system fallback for other families.

Comment thread templates/slides/app/global.css
builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

builder-io-integration[bot]

This comment was marked as outdated.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 5 potential issues 🟡

Review Details

Incremental Code Review Summary

The latest commit fixes the named dark utility detection and Builder-proxy fallback issues previously reported; those comments were resolved and are not reposted. The remaining open default-font export comment also remains unchanged. The new implementation adds token substitution, background compatibility, and broader inline-editor styling, but introduces several consistency and state issues.

New Findings

  • 🟡 MEDIUM — Standalone export still drops most valid named/gradient Tailwind backgrounds, falling back to the neutral canvas.
  • 🟡 MEDIUM — Builder token substitution occurs after sanitization and can reintroduce unsafe CSS into the generated style attribute.
  • 🟡 MEDIUM — Builder-tokenized slide backgrounds are not resolved because the --ds-bg serialization omits the hydrated token map.
  • 🟡 MEDIUM — Short/arbitrary dark CSS backgrounds are misclassified by export/renderer contrast detection.
  • 🟡 MEDIUM — Newly inserted text boxes can capture a stale design-system font because the placement callback dependencies are incomplete.
  • 🟡 MEDIUM — TipTap inline editing still forces white child text on the new light canvas despite the added CSS variables.

The shared background/token direction is improving, but renderer, inline editor, and standalone export still need one canonical background/contrast/token path. This remains standard risk. Focused renderer/style tests passed in agent validation; broader typecheck remains blocked by local production configuration.

🧪 Browser testing: Will run after this review (PR touches UI code).

Comment thread templates/slides/actions/export-html.ts Outdated
Comment on lines +90 to +94
function standaloneBackgroundCssValue(value: string): string {
return (
backgroundCssValue(value) ??
STANDALONE_TAILWIND_BACKGROUNDS[value] ??
DEFAULT_SLIDE_BACKGROUND

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Preserve all supported named and gradient backgrounds in standalone export

The renderer retains every bg-* class, but standalone output has no Tailwind stylesheet and this resolver maps only a small dark-color allowlist. Valid values such as bg-blue-500, bg-indigo-950, and gradient utilities therefore fall back to #F5F2EA in exported HTML even though they render differently in the app. Translate the supported utility combinations to CSS or emit an equivalent stylesheet instead of silently replacing them.

Additional Info
Found independently by 2 review agents.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bc5c4d3. Standalone export now preserves arbitrary CSS backgrounds and translates supported Tailwind solid colors plus gradient direction/from/via/to combinations instead of falling back to the default canvas.

Comment thread templates/slides/actions/export-html.ts Outdated
Comment on lines +59 to +63
const resolved = sanitized
.replace(/[{}<>;]/g, "")
.replace(
/var\(\s*(--[a-zA-Z][\w-]*)\s*\)/g,
(_, name: string) => builderTokenValues?.[name] ?? `var(${name})`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Sanitize hydrated Builder token values after substitution

safeCssToken sanitizes the original string before replacing var(--token), but inserts builderTokenValues[name] without sanitizing that replacement. A hydrated value containing a semicolon, url(...), or other CSS payload can therefore re-enter the generated style attribute after the sanitizer has run. Validate/sanitize substituted values and revalidate the final resolved token.

Additional Info
Found by 1 review agent; this is a security-sensitive export path.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bc5c4d3. Hydrated Builder substitutions are sanitized before insertion, and the final resolved token is sanitized and rejected when an unresolved var or unsafe value remains.

Comment thread templates/slides/actions/export-html.ts Outdated
Comment on lines +150 to +152
const darkBackground = isDarkStandaloneBackground(slideBackground);
return [
`--ds-bg: ${safeCssToken(standaloneBackgroundCssValue(slideBackground), DEFAULT_SLIDE_BACKGROUND)}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Resolve hydrated Builder values for the exported slide background

The exporter passes builderTokenValues to foreground/font token serialization but not to the --ds-bg call. A design-system background such as var(--brand-canvas) is therefore treated as unresolved and replaced with the warm-neutral fallback, even when hydration supplied that token. Pass the hydrated map through the background serialization path and cover a tokenized slide background.

Additional Info
Found independently by 2 review agents.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bc5c4d3. The hydrated Builder token map now flows through slide background serialization, so tokenized backgrounds resolve in the standalone export.

Comment thread templates/slides/actions/export-html.ts Outdated
value === "bg-black" ||
/^bg-(?:slate|gray|zinc|neutral|stone)-(?:900|950)$/i.test(value) ||
(() => {
const hex = value.match(/^#([\da-f]{6})$/i)?.[1];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Detect short and arbitrary dark backgrounds in export contrast selection

The renderer handles 3/4/6/8-digit hex values, but export darkness detection only matches six-digit hex and does not parse arbitrary CSS colors after bg-[...] unwrapping. A no-design-system slide with #000, #000f, or bg-[rgb(0,0,0)] exports a dark canvas with the light-canvas dark text tokens. Mirror the renderer's supported luminance parsing before choosing fallback foreground tokens.

Additional Info
Found independently by 2 review agents for the broader renderer/export mismatch.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bc5c4d3. Export contrast detection now handles 3/4/6/8-digit hex and rgb/rgba colors, including arbitrary CSS background values and dark gradients.

Comment on lines +4495 to +4496
box.style.fontFamily =
designSystem?.typography.bodyFont ?? "Inter, sans-serif";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Refresh the design-system font used for new text boxes

placeTextBoxAt is memoized with a dependency list that does not include designSystem, but this new assignment reads designSystem?.typography.bodyFont. If the design system resolves asynchronously or changes after mount, the callback keeps the old value and new text boxes use Inter instead of the linked body font. Include the selected font/design-system value in the callback dependencies.

Additional Info
Found by 1 review agent; confirmed from the callback closure and new font read.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bc5c4d3. placeTextBoxAt now depends on the selected body font, so asynchronously resolved design systems are used for newly created text boxes.

@steve8708
steve8708 merged commit 01f6b7b into main Sep 9, 2026
45 checks passed
@steve8708
steve8708 deleted the steve8708/changes-7130 branch September 9, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant