Files
anything-llm/server/utils/agents/aibitat/plugins/create-files/docx/test-themes.js
Timothy Carambat 7aaea7f514 File creation agent skills (#5280)
* Powerpoint File Creation (#5278)

* wip

* download card

* UI for downloading

* move to fs system with endpoint to pull files

* refactor UI

* final-pass

* remove save-file-browser skill and refactor

* remove fileDownload event

* reset

* reset file

* reset timeout

* persist toggle

* Txt creation (#5279)

* wip

* download card

* UI for downloading

* move to fs system with endpoint to pull files

* refactor UI

* final-pass

* remove save-file-browser skill and refactor

* remove fileDownload event

* reset

* reset file

* reset timeout

* wip

* persist toggle

* add arbitrary text creation file

* Add PDF document generation with markdown formatting (#5283)

add support for branding in bottom right corner
refactor core utils and frontend rendering

* Xlsx document creation (#5284)

add Excel doc & sheet creation

* Basic docx creation (#5285)

* Basic docx creation

* add test theme support + styling and title pages

* simplify skill selection

* handle TG attachments

* send documents over tg

* lazy import

* pin deps

* fix lock

* i18n for file creation (#5286)

i18n for file-creation
connect #5280

* theme overhaul

* Add PPTX subagent for better results

* forgot files

* Add PPTX subagent for better results (#5287)

* Add PPTX subagent for better results

* forgot files

* make sub-agent use proper tool calling if it can and better UI hints
2026-03-30 15:13:39 -07:00

299 lines
7.6 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Test utility to generate sample Word documents for all themes and configurations.
* Run from the server directory: node utils/agents/aibitat/plugins/create-files/docx/test-themes.js
*
* Output goes to: storage/generated-files/docx-theme-previews/
*/
const path = require("path");
const fs = require("fs/promises");
const {
DOCUMENT_STYLES,
getTheme,
getMargins,
loadLibraries,
htmlToDocxElements,
createCoverPageSection,
createRunningHeader,
createRunningFooter,
DEFAULT_NUMBERING_CONFIG,
} = require("./utils.js");
const OUTPUT_DIR = path.resolve(
__dirname,
"../../../../../../storage/generated-files/docx-theme-previews"
);
const SAMPLE_CONTENT = `# Sample Document
## Executive Summary
This document demonstrates the **styling capabilities** of the Word document generator. It includes various content types to showcase how themes affect the visual appearance.
## Key Features
- Professional title pages with centered content
- Running headers with document title
- Page X of Y footer numbering
- Color-coordinated themes throughout
## Data Overview
| Metric | Q1 | Q2 | Q3 | Q4 |
|--------|-----|-----|-----|-----|
| Revenue | $1.2M | $1.5M | $1.8M | $2.1M |
| Growth | +15% | +25% | +20% | +17% |
| Users | 10K | 15K | 22K | 30K |
## Technical Details
Here is an example code block:
\`\`\`javascript
const config = {
theme: "blue",
margins: "normal",
includeTitlePage: true
};
\`\`\`
> **Note:** This blockquote demonstrates how accent colors are applied to the left border. Blockquotes are useful for callouts and important notes.
## Conclusion
The themed document system provides a consistent, professional look across all generated documents. Each theme cascades colors through:
1. Heading text colors
2. Table header backgrounds
3. Blockquote borders
4. Footer text styling
---
Thank you for reviewing this sample document.
`;
const MINIMAL_CONTENT = `# Quick Report
## Summary
A brief document to test minimal content rendering.
- Point one
- Point two
- Point three
| Item | Value |
|------|-------|
| A | 100 |
| B | 200 |
`;
async function generateThemePreview(themeName, themeConfig, options = {}) {
const libs = await loadLibraries();
const { marked, docx } = libs;
const { Document, Packer, Paragraph, TextRun } = docx;
marked.setOptions({ gfm: true, breaks: true });
const {
margins = "normal",
includeTitlePage = false,
content = SAMPLE_CONTENT,
subtitle = null,
author = null,
} = options;
const marginConfig = getMargins(margins);
const title = `${themeConfig.name || themeName} Theme Preview`;
const html = marked.parse(content);
const docElements = await htmlToDocxElements(
html,
libs,
console.log,
themeConfig
);
if (docElements.length === 0) {
docElements.push(
new Paragraph({
children: [new TextRun({ text: content })],
})
);
}
const sections = [];
if (includeTitlePage) {
const currentDate = new Date().toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
sections.push(
createCoverPageSection(docx, {
title,
subtitle: subtitle || `Demonstrating the ${themeName} color scheme`,
author: author || "AnythingLLM Theme Tester",
date: currentDate,
theme: themeConfig,
margins: marginConfig,
logoBuffer: null,
})
);
sections.push({
properties: {
page: { margin: marginConfig },
titlePage: true,
},
children: docElements,
headers: {
default: createRunningHeader(docx, title, themeConfig),
},
footers: {
default: createRunningFooter(docx, null, themeConfig),
},
});
} else {
sections.push({
properties: {
page: { margin: marginConfig },
},
children: docElements,
footers: {
default: createRunningFooter(docx, null, themeConfig),
},
});
}
const doc = new Document({
title,
creator: "AnythingLLM Theme Tester",
description: `Theme preview for ${themeName}`,
numbering: DEFAULT_NUMBERING_CONFIG,
sections,
});
return Packer.toBuffer(doc);
}
async function main() {
console.log("DOCX Theme Preview Generator");
console.log("============================\n");
await fs.mkdir(OUTPUT_DIR, { recursive: true });
const themes = Object.keys(DOCUMENT_STYLES.themes);
const marginPresets = Object.keys(DOCUMENT_STYLES.margins);
console.log(`Themes: ${themes.join(", ")}`);
console.log(`Margins: ${marginPresets.join(", ")}\n`);
const configs = [];
for (const themeName of themes) {
configs.push({
name: `theme-${themeName}-simple`,
theme: themeName,
margins: "normal",
includeTitlePage: false,
content: SAMPLE_CONTENT,
});
configs.push({
name: `theme-${themeName}-with-title-page`,
theme: themeName,
margins: "normal",
includeTitlePage: true,
content: SAMPLE_CONTENT,
});
}
for (const marginName of marginPresets) {
configs.push({
name: `margins-${marginName}`,
theme: "neutral",
margins: marginName,
includeTitlePage: true,
content: SAMPLE_CONTENT,
});
}
configs.push({
name: `full-featured-blue`,
theme: "blue",
margins: "normal",
includeTitlePage: true,
content: SAMPLE_CONTENT,
subtitle: "A Complete Feature Demonstration",
author: "Documentation Team",
});
configs.push({
name: `minimal-warm`,
theme: "warm",
margins: "narrow",
includeTitlePage: false,
content: MINIMAL_CONTENT,
});
console.log(`Generating ${configs.length} preview documents...\n`);
for (const config of configs) {
const themeConfig = getTheme(config.theme);
try {
const buffer = await generateThemePreview(config.theme, themeConfig, {
margins: config.margins,
includeTitlePage: config.includeTitlePage,
content: config.content,
subtitle: config.subtitle,
author: config.author,
});
const filename = `${config.name}.docx`;
const filepath = path.join(OUTPUT_DIR, filename);
await fs.writeFile(filepath, buffer);
const sizeKB = (buffer.length / 1024).toFixed(1);
const titlePage = config.includeTitlePage ? "✓ title" : " - ";
console.log(
`${config.name.padEnd(30)} [${config.theme.padEnd(7)}] [${config.margins.padEnd(6)}] ${titlePage} (${sizeKB}KB)`
);
} catch (error) {
console.error(`${config.name.padEnd(30)} → Error: ${error.message}`);
console.error(error.stack);
}
}
console.log(`\n✅ Done! Files saved to: ${OUTPUT_DIR}`);
console.log(
"\nOpen the .docx files in Microsoft Word or LibreOffice to preview each configuration."
);
console.log("\n--- Theme Color Reference ---");
for (const [name, colors] of Object.entries(DOCUMENT_STYLES.themes)) {
console.log(`\n${name.toUpperCase()}:`);
console.log(` Heading: #${colors.heading}`);
console.log(` Accent: #${colors.accent}`);
console.log(` Table Header: #${colors.tableHeader}`);
console.log(` Border: #${colors.border}`);
console.log(` Cover BG: #${colors.coverBg}`);
console.log(` Footer Text: #${colors.footerText}`);
}
console.log("\n--- Margin Presets (twips) ---");
for (const [name, margins] of Object.entries(DOCUMENT_STYLES.margins)) {
const inchTop = (margins.top / 1440).toFixed(2);
const inchLeft = (margins.left / 1440).toFixed(2);
console.log(
`${name.padEnd(8)}: top/bottom=${inchTop}" left/right=${inchLeft}"`
);
}
}
main().catch(console.error);