/** * Document templates: `createBlankDocument()` (Datei › Neu, and what a first * start opens) and `createSeedDocument()` (Datei › Muster). * * The pre-filled document ("roter Faden" of the study), in the v2 canvas model: * one sheet ("Analyse") carrying three table objects and a chart object, plus a * second empty sheet to try things out. * * Note on the brief: the acceptance list mentions "Übersicht!B2 = 6070" as the * yearly Nord revenue, but the given Nord row is 1200 + 1450 + 1600 + 1720 = * 5970. The explicit table wins -- the exact number is deterministic and the * propagation behaviour it demonstrates is unchanged. */ import { parseA1 } from '../engine'; import type { ChartObject, DocumentState, TableObject } from '../store/types'; import { defaultTableView } from '../store/types'; let uid = 0; const nextId = (p: string) => `${p}-seed-${(uid++).toString(36)}`; function makeTable( name: string, x: number, y: number, rows: number, cols: number, entries: Array<[string, string | number]>, colWidths: Record = {}, viewOverride: Partial = {}, ): TableObject { const cells: Record = {}; for (const [a1, value] of entries) { const { col, row } = parseA1(a1); cells[`${col},${row}`] = String(value); } return { kind: 'table', id: nextId('tbl'), name, x, y, rows, cols, colWidths, cells, view: { ...defaultTableView(), ...viewOverride }, }; } export function createSeedDocument(): DocumentState { const umsatz = makeTable('Umsatz', 40, 40, 20, 8, [ ['A1', 'Region'], ['B1', 'Q1'], ['C1', 'Q2'], ['D1', 'Q3'], ['E1', 'Q4'], ['A2', 'Nord'], ['B2', 1200], ['C2', 1450], ['D2', 1600], ['E2', 1720], ['A3', 'Süd'], ['B3', 980], ['C3', 1100], ['D3', 1250], ['E3', 1310], ['A4', 'Ost'], ['B4', 1550], ['C4', 1480], ['D4', 1620], ['E4', 1700], ['A5', 'West'], ['B5', 1340], ['C5', 1390], ['D5', 1500], ['E5', 1580], ['A6', 'Zentral'], ['B6', 1105], ['C6', 1205], ['D6', 1298], ['E6', 1402], ['A8', 'Summe'], ['B8', '=SUM(B2:B6)'], ['C8', '=SUM(C2:C6)'], ['D8', '=SUM(D2:D6)'], ['E8', '=SUM(E2:E6)'], ['A9', 'Mittelwert'], ['B9', '=AVG(B2:B6)'], ['C9', '=AVG(C2:C6)'], ['D9', '=AVG(D2:D6)'], ['E9', '=AVG(E2:E6)'], ['A10', 'Minimum'], ['B10', '=MIN(B2:B6)'], ['C10', '=MIN(C2:C6)'], ['D10', '=MIN(D2:D6)'], ['E10', '=MIN(E2:E6)'], ['A11', 'Maximum'], ['B11', '=MAX(B2:B6)'], ['C11', '=MAX(C2:C6)'], ['D11', '=MAX(D2:D6)'], ['E11', '=MAX(E2:E6)'], ['A12', 'Anzahl'], ['B12', '=COUNT(B2:B6)'], ['C12', '=COUNT(C2:C6)'], ['D12', '=COUNT(D2:D6)'], ['E12', '=COUNT(E2:E6)'], ['G2', 'Jahr Nord'], ['H2', '=SUM(B2:E2)'], ['G3', 'Schnitt/Q'], ['H3', '=SUM(B2:E2)/4'], ['G4', 'Delta Q4-Q1'], ['H4', '=E2-B2'], ], { 0: 92, 6: 96 }, { mode: 'fixed', width: 545, height: 360, frozenRows: 1, frozenCols: 1 }); const kosten = makeTable('Kosten', 40, 700, 12, 8, [ ['A1', 'Region'], ['B1', 'Q1'], ['C1', 'Q2'], ['D1', 'Q3'], ['E1', 'Q4'], ['A2', 'Nord'], ['B2', 800], ['C2', 820], ['D2', 900], ['E2', 880], ['A3', 'Süd'], ['B3', 700], ['C3', 690], ['D3', 710], ['E3', 720], ['A4', 'Ost'], ['B4', 900], ['C4', 910], ['D4', 950], ['E4', 980], ['A5', 'West'], ['B5', 760], ['C5', 770], ['D5', 780], ['E5', 790], ['A6', 'Zentral'], ['B6', 640], ['C6', 650], ['D6', 660], ['E6', 670], ], { 0: 92 }); const regions = ['Nord', 'Süd', 'Ost', 'West', 'Zentral']; const overview: Array<[string, string | number]> = [ ['A1', 'Region'], ['B1', 'Umsatz Jahr'], ['C1', 'Kosten Jahr'], ['D1', 'Deckungsbeitrag'], ['E1', 'Marge %'], ]; regions.forEach((region, i) => { const r = i + 2; overview.push( [`A${r}`, region], [`B${r}`, `=SUM(Umsatz!B${r}:E${r})`], [`C${r}`, `=SUM(Kosten!B${r}:E${r})`], [`D${r}`, `=B${r}-C${r}`], [`E${r}`, `=D${r}/B${r}*100`], ); }); overview.push( ['A8', 'Gesamt'], ['B8', '=SUM(B2:B6)'], ['C8', '=SUM(C2:C6)'], ['D8', '=SUM(D2:D6)'], ['E8', '=AVG(E2:E6)'], ); const uebersicht = makeTable('Übersicht', 1000, 40, 12, 6, overview, { 0: 84, 3: 118, }); const chart: ChartObject = { kind: 'chart', id: nextId('cht'), name: 'Umsatz je Region', x: 1000, y: 460, width: 560, height: 340, view: 'bar', sourceTableId: umsatz.id, }; const analyse = { id: nextId('sheet'), name: 'Analyse', objects: [umsatz, kosten, uebersicht, chart], }; // second sheet demos the per-sheet backdrop colour + hidden grid const blatt2 = { id: nextId('sheet'), name: 'Blatt 2', objects: [], background: '#f4f1ff', showGrid: false, }; return { version: 2, sheets: [analyse, blatt2], activeSheetId: analyse.id, activeObjectId: umsatz.id, selection: { tableId: umsatz.id, anchor: { col: 0, row: 0 }, focus: { col: 0, row: 0 } }, locale: 'de-DE', csvDelimiter: ',', customFunctions: [], namedRanges: [ // demos "🏷 Namen": =Umsatz_Q1 anywhere resolves to Umsatz!B2:B6, even // from a different sheet, without a table qualifier. { id: nextId('nr'), name: 'Umsatz_Q1', tableId: umsatz.id, start: { col: 1, row: 1 }, end: { col: 1, row: 5 } }, ], macros: [], }; } /** An empty document: one sheet with one empty table, ready to type into. */ export function createBlankDocument(): DocumentState { const table = makeTable('Tabelle 1', 40, 40, 12, 6, []); const sheet = { id: nextId('sheet'), name: 'Blatt 1', objects: [table] }; return { version: 2, sheets: [sheet], activeSheetId: sheet.id, activeObjectId: table.id, selection: { tableId: table.id, anchor: { col: 0, row: 0 }, focus: { col: 0, row: 0 } }, locale: 'de-DE', csvDelimiter: ',', customFunctions: [], namedRanges: [], macros: [], }; }