Files
simstudioai--sim/apps/sim/lib/pptx-renderer/model/theme.ts
T
wehub-resource-sync d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

96 lines
2.8 KiB
TypeScript

/**
* Theme parser — extracts color scheme and font definitions from a:theme XML.
*/
import type { SafeXmlNode } from '../parser/xml-parser'
export interface ThemeData {
colorScheme: Map<string, string>
majorFont: { latin: string; ea: string; cs: string }
minorFont: { latin: string; ea: string; cs: string }
fillStyles: SafeXmlNode[] // from a:fillStyleLst children (indexed 1-based)
lineStyles: SafeXmlNode[] // from a:lnStyleLst children (indexed 1-based)
effectStyles: SafeXmlNode[] // from a:effectStyleLst children (indexed 1-based)
}
/** Known color scheme slot names in a:clrScheme. */
const COLOR_SLOTS = [
'dk1',
'dk2',
'lt1',
'lt2',
'accent1',
'accent2',
'accent3',
'accent4',
'accent5',
'accent6',
'hlink',
'folHlink',
] as const
/**
* Extract a hex color value from a color definition node.
* Handles both `a:srgbClr@val` and `a:sysClr@lastClr`.
*/
function extractColor(node: SafeXmlNode): string | undefined {
const srgb = node.child('srgbClr')
if (srgb.exists()) {
return srgb.attr('val')
}
const sys = node.child('sysClr')
if (sys.exists()) {
return sys.attr('lastClr') ?? sys.attr('val')
}
return undefined
}
/**
* Parse font info from a majorFont or minorFont node.
* Extracts typeface attributes from latin, ea, and cs child elements.
*/
function parseFontInfo(fontNode: SafeXmlNode): { latin: string; ea: string; cs: string } {
return {
latin: fontNode.child('latin').attr('typeface') ?? '',
ea: fontNode.child('ea').attr('typeface') ?? '',
cs: fontNode.child('cs').attr('typeface') ?? '',
}
}
/**
* Parse a theme XML root (`a:theme`) into ThemeData.
*/
export function parseTheme(root: SafeXmlNode): ThemeData {
const themeElements = root.child('themeElements')
// --- Color scheme ---
const clrScheme = themeElements.child('clrScheme')
const colorScheme = new Map<string, string>()
for (const slot of COLOR_SLOTS) {
const slotNode = clrScheme.child(slot)
if (slotNode.exists()) {
const hex = extractColor(slotNode)
if (hex !== undefined) {
colorScheme.set(slot, hex)
}
}
}
// --- Font scheme ---
const fontScheme = themeElements.child('fontScheme')
const majorFont = parseFontInfo(fontScheme.child('majorFont'))
const minorFont = parseFontInfo(fontScheme.child('minorFont'))
// --- Format scheme ---
const fmtScheme = themeElements.child('fmtScheme')
const fillStyleLst = fmtScheme.child('fillStyleLst')
const fillStyles: SafeXmlNode[] = fillStyleLst.allChildren()
const lnStyleLst = fmtScheme.child('lnStyleLst')
const lineStyles: SafeXmlNode[] = lnStyleLst.allChildren()
const effectStyleLst = fmtScheme.child('effectStyleLst')
const effectStyles: SafeXmlNode[] = effectStyleLst.allChildren()
return { colorScheme, majorFont, minorFont, fillStyles, lineStyles, effectStyles }
}