Files
kottgard-testing/docs/generate-guide-docx.mjs
T

272 lines
10 KiB
JavaScript

/**
* Generates Kottgard-Website-Guide.docx
* Run: node docs/generate-guide-docx.mjs
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import {
Document,
Packer,
Paragraph,
TextRun,
Table,
TableRow,
TableCell,
HeadingLevel,
AlignmentType,
BorderStyle,
WidthType,
ShadingType,
PageBreak,
LevelFormat,
} from 'docx';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const outPath = path.join(__dirname, 'Kottgard-Website-Guide.docx');
const border = { style: BorderStyle.SINGLE, size: 1, color: 'CCCCCC' };
const borders = { top: border, bottom: border, left: border, right: border };
const tableWidth = 9360;
function cell(text, width, fill = 'FFFFFF') {
return new TableCell({
borders,
width: { size: width, type: WidthType.DXA },
shading: { fill, type: ShadingType.CLEAR },
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph({ children: [new TextRun(text)] })],
});
}
function headerRow(cols, widths) {
return new TableRow({
children: cols.map((t, i) => cell(t, widths[i], 'D5E8F0')),
});
}
function dataRow(cols, widths) {
return new TableRow({
children: cols.map((t, i) => cell(t, widths[i])),
});
}
function table(columnWidths, rows) {
return new Table({
width: { size: tableWidth, type: WidthType.DXA },
columnWidths,
rows,
});
}
function h1(text) {
return new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(text)] });
}
function h2(text) {
return new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun(text)] });
}
function p(text) {
return new Paragraph({ spacing: { after: 200 }, children: [new TextRun(text)] });
}
function bullet(ref, text) {
return new Paragraph({
numbering: { reference: ref, level: 0 },
children: [new TextRun(text)],
});
}
const doc = new Document({
styles: {
default: { document: { run: { font: 'Arial', size: 22 } } },
paragraphStyles: [
{
id: 'Heading1',
name: 'Heading 1',
basedOn: 'Normal',
next: 'Normal',
quickFormat: true,
run: { size: 32, bold: true, font: 'Arial' },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 },
},
{
id: 'Heading2',
name: 'Heading 2',
basedOn: 'Normal',
next: 'Normal',
quickFormat: true,
run: { size: 26, bold: true, font: 'Arial' },
paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 },
},
],
},
numbering: {
config: [
{
reference: 'bullets',
levels: [
{
level: 0,
format: LevelFormat.BULLET,
text: '\u2022',
alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } },
},
],
},
],
},
sections: [
{
properties: {
page: {
size: { width: 12240, height: 15840 },
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 },
},
},
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 400 },
children: [
new TextRun({ text: 'Kött Gård', bold: true, size: 48 }),
],
}),
new Paragraph({
alignment: AlignmentType.CENTER,
spacing: { after: 600 },
children: [
new TextRun({
text: 'Website Visual & Programming Guide',
size: 32,
color: '8B1F1F',
}),
],
}),
p('Premium Halal meat e-commerce — Märsta, Sweden'),
p('Document version: June 2026'),
p('Companion files: docs/annotated/ (line-by-line code comments)'),
new Paragraph({ children: [new PageBreak()] }),
h1('1. What is this website?'),
p(
'Kött Gård is a Next.js e-commerce front-end for ordering fresh Halal chicken, beef, lamb, and fish. Customers browse products, customize cuts (Nihari, Karahi, piece counts), add to cart, checkout, and view order history. Languages: Swedish, English, Urdu (RTL).'
),
h2('Demo login'),
table(
[3120, 6240],
[
headerRow(['Field', 'Value'], [3120, 6240]),
dataRow(['Email', 'demo@kottgard.se'], [3120, 6240]),
dataRow(['Password', 'demo123'], [3120, 6240]),
dataRow(['Orders', '3 sample orders in Account'], [3120, 6240]),
]
),
h1('2. Homepage layout (visual map)'),
p('When a customer opens https://kottgard.se/, they scroll through these sections:'),
table(
[800, 2200, 3160, 3200],
[
headerRow(['#', 'Section', 'File', 'Customer action'], [800, 2200, 3160, 3200]),
dataRow(['1', 'Hero', 'Hero.tsx', 'Shop now / WhatsApp'], [800, 2200, 3160, 3200]),
dataRow(['2', 'Trust badges', 'TrustBadges.tsx', 'Click → About'], [800, 2200, 3160, 3200]),
dataRow(['3', 'About preview', 'AboutPreview.tsx', 'Read more → /about'], [800, 2200, 3160, 3200]),
dataRow(['4', 'Categories', 'CategoryGrid.tsx', 'Chicken/Beef/Lamb/Fish'], [800, 2200, 3160, 3200]),
dataRow(['5', 'Featured', 'FeaturedProducts.tsx', 'Product cards'], [800, 2200, 3160, 3200]),
dataRow(['6', 'How it works', 'HowItWorks.tsx', 'Order steps'], [800, 2200, 3160, 3200]),
dataRow(['7', 'Weekly offers', 'WeeklyOffers.tsx', 'Deals → products'], [800, 2200, 3160, 3200]),
dataRow(['8', 'CTA', 'CTA.tsx', 'Browse selection'], [800, 2200, 3160, 3200]),
dataRow(['9', 'Social', 'SocialFollow.tsx', 'Facebook / Instagram'], [800, 2200, 3160, 3200]),
dataRow(['10', 'Contact', 'ContactPreview.tsx', 'Map / phone / about'], [800, 2200, 3160, 3200]),
]
),
h1('3. All pages & routes'),
table(
[2800, 3360, 3200],
[
headerRow(['URL', 'File', 'Description'], [2800, 3360, 3200]),
dataRow(['/', 'app/page.tsx', 'Homepage'], [2800, 3360, 3200]),
dataRow(['/shop', 'app/shop/page.tsx', 'Catalog + search + filters'], [2800, 3360, 3200]),
dataRow(['/product/[slug]', 'app/product/[slug]/page.tsx', 'Detail + customize'], [2800, 3360, 3200]),
dataRow(['/cart', 'app/cart/page.tsx', 'Shopping cart'], [2800, 3360, 3200]),
dataRow(['/checkout', 'app/checkout/page.tsx', 'Place order (demo)'], [2800, 3360, 3200]),
dataRow(['/login', 'app/login/page.tsx', 'Auth'], [2800, 3360, 3200]),
dataRow(['/account', 'app/account/page.tsx', 'Profile + orders'], [2800, 3360, 3200]),
dataRow(['/wishlist', 'app/wishlist/page.tsx', 'Saved items'], [2800, 3360, 3200]),
dataRow(['/about', 'app/about/page.tsx', 'Company + privacy + terms'], [2800, 3360, 3200]),
]
),
new Paragraph({ children: [new PageBreak()] }),
h1('4. Programming languages & frameworks'),
h2('TypeScript'),
p(
'TypeScript adds types to JavaScript. Example: Product interface ensures every product has id, slug, price. The compiler errors if you typo product.slugg.'
),
h2('React'),
p(
'React builds UI from components (functions returning JSX). State (useState) updates what users see. Props pass data parent → child.'
),
h2('Next.js 13 App Router'),
bullet('bullets', 'app/ folder = routes. page.tsx = page, layout.tsx = wrapper.'),
bullet('bullets', 'Server Components default — less JavaScript sent to browser.'),
bullet('bullets', "'use client' = component runs in browser (hooks, clicks)."),
h2('Zustand'),
p(
'Global stores: useCartStore, useAuthStore, useWishlistStore. persist middleware saves to localStorage so cart survives refresh.'
),
h2('Tailwind CSS'),
p(
'Classes like bg-brand-700 text-white px-4 py-2 style elements. Colors defined in tailwind.config.ts (burgundy, cream, gold).'
),
h1('5. Data flow diagram (text)'),
p('Homepage → Shop (filter URL) → Product page → addItem() → Cart store → Checkout → Order in Auth store → Account page'),
p('Images: lib/images.ts → products.ts → ProductCard / Hero → AppImage → next/image → Unsplash CDN'),
p('Text: i18n/locales/sv|en|ur.ts → useTranslation() → t("key") in components'),
h1('6. Annotated code (line-by-line)'),
p('Location: Kottgard/docs/annotated/'),
table(
[4200, 5160],
[
headerRow(['File', 'Explains'], [4200, 5160]),
dataRow(['01-homepage.annotated.tsx', 'How homepage composes sections'], [4200, 5160]),
dataRow(['02-root-layout.annotated.tsx', 'Fonts, SEO, shell layout'], [4200, 5160]),
dataRow(['03-shop-page.annotated.tsx', 'URL sync, useMemo filtering'], [4200, 5160]),
dataRow(['04-header.annotated.tsx', 'Navigation + Zustand badges'], [4200, 5160]),
dataRow(['05-images.annotated.ts', 'Unsplash URL builder'], [4200, 5160]),
dataRow(['06-cart-store.annotated.ts', 'Cart logic + persist'], [4200, 5160]),
]
),
p(
'Each line has comments explaining WHAT the code does and WHY. These are learning copies — not imported by the live app.'
),
h1('7. Brand colors'),
table(
[3120, 3120, 3120],
[
headerRow(['Name', 'Hex', 'Use'], [3120, 3120, 3120]),
dataRow(['Burgundy (brand)', '#8B1F1F', 'Header, buttons, footer'], [3120, 3120, 3120]),
dataRow(['Cream', 'Warm off-white', 'Page backgrounds'], [3120, 3120, 3120]),
dataRow(['Gold', 'Accent', 'Prices, badges, CTAs'], [3120, 3120, 3120]),
]
),
h1('8. How to run locally'),
bullet('bullets', 'npm install'),
bullet('bullets', 'npm run dev → http://localhost:3000'),
bullet('bullets', 'npm run build → production check'),
],
},
],
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outPath, buffer);
console.log('Written:', outPath);