mirror of
https://github.com/Mintplex-Labs/anything-llm
synced 2026-04-25 17:15:37 +02:00
* 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
299 lines
7.6 KiB
JavaScript
Executable File
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);
|