Initial commit after recreate

This commit is contained in:
2026-04-11 09:21:22 +02:00
commit 02704133f4
378 changed files with 93091 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
{
"name": "@gnommo/slide-contracts",
"private": true,
"version": "0.1.0",
"type": "module",
"exports": {
".": "./src/index.ts"
}
}
+13
View File
@@ -0,0 +1,13 @@
import type { SlideTemplateKey } from "./templates";
export interface FieldBudget {
targetMin?: number;
targetMax: number;
hardMax: number;
notes?: string;
}
export interface SlideTemplateBudget {
template: SlideTemplateKey;
description: string;
fields: Record<string, FieldBudget>;
}
export declare const slideTemplateBudgets: Record<SlideTemplateKey, SlideTemplateBudget>;
+138
View File
@@ -0,0 +1,138 @@
export var slideTemplateBudgets = {
SquareYellow: {
template: "SquareYellow",
description: "One image plus one short header.",
fields: {
header: { targetMin: 8, targetMax: 24, hardMax: 32 },
imageAlt: { targetMin: 12, targetMax: 60, hardMax: 100 }
}
},
SquareVideo: {
template: "SquareVideo",
description: "One video plus one short header.",
fields: {
header: { targetMin: 8, targetMax: 24, hardMax: 32 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
FullscreenSplit: {
template: "FullscreenSplit",
description: "One image, one short text block.",
fields: {
eyebrow: { targetMin: 6, targetMax: 14, hardMax: 24 },
title: { targetMin: 12, targetMax: 34, hardMax: 44 },
body: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
FullscreenVideo: {
template: "FullscreenVideo",
description: "Full-bleed video with optional short overlay text.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
},
caption: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
FullscreenVideoTitle: {
template: "FullscreenVideoTitle",
description: "Full-bleed video with one large overlaid title.",
fields: {
title: { targetMin: 12, targetMax: 26, hardMax: 36 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
FullscreenVideoCenterCaption: {
template: "FullscreenVideoCenterCaption",
description: "Full-bleed video with one oversized centered caption.",
fields: {
caption: { targetMin: 12, targetMax: 30, hardMax: 42 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
EquationFocus: {
template: "EquationFocus",
description: "One display equation plus one short annotation.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
title: { targetMin: 12, targetMax: 32, hardMax: 48 },
latexString: {
targetMin: 8,
targetMax: 60,
hardMax: 120,
notes: "One expression only."
},
annotation: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
QuoteImage: {
template: "QuoteImage",
description: "One quote plus one image.",
fields: {
quote: { targetMin: 18, targetMax: 50, hardMax: 72 },
attribution: { targetMin: 4, targetMax: 18, hardMax: 24 }
}
},
ChartSingle: {
template: "ChartSingle",
description: "One chart and one short framing line.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
title: { targetMin: 12, targetMax: 30, hardMax: 40 },
body: { targetMin: 12, targetMax: 36, hardMax: 48 },
pointLabel: { targetMin: 4, targetMax: 10, hardMax: 14 }
}
},
ProcessFlow: {
template: "ProcessFlow",
description: "Short pipeline with 3-5 steps.",
fields: {
title: { targetMin: 12, targetMax: 34, hardMax: 44 },
step: { targetMin: 8, targetMax: 22, hardMax: 30 }
}
},
DefinitionCard: {
template: "DefinitionCard",
description: "One term, one definition, one concrete example.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
term: { targetMin: 6, targetMax: 22, hardMax: 28 },
definition: { targetMin: 18, targetMax: 50, hardMax: 65 },
example: { targetMin: 12, targetMax: 40, hardMax: 52 }
}
},
GlitchComponentFrame: {
template: "GlitchComponentFrame",
description: "Interactive hosted component plus one short framing line.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
componentId: { targetMin: 4, targetMax: 24, hardMax: 40 },
componentUrl: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted component URL."
},
caption: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
}
};
+153
View File
@@ -0,0 +1,153 @@
import type { SlideTemplateKey } from "./templates";
export interface FieldBudget {
targetMin?: number;
targetMax: number;
hardMax: number;
notes?: string;
}
export interface SlideTemplateBudget {
template: SlideTemplateKey;
description: string;
fields: Record<string, FieldBudget>;
}
export const slideTemplateBudgets: Record<SlideTemplateKey, SlideTemplateBudget> = {
SquareYellow: {
template: "SquareYellow",
description: "One image plus one short header.",
fields: {
header: { targetMin: 8, targetMax: 24, hardMax: 32 },
imageAlt: { targetMin: 12, targetMax: 60, hardMax: 100 }
}
},
SquareVideo: {
template: "SquareVideo",
description: "One video plus one short header.",
fields: {
header: { targetMin: 8, targetMax: 24, hardMax: 32 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
FullscreenSplit: {
template: "FullscreenSplit",
description: "One image, one short text block.",
fields: {
eyebrow: { targetMin: 6, targetMax: 14, hardMax: 24 },
title: { targetMin: 12, targetMax: 34, hardMax: 44 },
body: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
FullscreenVideo: {
template: "FullscreenVideo",
description: "Full-bleed video with optional short overlay text.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
},
caption: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
FullscreenVideoTitle: {
template: "FullscreenVideoTitle",
description: "Full-bleed video with one large overlaid title.",
fields: {
title: { targetMin: 12, targetMax: 26, hardMax: 36 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
FullscreenVideoCenterCaption: {
template: "FullscreenVideoCenterCaption",
description: "Full-bleed video with one oversized centered caption.",
fields: {
caption: { targetMin: 12, targetMax: 30, hardMax: 42 },
videoSrc: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted or CDN video URL."
}
}
},
EquationFocus: {
template: "EquationFocus",
description: "One display equation plus one short annotation.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
title: { targetMin: 12, targetMax: 32, hardMax: 48 },
latexString: {
targetMin: 8,
targetMax: 60,
hardMax: 120,
notes: "One expression only."
},
annotation: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
},
QuoteImage: {
template: "QuoteImage",
description: "One quote plus one image.",
fields: {
quote: { targetMin: 18, targetMax: 50, hardMax: 72 },
attribution: { targetMin: 4, targetMax: 18, hardMax: 24 }
}
},
ChartSingle: {
template: "ChartSingle",
description: "One chart and one short framing line.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
title: { targetMin: 12, targetMax: 30, hardMax: 40 },
body: { targetMin: 12, targetMax: 36, hardMax: 48 },
pointLabel: { targetMin: 4, targetMax: 10, hardMax: 14 }
}
},
ProcessFlow: {
template: "ProcessFlow",
description: "Short pipeline with 3-5 steps.",
fields: {
title: { targetMin: 12, targetMax: 34, hardMax: 44 },
step: { targetMin: 8, targetMax: 22, hardMax: 30 }
}
},
DefinitionCard: {
template: "DefinitionCard",
description: "One term, one definition, one concrete example.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
term: { targetMin: 6, targetMax: 22, hardMax: 28 },
definition: { targetMin: 18, targetMax: 50, hardMax: 65 },
example: { targetMin: 12, targetMax: 40, hardMax: 52 }
}
},
GlitchComponentFrame: {
template: "GlitchComponentFrame",
description: "Interactive hosted component plus one short framing line.",
fields: {
header: { targetMin: 6, targetMax: 20, hardMax: 28 },
componentId: { targetMin: 4, targetMax: 24, hardMax: 40 },
componentUrl: {
targetMin: 12,
targetMax: 160,
hardMax: 300,
notes: "Prefer a stable hosted component URL."
},
caption: { targetMin: 12, targetMax: 42, hardMax: 56 }
}
}
};
+3
View File
@@ -0,0 +1,3 @@
export * from "./templates";
export * from "./budgets";
export * from "./metadata";
+3
View File
@@ -0,0 +1,3 @@
export * from "./templates";
export * from "./budgets";
export * from "./metadata";
+3
View File
@@ -0,0 +1,3 @@
export * from "./templates";
export * from "./budgets";
export * from "./metadata";
+40
View File
@@ -0,0 +1,40 @@
import type { SlideTemplateKey, SlideTemplateProps } from "./templates";
export type SlideTemplateFieldType = "text" | "textarea" | "lines" | "image" | "video" | "latex";
export interface SlideTemplateFieldDefinition {
name: string;
type: SlideTemplateFieldType;
label: string;
placeholder?: string;
description?: string;
required?: boolean;
}
export interface SlideTemplateDefinition {
componentKey: SlideTemplateKey;
label: string;
description: string;
displayMode: "square" | "fullscreen";
supportedDisplayModes?: Array<"square" | "fullscreen">;
fields: SlideTemplateFieldDefinition[];
}
export interface SlideTemplateAvailability {
componentKey: SlideTemplateKey;
label: string;
description: string;
displayMode: "square" | "fullscreen";
fields: SlideTemplateFieldDefinition[];
}
export interface SlideTemplateDraft {
props: SlideTemplateProps;
latexString?: string;
}
export declare const slideTemplateDefinitions: Record<SlideTemplateKey, SlideTemplateDefinition>;
export declare const slideTemplateDefinitionList: SlideTemplateDefinition[];
export declare const slideTemplateAvailabilityList: SlideTemplateAvailability[];
export declare const slideTemplateAvailabilityByDisplayMode: {
square: SlideTemplateAvailability[];
fullscreen: SlideTemplateAvailability[];
};
export declare const slideTemplateDrafts: Record<SlideTemplateKey, SlideTemplateDraft>;
export declare function getSlideTemplateDefinition(componentKey: SlideTemplateKey): SlideTemplateDefinition;
export declare function getSlideTemplateAvailability(displayMode?: "square" | "fullscreen"): SlideTemplateAvailability[];
export declare function getSlideTemplateDraft(componentKey: SlideTemplateKey): SlideTemplateDraft;
+546
View File
@@ -0,0 +1,546 @@
var squareYellowDefaults = {
header: "",
imageSrc: "",
imageAlt: ""
};
var squareVideoDefaults = {
header: "",
videoSrc: "",
posterSrc: ""
};
var fullscreenSplitDefaults = {
eyebrow: "",
title: "",
body: "",
imageSrc: "",
imageAlt: "",
imagePosition: "left"
};
var fullscreenVideoDefaults = {
header: "",
videoSrc: "",
posterSrc: "",
caption: ""
};
var fullscreenVideoTitleDefaults = {
title: "No need to be discrete",
videoSrc: "",
posterSrc: ""
};
var fullscreenVideoCenterCaptionDefaults = {
caption: "",
videoSrc: "",
posterSrc: ""
};
var equationFocusDefaults = {
header: "",
eyebrow: "",
title: "",
annotation: ""
};
var quoteImageDefaults = {
eyebrow: "",
quote: "",
attribution: "",
imageSrc: "",
imageAlt: "",
imagePosition: "left"
};
var chartSingleDefaults = {
header: "",
eyebrow: "",
title: "",
body: "",
points: []
};
var processFlowDefaults = {
eyebrow: "",
title: "",
steps: []
};
var definitionCardDefaults = {
header: "",
eyebrow: "",
term: "",
definition: "",
example: ""
};
var glitchComponentFrameDefaults = {
header: "",
componentId: "",
componentUrl: "",
caption: ""
};
export var slideTemplateDefinitions = {
SquareYellow: {
componentKey: "SquareYellow",
label: "Square image + header",
description: "Square image with a short external header.",
displayMode: "square",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short headline",
required: true
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
}
]
},
SquareVideo: {
componentKey: "SquareVideo",
label: "Square video + header",
description: "Square video inside a framed square slide with a short header.",
displayMode: "square",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short headline",
required: true
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
FullscreenSplit: {
componentKey: "FullscreenSplit",
label: "Fullscreen split",
description: "Two-panel fullscreen slide with image and text.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Main title",
required: true
},
{
name: "body",
type: "textarea",
label: "Body",
placeholder: "Short supporting text",
required: true
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
},
{
name: "imagePosition",
type: "text",
label: "Image position",
placeholder: "left or right"
}
]
},
FullscreenVideo: {
componentKey: "FullscreenVideo",
label: "Fullscreen video",
description: "Full-bleed video slide with optional overlay text.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
},
{
name: "caption",
type: "textarea",
label: "Caption",
placeholder: "Short framing note"
}
]
},
FullscreenVideoTitle: {
componentKey: "FullscreenVideoTitle",
label: "Fullscreen video + title",
description: "Full-bleed video with one oversized overlaid title.",
displayMode: "fullscreen",
fields: [
{
name: "title",
type: "text",
label: "Title",
placeholder: "No need to be discrete"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
FullscreenVideoCenterCaption: {
componentKey: "FullscreenVideoCenterCaption",
label: "Fullscreen video + centered caption",
description: "Full-bleed video with one oversized centered caption.",
displayMode: "fullscreen",
fields: [
{
name: "caption",
type: "text",
label: "Caption",
placeholder: "Short centered statement"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
EquationFocus: {
componentKey: "EquationFocus",
label: "Equation focus",
description: "One display equation with a short annotation.",
displayMode: "fullscreen",
supportedDisplayModes: ["square", "fullscreen"],
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "What does the equation show?",
required: true
},
{
name: "latexString",
type: "latex",
label: "LaTeX equation",
placeholder: "\\bar{x} = \\frac{1}{N}\\sum_{i=0}^{N} x_i",
required: true
},
{
name: "annotation",
type: "textarea",
label: "Annotation",
placeholder: "One short explanation"
}
]
},
QuoteImage: {
componentKey: "QuoteImage",
label: "Quote + image",
description: "Strong quote paired with one image.",
displayMode: "fullscreen",
fields: [
{
name: "eyebrow",
type: "text",
label: "Eyebrow",
placeholder: "Optional eyebrow"
},
{
name: "quote",
type: "textarea",
label: "Quote",
placeholder: "Short quote",
required: true
},
{
name: "attribution",
type: "text",
label: "Attribution",
placeholder: "Person or source"
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
},
{
name: "imagePosition",
type: "text",
label: "Image position",
placeholder: "left or right"
}
]
},
ChartSingle: {
componentKey: "ChartSingle",
label: "Single chart",
description: "One compact chart with a short framing line.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Chart title",
required: true
},
{
name: "body",
type: "textarea",
label: "Body",
placeholder: "Short interpretation"
},
{
name: "points",
type: "lines",
label: "Data points",
placeholder: "Label: value",
description: "One point per line. Format each line as label: value."
}
]
},
ProcessFlow: {
componentKey: "ProcessFlow",
label: "Process flow",
description: "Short pipeline with 3 to 5 steps.",
displayMode: "fullscreen",
fields: [
{
name: "eyebrow",
type: "text",
label: "Eyebrow",
placeholder: "Optional eyebrow"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Process title",
required: true
},
{
name: "steps",
type: "lines",
label: "Steps",
placeholder: "One step per line",
required: true
}
]
},
DefinitionCard: {
componentKey: "DefinitionCard",
label: "Definition card",
description: "Term, definition, and optional example.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "term",
type: "text",
label: "Term",
placeholder: "Key term",
required: true
},
{
name: "definition",
type: "textarea",
label: "Definition",
placeholder: "Short definition",
required: true
},
{
name: "example",
type: "textarea",
label: "Example",
placeholder: "Optional example"
}
]
},
GlitchComponentFrame: {
componentKey: "GlitchComponentFrame",
label: "Interactive Glitch component",
description: "Hosted Glitch component embedded inside the slide surface.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "componentId",
type: "text",
label: "Component id",
placeholder: "lightlane",
required: true
},
{
name: "componentUrl",
type: "text",
label: "Component URL",
placeholder: "Optional hosted URL",
description: "Optional URL for iframe-hosted components. Leave empty for known local component ids."
},
{
name: "caption",
type: "textarea",
label: "Caption",
placeholder: "Short framing note"
}
]
}
};
export var slideTemplateDefinitionList = Object.values(slideTemplateDefinitions);
export var slideTemplateAvailabilityList = slideTemplateDefinitionList.flatMap(function (definition) {
var _a;
var supportedDisplayModes = (_a = definition.supportedDisplayModes) !== null && _a !== void 0 ? _a : [definition.displayMode];
return supportedDisplayModes.map(function (displayMode) { return ({
componentKey: definition.componentKey,
label: definition.label,
description: definition.description,
displayMode: displayMode,
fields: definition.fields
}); });
});
export var slideTemplateAvailabilityByDisplayMode = {
square: slideTemplateAvailabilityList.filter(function (definition) { return definition.displayMode === "square"; }),
fullscreen: slideTemplateAvailabilityList.filter(function (definition) { return definition.displayMode === "fullscreen"; })
};
export var slideTemplateDrafts = {
SquareYellow: {
props: squareYellowDefaults
},
SquareVideo: {
props: squareVideoDefaults
},
FullscreenSplit: {
props: fullscreenSplitDefaults
},
FullscreenVideo: {
props: fullscreenVideoDefaults
},
FullscreenVideoTitle: {
props: fullscreenVideoTitleDefaults
},
FullscreenVideoCenterCaption: {
props: fullscreenVideoCenterCaptionDefaults
},
EquationFocus: {
props: equationFocusDefaults,
latexString: ""
},
QuoteImage: {
props: quoteImageDefaults
},
ChartSingle: {
props: chartSingleDefaults
},
ProcessFlow: {
props: processFlowDefaults
},
DefinitionCard: {
props: definitionCardDefaults
},
GlitchComponentFrame: {
props: glitchComponentFrameDefaults
}
};
export function getSlideTemplateDefinition(componentKey) {
return slideTemplateDefinitions[componentKey];
}
export function getSlideTemplateAvailability(displayMode) {
if (!displayMode) {
return slideTemplateAvailabilityList;
}
return slideTemplateAvailabilityByDisplayMode[displayMode];
}
export function getSlideTemplateDraft(componentKey) {
return slideTemplateDrafts[componentKey];
}
+633
View File
@@ -0,0 +1,633 @@
import type {
ChartSingleData,
DefinitionCardData,
EquationFocusData,
FullscreenVideoData,
FullscreenVideoCenterCaptionData,
FullscreenVideoTitleData,
FullscreenSplitData,
GlitchComponentFrameData,
ProcessFlowData,
QuoteImageData,
SlideTemplateKey,
SlideTemplateProps,
SquareVideoData,
SquareYellowData
} from "./templates";
export type SlideTemplateFieldType =
| "text"
| "textarea"
| "lines"
| "image"
| "video"
| "latex";
export interface SlideTemplateFieldDefinition {
name: string;
type: SlideTemplateFieldType;
label: string;
placeholder?: string;
description?: string;
required?: boolean;
}
export interface SlideTemplateDefinition {
componentKey: SlideTemplateKey;
label: string;
description: string;
displayMode: "square" | "fullscreen";
supportedDisplayModes?: Array<"square" | "fullscreen">;
fields: SlideTemplateFieldDefinition[];
}
export interface SlideTemplateAvailability {
componentKey: SlideTemplateKey;
label: string;
description: string;
displayMode: "square" | "fullscreen";
fields: SlideTemplateFieldDefinition[];
}
export interface SlideTemplateDraft {
props: SlideTemplateProps;
latexString?: string;
}
const squareYellowDefaults: SquareYellowData = {
header: "",
imageSrc: "",
imageAlt: ""
};
const squareVideoDefaults: SquareVideoData = {
header: "",
videoSrc: "",
posterSrc: ""
};
const fullscreenSplitDefaults: FullscreenSplitData = {
eyebrow: "",
title: "",
body: "",
imageSrc: "",
imageAlt: "",
imagePosition: "left"
};
const fullscreenVideoDefaults: FullscreenVideoData = {
header: "",
videoSrc: "",
posterSrc: "",
caption: ""
};
const fullscreenVideoTitleDefaults: FullscreenVideoTitleData = {
title: "No need to be discrete",
videoSrc: "",
posterSrc: ""
};
const fullscreenVideoCenterCaptionDefaults: FullscreenVideoCenterCaptionData = {
caption: "",
videoSrc: "",
posterSrc: ""
};
const equationFocusDefaults: EquationFocusData = {
header: "",
eyebrow: "",
title: "",
annotation: ""
};
const quoteImageDefaults: QuoteImageData = {
eyebrow: "",
quote: "",
attribution: "",
imageSrc: "",
imageAlt: "",
imagePosition: "left"
};
const chartSingleDefaults: ChartSingleData = {
header: "",
eyebrow: "",
title: "",
body: "",
points: []
};
const processFlowDefaults: ProcessFlowData = {
eyebrow: "",
title: "",
steps: []
};
const definitionCardDefaults: DefinitionCardData = {
header: "",
eyebrow: "",
term: "",
definition: "",
example: ""
};
const glitchComponentFrameDefaults: GlitchComponentFrameData = {
header: "",
componentId: "",
componentUrl: "",
caption: ""
};
export const slideTemplateDefinitions: Record<
SlideTemplateKey,
SlideTemplateDefinition
> = {
SquareYellow: {
componentKey: "SquareYellow",
label: "Square image + header",
description: "Square image with a short external header.",
displayMode: "square",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short headline",
required: true
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
}
]
},
SquareVideo: {
componentKey: "SquareVideo",
label: "Square video + header",
description: "Square video inside a framed square slide with a short header.",
displayMode: "square",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short headline",
required: true
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
FullscreenSplit: {
componentKey: "FullscreenSplit",
label: "Fullscreen split",
description: "Two-panel fullscreen slide with image and text.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Main title",
required: true
},
{
name: "body",
type: "textarea",
label: "Body",
placeholder: "Short supporting text",
required: true
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
},
{
name: "imagePosition",
type: "text",
label: "Image position",
placeholder: "left or right"
}
]
},
FullscreenVideo: {
componentKey: "FullscreenVideo",
label: "Fullscreen video",
description: "Full-bleed video slide with optional overlay text.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
},
{
name: "caption",
type: "textarea",
label: "Caption",
placeholder: "Short framing note"
}
]
},
FullscreenVideoTitle: {
componentKey: "FullscreenVideoTitle",
label: "Fullscreen video + title",
description: "Full-bleed video with one oversized overlaid title.",
displayMode: "fullscreen",
fields: [
{
name: "title",
type: "text",
label: "Title",
placeholder: "No need to be discrete"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
FullscreenVideoCenterCaption: {
componentKey: "FullscreenVideoCenterCaption",
label: "Fullscreen video + centered caption",
description: "Full-bleed video with one oversized centered caption.",
displayMode: "fullscreen",
fields: [
{
name: "caption",
type: "text",
label: "Caption",
placeholder: "Short centered statement"
},
{
name: "videoSrc",
type: "video",
label: "Video",
placeholder: "https://...",
required: true
},
{
name: "posterSrc",
type: "image",
label: "Poster image",
placeholder: "https://..."
}
]
},
EquationFocus: {
componentKey: "EquationFocus",
label: "Equation focus",
description: "One display equation with a short annotation.",
displayMode: "fullscreen",
supportedDisplayModes: ["square", "fullscreen"],
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "What does the equation show?",
required: true
},
{
name: "latexString",
type: "latex",
label: "LaTeX equation",
placeholder: "\\bar{x} = \\frac{1}{N}\\sum_{i=0}^{N} x_i",
required: true
},
{
name: "annotation",
type: "textarea",
label: "Annotation",
placeholder: "One short explanation"
}
]
},
QuoteImage: {
componentKey: "QuoteImage",
label: "Quote + image",
description: "Strong quote paired with one image.",
displayMode: "fullscreen",
fields: [
{
name: "eyebrow",
type: "text",
label: "Eyebrow",
placeholder: "Optional eyebrow"
},
{
name: "quote",
type: "textarea",
label: "Quote",
placeholder: "Short quote",
required: true
},
{
name: "attribution",
type: "text",
label: "Attribution",
placeholder: "Person or source"
},
{
name: "imageSrc",
type: "image",
label: "Image",
placeholder: "https://...",
required: true
},
{
name: "imageAlt",
type: "text",
label: "Alt text",
placeholder: "Describe the image",
required: true
},
{
name: "imagePosition",
type: "text",
label: "Image position",
placeholder: "left or right"
}
]
},
ChartSingle: {
componentKey: "ChartSingle",
label: "Single chart",
description: "One compact chart with a short framing line.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Chart title",
required: true
},
{
name: "body",
type: "textarea",
label: "Body",
placeholder: "Short interpretation"
},
{
name: "points",
type: "lines",
label: "Data points",
placeholder: "Label: value",
description: "One point per line. Format each line as label: value."
}
]
},
ProcessFlow: {
componentKey: "ProcessFlow",
label: "Process flow",
description: "Short pipeline with 3 to 5 steps.",
displayMode: "fullscreen",
fields: [
{
name: "eyebrow",
type: "text",
label: "Eyebrow",
placeholder: "Optional eyebrow"
},
{
name: "title",
type: "text",
label: "Title",
placeholder: "Process title",
required: true
},
{
name: "steps",
type: "lines",
label: "Steps",
placeholder: "One step per line",
required: true
}
]
},
DefinitionCard: {
componentKey: "DefinitionCard",
label: "Definition card",
description: "Term, definition, and optional example.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "term",
type: "text",
label: "Term",
placeholder: "Key term",
required: true
},
{
name: "definition",
type: "textarea",
label: "Definition",
placeholder: "Short definition",
required: true
},
{
name: "example",
type: "textarea",
label: "Example",
placeholder: "Optional example"
}
]
},
GlitchComponentFrame: {
componentKey: "GlitchComponentFrame",
label: "Interactive Glitch component",
description: "Hosted Glitch component embedded inside the slide surface.",
displayMode: "fullscreen",
fields: [
{
name: "header",
type: "text",
label: "Header",
placeholder: "Short header"
},
{
name: "componentId",
type: "text",
label: "Component id",
placeholder: "lightlane",
required: true
},
{
name: "componentUrl",
type: "text",
label: "Component URL",
placeholder: "Optional hosted URL",
description: "Optional URL for iframe-hosted components. Leave empty for known local component ids."
},
{
name: "caption",
type: "textarea",
label: "Caption",
placeholder: "Short framing note"
}
]
}
};
export const slideTemplateDefinitionList = Object.values(
slideTemplateDefinitions
);
export const slideTemplateAvailabilityList: SlideTemplateAvailability[] =
slideTemplateDefinitionList.flatMap((definition) => {
const supportedDisplayModes =
definition.supportedDisplayModes ?? [definition.displayMode];
return supportedDisplayModes.map((displayMode) => ({
componentKey: definition.componentKey,
label: definition.label,
description: definition.description,
displayMode,
fields: definition.fields
}));
});
export const slideTemplateAvailabilityByDisplayMode = {
square: slideTemplateAvailabilityList.filter(
(definition) => definition.displayMode === "square"
),
fullscreen: slideTemplateAvailabilityList.filter(
(definition) => definition.displayMode === "fullscreen"
)
} satisfies Record<"square" | "fullscreen", SlideTemplateAvailability[]>;
export const slideTemplateDrafts: Record<SlideTemplateKey, SlideTemplateDraft> = {
SquareYellow: {
props: squareYellowDefaults
},
SquareVideo: {
props: squareVideoDefaults
},
FullscreenSplit: {
props: fullscreenSplitDefaults
},
FullscreenVideo: {
props: fullscreenVideoDefaults
},
FullscreenVideoTitle: {
props: fullscreenVideoTitleDefaults
},
FullscreenVideoCenterCaption: {
props: fullscreenVideoCenterCaptionDefaults
},
EquationFocus: {
props: equationFocusDefaults,
latexString: ""
},
QuoteImage: {
props: quoteImageDefaults
},
ChartSingle: {
props: chartSingleDefaults
},
ProcessFlow: {
props: processFlowDefaults
},
DefinitionCard: {
props: definitionCardDefaults
},
GlitchComponentFrame: {
props: glitchComponentFrameDefaults
}
};
export function getSlideTemplateDefinition(componentKey: SlideTemplateKey) {
return slideTemplateDefinitions[componentKey];
}
export function getSlideTemplateAvailability(displayMode?: "square" | "fullscreen") {
if (!displayMode) {
return slideTemplateAvailabilityList;
}
return slideTemplateAvailabilityByDisplayMode[displayMode];
}
export function getSlideTemplateDraft(componentKey: SlideTemplateKey) {
return slideTemplateDrafts[componentKey];
}
+144
View File
@@ -0,0 +1,144 @@
export declare const slideTemplateKeys: readonly ["SquareYellow", "SquareVideo", "FullscreenSplit", "FullscreenVideo", "FullscreenVideoTitle", "FullscreenVideoCenterCaption", "EquationFocus", "QuoteImage", "ChartSingle", "ProcessFlow", "DefinitionCard", "GlitchComponentFrame"];
export type SlideTemplateKey = (typeof slideTemplateKeys)[number];
export type SlideTemplateVersion = 1;
export interface SquareYellowData {
header: string;
imageSrc: string;
imageAlt: string;
}
export interface SquareVideoData {
header: string;
videoSrc: string;
posterSrc?: string;
}
export interface FullscreenSplitData {
eyebrow?: string;
title: string;
body: string;
imageSrc: string;
imageAlt: string;
imagePosition?: "left" | "right";
}
export interface FullscreenVideoData {
header?: string;
videoSrc: string;
posterSrc?: string;
caption?: string;
}
export interface FullscreenVideoTitleData {
title?: string;
videoSrc: string;
posterSrc?: string;
}
export interface FullscreenVideoCenterCaptionData {
caption?: string;
videoSrc: string;
posterSrc?: string;
}
export interface EquationFocusData {
header?: string;
eyebrow?: string;
title: string;
annotation?: string;
}
export interface QuoteImageData {
eyebrow?: string;
quote: string;
attribution?: string;
imageSrc: string;
imageAlt: string;
imagePosition?: "left" | "right";
}
export interface ChartSinglePoint {
label: string;
value: number;
color?: string;
}
export interface ChartSingleData {
header?: string;
eyebrow?: string;
title: string;
body?: string;
points: ChartSinglePoint[];
}
export interface ProcessFlowData {
eyebrow?: string;
title: string;
steps: string[];
}
export interface DefinitionCardData {
header?: string;
eyebrow?: string;
term: string;
definition: string;
example?: string;
}
export interface GlitchComponentFrameData {
header?: string;
componentId: string;
componentUrl?: string;
caption?: string;
}
export interface SquareYellowContract {
componentKey: "SquareYellow";
version: 1;
props: SquareYellowData;
}
export interface SquareVideoContract {
componentKey: "SquareVideo";
version: 1;
props: SquareVideoData;
}
export interface FullscreenSplitContract {
componentKey: "FullscreenSplit";
version: 1;
props: FullscreenSplitData;
}
export interface FullscreenVideoContract {
componentKey: "FullscreenVideo";
version: 1;
props: FullscreenVideoData;
}
export interface FullscreenVideoTitleContract {
componentKey: "FullscreenVideoTitle";
version: 1;
props: FullscreenVideoTitleData;
}
export interface FullscreenVideoCenterCaptionContract {
componentKey: "FullscreenVideoCenterCaption";
version: 1;
props: FullscreenVideoCenterCaptionData;
}
export interface EquationFocusContract {
componentKey: "EquationFocus";
version: 1;
props: EquationFocusData;
latexString: string;
}
export interface QuoteImageContract {
componentKey: "QuoteImage";
version: 1;
props: QuoteImageData;
}
export interface ChartSingleContract {
componentKey: "ChartSingle";
version: 1;
props: ChartSingleData;
}
export interface ProcessFlowContract {
componentKey: "ProcessFlow";
version: 1;
props: ProcessFlowData;
}
export interface DefinitionCardContract {
componentKey: "DefinitionCard";
version: 1;
props: DefinitionCardData;
}
export interface GlitchComponentFrameContract {
componentKey: "GlitchComponentFrame";
version: 1;
props: GlitchComponentFrameData;
}
export type SupportedSlideContract = SquareYellowContract | SquareVideoContract | FullscreenSplitContract | FullscreenVideoContract | FullscreenVideoTitleContract | FullscreenVideoCenterCaptionContract | EquationFocusContract | QuoteImageContract | ChartSingleContract | ProcessFlowContract | DefinitionCardContract | GlitchComponentFrameContract;
export type SlideTemplateProps = SupportedSlideContract["props"];
+14
View File
@@ -0,0 +1,14 @@
export var slideTemplateKeys = [
"SquareYellow",
"SquareVideo",
"FullscreenSplit",
"FullscreenVideo",
"FullscreenVideoTitle",
"FullscreenVideoCenterCaption",
"EquationFocus",
"QuoteImage",
"ChartSingle",
"ProcessFlow",
"DefinitionCard",
"GlitchComponentFrame"
];
+197
View File
@@ -0,0 +1,197 @@
export const slideTemplateKeys = [
"SquareYellow",
"SquareVideo",
"FullscreenSplit",
"FullscreenVideo",
"FullscreenVideoTitle",
"FullscreenVideoCenterCaption",
"EquationFocus",
"QuoteImage",
"ChartSingle",
"ProcessFlow",
"DefinitionCard",
"GlitchComponentFrame"
] as const;
export type SlideTemplateKey = (typeof slideTemplateKeys)[number];
export type SlideTemplateVersion = 1;
export interface SquareYellowData {
header: string;
imageSrc: string;
imageAlt: string;
}
export interface SquareVideoData {
header: string;
videoSrc: string;
posterSrc?: string;
}
export interface FullscreenSplitData {
eyebrow?: string;
title: string;
body: string;
imageSrc: string;
imageAlt: string;
imagePosition?: "left" | "right";
}
export interface FullscreenVideoData {
header?: string;
videoSrc: string;
posterSrc?: string;
caption?: string;
}
export interface FullscreenVideoTitleData {
title?: string;
videoSrc: string;
posterSrc?: string;
}
export interface FullscreenVideoCenterCaptionData {
caption?: string;
videoSrc: string;
posterSrc?: string;
}
export interface EquationFocusData {
header?: string;
eyebrow?: string;
title: string;
annotation?: string;
}
export interface QuoteImageData {
eyebrow?: string;
quote: string;
attribution?: string;
imageSrc: string;
imageAlt: string;
imagePosition?: "left" | "right";
}
export interface ChartSinglePoint {
label: string;
value: number;
color?: string;
}
export interface ChartSingleData {
header?: string;
eyebrow?: string;
title: string;
body?: string;
points: ChartSinglePoint[];
}
export interface ProcessFlowData {
eyebrow?: string;
title: string;
steps: string[];
}
export interface DefinitionCardData {
header?: string;
eyebrow?: string;
term: string;
definition: string;
example?: string;
}
export interface GlitchComponentFrameData {
header?: string;
componentId: string;
componentUrl?: string;
caption?: string;
}
export interface SquareYellowContract {
componentKey: "SquareYellow";
version: 1;
props: SquareYellowData;
}
export interface SquareVideoContract {
componentKey: "SquareVideo";
version: 1;
props: SquareVideoData;
}
export interface FullscreenSplitContract {
componentKey: "FullscreenSplit";
version: 1;
props: FullscreenSplitData;
}
export interface FullscreenVideoContract {
componentKey: "FullscreenVideo";
version: 1;
props: FullscreenVideoData;
}
export interface FullscreenVideoTitleContract {
componentKey: "FullscreenVideoTitle";
version: 1;
props: FullscreenVideoTitleData;
}
export interface FullscreenVideoCenterCaptionContract {
componentKey: "FullscreenVideoCenterCaption";
version: 1;
props: FullscreenVideoCenterCaptionData;
}
export interface EquationFocusContract {
componentKey: "EquationFocus";
version: 1;
props: EquationFocusData;
latexString: string;
}
export interface QuoteImageContract {
componentKey: "QuoteImage";
version: 1;
props: QuoteImageData;
}
export interface ChartSingleContract {
componentKey: "ChartSingle";
version: 1;
props: ChartSingleData;
}
export interface ProcessFlowContract {
componentKey: "ProcessFlow";
version: 1;
props: ProcessFlowData;
}
export interface DefinitionCardContract {
componentKey: "DefinitionCard";
version: 1;
props: DefinitionCardData;
}
export interface GlitchComponentFrameContract {
componentKey: "GlitchComponentFrame";
version: 1;
props: GlitchComponentFrameData;
}
export type SupportedSlideContract =
| SquareYellowContract
| SquareVideoContract
| FullscreenSplitContract
| FullscreenVideoContract
| FullscreenVideoTitleContract
| FullscreenVideoCenterCaptionContract
| EquationFocusContract
| QuoteImageContract
| ChartSingleContract
| ProcessFlowContract
| DefinitionCardContract
| GlitchComponentFrameContract;
export type SlideTemplateProps = SupportedSlideContract["props"];