segment.trim())
+ .filter(Boolean);
+
+ return importSegments.length > 1 ? importSegments : [line];
+}
+
+function expandInlinePythonStatement(line: string) {
+ const inlineReturnMatch = line.match(/^(\s*def\s+[^(]+\([^)]*\):)\s+return\s+(.+)$/);
+
+ if (!inlineReturnMatch) {
+ return [line];
+ }
+
+ return [inlineReturnMatch[1], `return ${inlineReturnMatch[2]}`];
+}
+
+function expandPathListAssignment(line: string) {
+ const trimmedLine = line.trim();
+
+ if (!trimmedLine.startsWith("urlpatterns = [") || !trimmedLine.endsWith("]")) {
+ return [line];
+ }
+
+ const pathCalls = trimmedLine.match(/path\([^)]*\)/g);
+
+ if (!pathCalls?.length) {
+ return [line];
+ }
+
+ return [
+ "urlpatterns = [",
+ ...pathCalls.map((pathCall) => ` ${pathCall},`),
+ "]",
+ ];
+}
+
+function normalizePythonCode(content: string) {
+ const normalizedLines: string[] = [];
+
+ for (const line of content.split("\n")) {
+ const importLines = splitCollapsedPythonImports(line);
+
+ for (const importLine of importLines) {
+ const expandedPathLines = expandPathListAssignment(importLine);
+
+ for (const expandedPathLine of expandedPathLines) {
+ normalizedLines.push(...expandInlinePythonStatement(expandedPathLine));
+ }
+ }
+ }
+
+ return normalizedLines.join("\n").replace(/\n{3,}/g, "\n\n");
+}
+
+function tryFormatJson(content: string) {
+ const trimmedContent = content.replace(/^\uFEFF/, "").trim();
+
+ if (!trimmedContent) {
+ return "";
+ }
+
+ const normalizedSeparatorsContent = trimmedContent
+ .replace(/^\s*\/\s*$/gm, ",")
+ .replace(/\r\n?/g, "\n")
+ .replace(/\n\s*:\s*/g, ": ")
+ .replace(/\n\s*,\s*/g, ", ");
+
+ const parseAndFormat = (raw: string) => {
+ try {
+ const parsed = JSON.parse(raw);
+
+ if (typeof parsed === "string") {
+ try {
+ return JSON.stringify(JSON.parse(parsed), null, 2);
+ } catch {
+ return JSON.stringify(parsed, null, 2);
+ }
+ }
+
+ return JSON.stringify(parsed, null, 2);
+ } catch {
+ return null;
+ }
+ };
+
+ const extractedJsonMatch = normalizedSeparatorsContent.match(/[\[{][\s\S]*[\]}]/);
+ const extractedJsonCandidate = extractedJsonMatch?.[0];
+
+ const candidates = [
+ normalizedSeparatorsContent,
+ trimmedContent,
+ extractedJsonCandidate,
+ ].filter((candidate): candidate is string => Boolean(candidate));
+
+ for (const candidate of candidates) {
+ const direct = parseAndFormat(candidate);
+ if (direct !== null) {
+ return direct;
+ }
+
+ try {
+ const repairedJson = jsonrepair(candidate);
+ const repaired = parseAndFormat(repairedJson);
+ if (repaired !== null) {
+ return repaired;
+ }
+ } catch {
+ // Try next parsing strategy.
+ }
+ }
+
+ const jsonLikeTokenMatch = normalizedSeparatorsContent.match(
+ /"(?:\\.|[^"\\])*"|true|false|null|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|[{}\[\]:,\/]/g
+ );
+
+ if (jsonLikeTokenMatch?.length) {
+ const normalizedTokens = jsonLikeTokenMatch.map((token) => (token === "/" ? "," : token));
+ let rebuilt = "";
+
+ for (const token of normalizedTokens) {
+ if (token === ":" || token === ",") {
+ rebuilt = rebuilt.replace(/\s*$/, "");
+ rebuilt += `${token} `;
+ continue;
+ }
+
+ if (token === "}" || token === "]") {
+ rebuilt = rebuilt.replace(/\s*$/, "");
+ rebuilt += token;
+ continue;
+ }
+
+ if (token === "{" || token === "[") {
+ rebuilt = rebuilt.replace(/\s*$/, "");
+ rebuilt += token;
+ continue;
+ }
+
+ rebuilt += token;
+ }
+
+ const rebuiltDirect = parseAndFormat(rebuilt);
+ if (rebuiltDirect !== null) {
+ return rebuiltDirect;
+ }
+
+ try {
+ const rebuiltRepaired = parseAndFormat(jsonrepair(rebuilt));
+ if (rebuiltRepaired !== null) {
+ return rebuiltRepaired;
+ }
+ } catch {
+ // Continue to best-effort line merge fallback below.
+ }
+ }
+
+ const normalizedLines = normalizedSeparatorsContent
+ .replace(/\n\s*:\s*\n\s*/g, ": ")
+ .replace(/\n\s*\/\s*\n/g, ",\n")
+ .split("\n")
+ .map((line) => line.replace(/\s+$/g, ""));
+
+ const mergedLines: string[] = [];
+
+ for (const rawLine of normalizedLines) {
+ const trimmedLine = rawLine.trim();
+
+ if (!trimmedLine) {
+ continue;
+ }
+
+ if (trimmedLine === ":") {
+ if (mergedLines.length > 0) {
+ mergedLines[mergedLines.length - 1] = `${mergedLines[mergedLines.length - 1]}:`;
+ }
+ continue;
+ }
+
+ if (trimmedLine === "/") {
+ if (mergedLines.length > 0 && !mergedLines[mergedLines.length - 1].trim().endsWith(",")) {
+ mergedLines[mergedLines.length - 1] = `${mergedLines[mergedLines.length - 1]},`;
+ }
+ continue;
+ }
+
+ const previousLine = mergedLines[mergedLines.length - 1]?.trim() || "";
+ if (previousLine.endsWith(":")) {
+ mergedLines[mergedLines.length - 1] = `${mergedLines[mergedLines.length - 1]} ${trimmedLine}`;
+ continue;
+ }
+
+ mergedLines.push(rawLine);
+ }
+
+ for (let index = 0; index < mergedLines.length - 1; index += 1) {
+ const currentLine = mergedLines[index].trim();
+ const nextLine = mergedLines[index + 1].trim();
+ const currentEndsWithComma = currentLine.endsWith(",");
+ const currentIsContainerStart = currentLine.endsWith("{") || currentLine.endsWith("[");
+ const nextStartsNewKey = nextLine.startsWith("\"");
+ const nextIsContainerEnd = nextLine.startsWith("}") || nextLine.startsWith("]");
+
+ if (!currentEndsWithComma && !currentIsContainerStart && nextStartsNewKey && !nextIsContainerEnd) {
+ mergedLines[index] = `${mergedLines[index]},`;
+ }
+ }
+
+ return mergedLines
+ .join("\n")
+ .replace(/,\s*([}\]])/g, "$1");
+}
+
+function isValidJsonContent(content: string) {
+ try {
+ JSON.parse(content.trim());
+ return true;
+ } catch {
+ return false;
+ }
+}
+
+function seemsJsonLike(content: string) {
+ const trimmed = content.trim();
+ if (!trimmed) {
+ return false;
+ }
+
+ if (/^[\[{]/.test(trimmed)) {
+ return true;
+ }
+
+ return /"[^"\n]+"\s*:/.test(trimmed) || /[\[{][\s\S]*[\]}]/.test(trimmed);
+}
+
+function unwrapMarkdownCodeFence(content: string) {
+ const trimmedContent = content.trim();
+ const fencedCodeMatch = trimmedContent.match(/^```([^\n`]*)\n([\s\S]*?)\n```$/);
+
+ if (!fencedCodeMatch) {
+ return {
+ content: content,
+ fenceLanguage: undefined as string | undefined,
+ };
+ }
+
+ return {
+ content: fencedCodeMatch[2],
+ fenceLanguage: fencedCodeMatch[1]?.trim().toLowerCase() || undefined,
+ };
+}
+
+function escapeHtml(content: string) {
+ return content
+ .replace(/&/g, "&")
+ .replace(//g, ">");
+}
+
+function resolvePrismLanguage(language?: string) {
+ const normalizedLanguage = language?.toLowerCase().trim();
+
+ if (!normalizedLanguage) {
+ return "clike";
+ }
+
+ if (normalizedLanguage.includes("json")) {
+ return "json";
+ }
+
+ if (normalizedLanguage.includes("python")) {
+ return "python";
+ }
+
+ if (normalizedLanguage === "ts") {
+ return "typescript";
+ }
+
+ if (normalizedLanguage === "js") {
+ return "javascript";
+ }
+
+ if (normalizedLanguage === "py") {
+ return "python";
+ }
+
+ if (normalizedLanguage === "sh" || normalizedLanguage === "shell") {
+ return "bash";
+ }
+
+ if (normalizedLanguage === "yml") {
+ return "yaml";
+ }
+
+ if (Prism.languages[normalizedLanguage]) {
+ return normalizedLanguage;
+ }
+
+ return "clike";
+}
+
+function highlightCode(content: string, language?: string) {
+ const prismLanguage = resolvePrismLanguage(language);
+ const grammar = Prism.languages[prismLanguage];
+
+ if (!grammar) {
+ return {
+ html: escapeHtml(content),
+ prismLanguage,
+ };
+ }
+
+ try {
+ return {
+ html: Prism.highlight(content, grammar, prismLanguage),
+ prismLanguage,
+ };
+ } catch {
+ return {
+ html: escapeHtml(content),
+ prismLanguage,
+ };
+ }
+}
+
+export function normalizeCodeContent(language?: string, content?: string) {
+ let normalizedContent = (content || "")
+ .replace(/\r\n?/g, "\n")
+ .replace(/\\\[/g, "[")
+ .replace(/\\\]/g, "]");
+ const unwrappedContent = unwrapMarkdownCodeFence(normalizedContent);
+ normalizedContent = unwrappedContent.content.trimEnd();
+
+ const normalizedLanguage = language?.toLowerCase()?.trim() || unwrappedContent.fenceLanguage;
+ const isJsonLanguage = normalizedLanguage?.includes("json");
+ const looksLikeJsonPayload = seemsJsonLike(normalizedContent);
+
+ if (normalizedLanguage === "python") {
+ normalizedContent = normalizePythonCode(normalizedContent);
+ } else if (isJsonLanguage || looksLikeJsonPayload) {
+ const formattedJson = tryFormatJson(normalizedContent);
+ normalizedContent = formattedJson;
+ }
+
+ return normalizedContent;
+}
+
+function countRenderedLines(content: string, maxCharsPerLine: number) {
+ const rawLines = content.split("\n");
+ let renderedLineCount = 0;
+
+ for (const rawLine of rawLines) {
+ const expandedLine = rawLine.replace(/\t/g, " ");
+
+ if (expandedLine.length === 0) {
+ renderedLineCount += 1;
+ continue;
+ }
+
+ renderedLineCount += Math.max(1, Math.ceil(expandedLine.length / maxCharsPerLine));
+ }
+
+ return Math.max(1, renderedLineCount);
+}
+
+function splitLineForLineBudget(line: string, maxCharsPerLine: number) {
+ if (line.length === 0) {
+ return [""];
+ }
+
+ const chunks: string[] = [];
+
+ for (let start = 0; start < line.length; start += maxCharsPerLine) {
+ chunks.push(line.slice(start, start + maxCharsPerLine));
+ }
+
+ return chunks;
+}
+
+function truncateContentToLineBudget(
+ content: string,
+ lineBudget: number,
+ maxCharsPerLine: number
+) {
+ const linesForDisplay: string[] = [];
+ const rawLines = content.split("\n");
+
+ for (const rawLine of rawLines) {
+ const expandedLine = rawLine.replace(/\t/g, " ");
+ const chunks = splitLineForLineBudget(expandedLine, maxCharsPerLine);
+
+ for (const chunk of chunks) {
+ if (linesForDisplay.length >= lineBudget) {
+ const lastLineIndex = Math.max(0, lineBudget - 1);
+ const ellipsis = "...";
+ const existingLastLine = linesForDisplay[lastLineIndex] ?? "";
+ linesForDisplay[lastLineIndex] = `${existingLastLine.slice(
+ 0,
+ Math.max(0, maxCharsPerLine - ellipsis.length)
+ )}${ellipsis}`;
+ return linesForDisplay.join("\n");
+ }
+
+ linesForDisplay.push(chunk);
+ }
+ }
+
+ return linesForDisplay.join("\n");
+}
+
+function createTypographyCandidate(
+ normalizedContent: string,
+ fontSize: number,
+ maxWidth: number,
+ charWidthRatio: number,
+ lineHeightRatio: number
+): TypographyCandidate {
+ const lineHeight = Math.max(1, Math.round(fontSize * lineHeightRatio));
+ const maxCharsPerLine = Math.max(1, Math.floor(maxWidth / (fontSize * charWidthRatio)));
+ const renderedLineCount = countRenderedLines(normalizedContent, maxCharsPerLine);
+
+ return {
+ lineHeight,
+ maxCharsPerLine,
+ renderedLineCount,
+ };
+}
+
+function findFittingTypography(
+ normalizedContent: string,
+ startFontSize: number,
+ minFontSize: number,
+ maxWidth: number,
+ maxHeight: number,
+ fontStep: number,
+ charWidthRatio: number,
+ lineHeightRatio: number
+) {
+ for (let fontSize = startFontSize; fontSize >= minFontSize; fontSize -= fontStep) {
+ const candidate = createTypographyCandidate(
+ normalizedContent,
+ fontSize,
+ maxWidth,
+ charWidthRatio,
+ lineHeightRatio
+ );
+
+ if (candidate.renderedLineCount * candidate.lineHeight <= maxHeight) {
+ return {
+ candidate,
+ fontSize,
+ };
+ }
+ }
+
+ return null;
+}
+
+export function fitCodeBlock({
+ language,
+ content,
+ maxWidth,
+ maxHeight,
+ maxFontSize = 16,
+ minFontSize = 8,
+ fontStep = DEFAULT_FONT_STEP,
+ charWidthRatio = DEFAULT_CODE_CHAR_WIDTH_RATIO,
+ lineHeightRatio = DEFAULT_CODE_LINE_HEIGHT_RATIO,
+}: FitCodeBlockOptions): FittedCodeBlock {
+ const normalizedContent = normalizeCodeContent(language, content);
+ const highlightLanguage =
+ isValidJsonContent(normalizedContent) || seemsJsonLike(normalizedContent)
+ ? "json"
+ : language;
+ const preferredMinFont = Math.max(1, minFontSize);
+ const hardMinFont = Math.max(1, Math.min(preferredMinFont, HARD_MIN_FONT_SIZE));
+ const startFont = Math.max(maxFontSize, preferredMinFont);
+
+ const preferredFit = findFittingTypography(
+ normalizedContent,
+ startFont,
+ preferredMinFont,
+ maxWidth,
+ maxHeight,
+ fontStep,
+ charWidthRatio,
+ lineHeightRatio
+ );
+
+ if (preferredFit) {
+ const highlighted = highlightCode(normalizedContent, highlightLanguage);
+ return {
+ text: normalizedContent,
+ highlightedHtml: highlighted.html,
+ prismLanguage: highlighted.prismLanguage,
+ fontSize: Math.round(preferredFit.fontSize * 10) / 10,
+ lineHeight: preferredFit.candidate.lineHeight,
+ fontFamily: DEFAULT_CODE_FONT_FAMILY,
+ };
+ }
+
+ if (hardMinFont < preferredMinFont) {
+ const emergencyFit = findFittingTypography(
+ normalizedContent,
+ preferredMinFont - fontStep,
+ hardMinFont,
+ maxWidth,
+ maxHeight,
+ fontStep,
+ charWidthRatio,
+ lineHeightRatio
+ );
+
+ if (emergencyFit) {
+ const highlighted = highlightCode(normalizedContent, highlightLanguage);
+ return {
+ text: normalizedContent,
+ highlightedHtml: highlighted.html,
+ prismLanguage: highlighted.prismLanguage,
+ fontSize: Math.round(emergencyFit.fontSize * 10) / 10,
+ lineHeight: emergencyFit.candidate.lineHeight,
+ fontFamily: DEFAULT_CODE_FONT_FAMILY,
+ };
+ }
+ }
+
+ const fallback = createTypographyCandidate(
+ normalizedContent,
+ hardMinFont,
+ maxWidth,
+ charWidthRatio,
+ lineHeightRatio
+ );
+ const fallbackLineBudget = Math.max(1, Math.floor(maxHeight / fallback.lineHeight));
+ const fallbackText = truncateContentToLineBudget(
+ normalizedContent,
+ fallbackLineBudget,
+ fallback.maxCharsPerLine
+ );
+ const highlighted = highlightCode(fallbackText, highlightLanguage);
+ return {
+ text: fallbackText,
+ highlightedHtml: highlighted.html,
+ prismLanguage: highlighted.prismLanguage,
+ fontSize: Math.round(hardMinFont * 10) / 10,
+ lineHeight: fallback.lineHeight,
+ fontFamily: DEFAULT_CODE_FONT_FAMILY,
+ };
+}
diff --git a/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx
index 3a76a0e5..a686cf0a 100644
--- a/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/Education/EducationStatisticsGridSlide.tsx
@@ -9,7 +9,7 @@ const StatisticSchema = z.object({
value: z.string().max(8).meta({
description: "Main metric value shown at the top of one card.",
}),
- label: z.string().max(20).meta({
+ label: z.string().max(45).meta({
description: "Label shown under the value.",
}),
});
@@ -28,14 +28,14 @@ export const Schema = z.object({
.min(2)
.max(8)
.default([
- { value: "120", label: "Sales Team Strength" },
- { value: "15", label: "Senior Sales Officer" },
- { value: "1", label: "National Manager" },
- { value: "25", label: "Sales Officers" },
- { value: "2", label: "Regional Manager" },
- { value: "50", label: "Distributor Reps" },
- { value: "5", label: "Zonal Manager" },
- { value: "20", label: "Merchandising Team" },
+ { value: "120", label: "Sales Team Strength with a long label to test the layouts" },
+ { value: "15", label: "Senior Sales Officer with a long label to test the layout" },
+ { value: "1", label: "National Manager with a long label to test the layout" },
+ { value: "25", label: "Sales Officers with a long label to test the layout" },
+ { value: "2", label: "Regional Manager with a long label to test the layout" },
+ { value: "50", label: "Distributor Reps with a long label to test the layout" },
+ { value: "5", label: "Zonal Manager with a long label to test the layout" },
+ { value: "20", label: "Merchandising Team with a long label to the layout" },
])
.meta({
description: "statistic cards, with value and label each in a card",
@@ -93,29 +93,35 @@ const EducationStatisticsGridSlide = ({ data }: { data: Partial
}) =
{data.stats && data.stats?.length > 4 && data.stats?.length <= 8 && (() => {
- const rightArray = data.stats?.slice(0, Math.floor(data.stats?.length / 2));
- const leftArray = data.stats?.slice(Math.floor(data.stats?.length / 2));
+ // const rightArray = data.stats?.slice(0, Math.floor(data.stats?.length / 2));
+ // const leftArray = data.stats?.slice(Math.floor(data.stats?.length / 2));
return (
-
-
+
+ {/*
*/}
- {leftArray?.map((stat: any, index: number) => (
-
-
- {stat?.value}
-
-
- {stat?.label}
-
-
- ))}
-
-
+ {data.stats?.map((stat: any, index: number) => (
+
+
+ {stat?.value}
+
+
+ {stat?.label}
+
+
+ ))}
+
+ {/*
*/}
+
+ {/*
{rightArray?.map((stat: any, index: number) => (
}) =
))}
-
+
*/}
);
})()}
diff --git a/electron/servers/nextjs/app/presentation-templates/ProductOverview/ComparisonChartSlide.tsx b/electron/servers/nextjs/app/presentation-templates/ProductOverview/ComparisonChartSlide.tsx
index 5d1f5e59..818e6173 100644
--- a/electron/servers/nextjs/app/presentation-templates/ProductOverview/ComparisonChartSlide.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/ProductOverview/ComparisonChartSlide.tsx
@@ -32,7 +32,7 @@ const RowSchema = z.union([GeneralRowSchema, LegacyRowSchema]);
export const Schema = z.object({
- title: z.string().max(14).default("Comparison Chart").meta({
+ title: z.string().max(24).default("Comparison Chart Comparison").meta({
description: "Main heading shown above the table.",
}),
subtitle: z.string().max(80).default(
diff --git a/electron/servers/nextjs/app/presentation-templates/ProductOverview/CoverSlide.tsx b/electron/servers/nextjs/app/presentation-templates/ProductOverview/CoverSlide.tsx
index f1629236..bc69728f 100644
--- a/electron/servers/nextjs/app/presentation-templates/ProductOverview/CoverSlide.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/ProductOverview/CoverSlide.tsx
@@ -8,15 +8,7 @@ export const slideLayoutDescription =
"A cover slide with a compact logo in the top-left, a date/text/label in the top-right, a centered title, and a image anchored to the bottom with a soft fade into the background.";
export const Schema = z.object({
- image: z.object({
- __image_url__: z.string().default("https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/images/placeholder.jpg"),
- __image_prompt__: z.string().default("Image of the company"),
- }).optional().default({
- __image_url__:
- "https://presenton-public.s3.ap-southeast-1.amazonaws.com/static/images/placeholder.jpg",
- __image_prompt__: "Image of the company",
- }),
label: z.string().min(3).max(16).optional().default("MARCH 2026").meta({
description: "Date/text/label shown at the top-right corner.",
}),
@@ -56,11 +48,7 @@ const CoverSlide = ({ data }: { data: Partial
}) => {
>
- {data.image?.__image_url__ ?

:
}
+
}) => {
{title}
-
+
-
+
{items?.map((item, index) => (
diff --git a/electron/servers/nextjs/app/presentation-templates/Report/DataAnalysisDashboardSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Report/DataAnalysisDashboardSlide.tsx
index 92f1ac42..211ba519 100644
--- a/electron/servers/nextjs/app/presentation-templates/Report/DataAnalysisDashboardSlide.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/Report/DataAnalysisDashboardSlide.tsx
@@ -136,9 +136,9 @@ function SummaryCard({
return (
@@ -149,12 +149,7 @@ function SummaryCard({
color="var(--primary-text, #000000)"
title={iconAlt ?? ""}
/>
- {/*

*/}
}
- {halfChart && halfChart.length > 0 &&
+ {halfChart && halfChart.length > 0 &&
0 ? '200px' : 'auto',
+ }}
+ >
}) =>
>
-
+ 0 ? 200 : 400}>
+
+
+
))}
}
- {otherHalfChart && otherHalfChart.length > 0 &&
+ {otherHalfChart && otherHalfChart.length > 0 &&
}) =>
className="rounded-[6px] flex flex-col overflow-hidden"
>
-
+
+
-
))}
diff --git a/electron/servers/nextjs/app/presentation-templates/Report/MilestoneSlide.tsx b/electron/servers/nextjs/app/presentation-templates/Report/MilestoneSlide.tsx
index 3cccddc7..3274e6bc 100644
--- a/electron/servers/nextjs/app/presentation-templates/Report/MilestoneSlide.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/Report/MilestoneSlide.tsx
@@ -8,7 +8,7 @@ const MilestoneItemSchema = z.object({
description: "Heading displayed below the milestone marker.",
}),
description: z.string().min(10).max(80).meta({
- description: "Supporting milestone description shown under the heading.",
+ description: "Supporting milestone description shown under the heading. with max 80 characters",
}),
});
@@ -32,27 +32,27 @@ export const Schema = z.object({
{
bulletNumber: "01",
heading: "Heading",
- description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,",
},
{
bulletNumber: "02",
heading: "Heading",
- description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ description: "Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet,",
},
{
bulletNumber: "03",
heading: "Heading",
- description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ description: "Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet",
},
{
bulletNumber: "04",
heading: "Heading",
- description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,",
},
{
bulletNumber: "05",
heading: "Heading",
- description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
+ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,",
},
])
.meta({
@@ -118,7 +118,7 @@ const MilestoneSlide = ({ data }: { data: Partial
}) => {
0 ? 'pr-[33px]' : ''} ${index === 0 ? 'px-[33px]' : ''}`}
+ className={`text-center h-[130px] mt-[20px] text-[#232223] ${index > 0 ? 'pr-[33px]' : ''} ${index === 0 ? 'px-[33px]' : ''}`}
style={{ color: "var(--background-text,#232223)" }}
>
diff --git a/electron/servers/nextjs/app/presentation-templates/Report/flexibleReportChart.tsx b/electron/servers/nextjs/app/presentation-templates/Report/flexibleReportChart.tsx
index 37164a1f..7be6fafd 100644
--- a/electron/servers/nextjs/app/presentation-templates/Report/flexibleReportChart.tsx
+++ b/electron/servers/nextjs/app/presentation-templates/Report/flexibleReportChart.tsx
@@ -382,8 +382,6 @@ export function FlexibleReportChart({
case "bar":
return (
-
-
{
return (
-
+
{/* Processing... */}
- {Math.round(progress)}%
+ {Math.round(progress)}%
-
+
+
+
+
+
+
+
+
+
+ )
+}
+
/** Toasts with both title and description (matches styled [data-title] / [data-description]). */
export const notify = {
error: (title: string, description: string) =>
@@ -20,7 +36,7 @@ const Toaster = ({ icons, ...props }: ToasterProps) => {
const defaultIcons: NonNullable
= {
success: ,
error: ,
- info: ,
+ info: ,
warning: ,
loading: ,
close: Got it!,
diff --git a/servers/nextjs/components/CodexConfig.tsx b/servers/nextjs/components/CodexConfig.tsx
index c143c6b2..0f3f80a6 100644
--- a/servers/nextjs/components/CodexConfig.tsx
+++ b/servers/nextjs/components/CodexConfig.tsx
@@ -41,13 +41,13 @@ interface CodexModel {
}
const CHATGPT_MODELS: CodexModel[] = [
- { id: "gpt-5.1", name: "GPT-5.1" },
- { id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max" },
- { id: "gpt-5.2", name: "GPT-5.2" },
- { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
- { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
- { id: "gpt-5.4-mini", name: "GPT-5.4 Mini" },
- { id: "gpt-5.4", name: "GPT-5.4" },
+ { id: "gpt-5.1", name: "GPT-5.1" },
+ { id: "gpt-5.1-codex-max", name: "GPT-5.1 Codex Max" },
+ { id: "gpt-5.2", name: "GPT-5.2" },
+ { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
+ { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
+ { id: "gpt-5.4-mini", name: "GPT-5.4 Mini" },
+ { id: "gpt-5.4", name: "GPT-5.4" },
];
const DEFAULT_CODEX_MODEL = "gpt-5.4-mini";