@planu/cli 0.54.2 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/config/license-plans.json +1 -0
  2. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts +7 -1
  3. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.d.ts.map +1 -1
  4. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js +16 -3
  5. package/dist/engine/doc-generator/executive-summary/executive-summary-generator.js.map +1 -1
  6. package/dist/engine/doc-generator/executive-summary/html-template.d.ts +5 -2
  7. package/dist/engine/doc-generator/executive-summary/html-template.d.ts.map +1 -1
  8. package/dist/engine/doc-generator/executive-summary/html-template.js +7 -3
  9. package/dist/engine/doc-generator/executive-summary/html-template.js.map +1 -1
  10. package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts +3 -1
  11. package/dist/engine/doc-generator/per-spec-report/executive-report.d.ts.map +1 -1
  12. package/dist/engine/doc-generator/per-spec-report/executive-report.js +22 -2
  13. package/dist/engine/doc-generator/per-spec-report/executive-report.js.map +1 -1
  14. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts +5 -3
  15. package/dist/engine/doc-generator/per-spec-report/html-wrapper.d.ts.map +1 -1
  16. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js +27 -6
  17. package/dist/engine/doc-generator/per-spec-report/html-wrapper.js.map +1 -1
  18. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts +1 -0
  19. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.d.ts.map +1 -1
  20. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js +29 -0
  21. package/dist/engine/doc-generator/per-spec-report/spec-data-extractor.js.map +1 -1
  22. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts +8 -1
  23. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.d.ts.map +1 -1
  24. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js +188 -0
  25. package/dist/engine/doc-generator/per-spec-report/spec-section-builders.js.map +1 -1
  26. package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts +3 -1
  27. package/dist/engine/doc-generator/per-spec-report/technical-report.d.ts.map +1 -1
  28. package/dist/engine/doc-generator/per-spec-report/technical-report.js +24 -7
  29. package/dist/engine/doc-generator/per-spec-report/technical-report.js.map +1 -1
  30. package/dist/engine/doc-generator/portal/analytics-page.d.ts +8 -0
  31. package/dist/engine/doc-generator/portal/analytics-page.d.ts.map +1 -0
  32. package/dist/engine/doc-generator/portal/analytics-page.js +265 -0
  33. package/dist/engine/doc-generator/portal/analytics-page.js.map +1 -0
  34. package/dist/engine/doc-generator/portal/architecture-page.d.ts +6 -0
  35. package/dist/engine/doc-generator/portal/architecture-page.d.ts.map +1 -0
  36. package/dist/engine/doc-generator/portal/architecture-page.js +250 -0
  37. package/dist/engine/doc-generator/portal/architecture-page.js.map +1 -0
  38. package/dist/engine/doc-generator/portal/changelog-page.d.ts +6 -0
  39. package/dist/engine/doc-generator/portal/changelog-page.d.ts.map +1 -0
  40. package/dist/engine/doc-generator/portal/changelog-page.js +204 -0
  41. package/dist/engine/doc-generator/portal/changelog-page.js.map +1 -0
  42. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts +11 -0
  43. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.d.ts.map +1 -0
  44. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js +24 -0
  45. package/dist/engine/doc-generator/portal/data-aggregators/accuracy-aggregator.js.map +1 -0
  46. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts +9 -0
  47. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.d.ts.map +1 -0
  48. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js +31 -0
  49. package/dist/engine/doc-generator/portal/data-aggregators/bottleneck-detector.js.map +1 -0
  50. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts +10 -0
  51. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.d.ts.map +1 -0
  52. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js +77 -0
  53. package/dist/engine/doc-generator/portal/data-aggregators/burndown-aggregator.js.map +1 -0
  54. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts +9 -0
  55. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.d.ts.map +1 -0
  56. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js +31 -0
  57. package/dist/engine/doc-generator/portal/data-aggregators/velocity-aggregator.js.map +1 -0
  58. package/dist/engine/doc-generator/portal/decision-page.d.ts +6 -0
  59. package/dist/engine/doc-generator/portal/decision-page.d.ts.map +1 -0
  60. package/dist/engine/doc-generator/portal/decision-page.js +169 -0
  61. package/dist/engine/doc-generator/portal/decision-page.js.map +1 -0
  62. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts +8 -0
  63. package/dist/engine/doc-generator/portal/decision-timeline-builder.d.ts.map +1 -0
  64. package/dist/engine/doc-generator/portal/decision-timeline-builder.js +131 -0
  65. package/dist/engine/doc-generator/portal/decision-timeline-builder.js.map +1 -0
  66. package/dist/engine/doc-generator/portal/index.d.ts +19 -0
  67. package/dist/engine/doc-generator/portal/index.d.ts.map +1 -0
  68. package/dist/engine/doc-generator/portal/index.js +21 -0
  69. package/dist/engine/doc-generator/portal/index.js.map +1 -0
  70. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts +8 -0
  71. package/dist/engine/doc-generator/portal/kanban-view-builder.d.ts.map +1 -0
  72. package/dist/engine/doc-generator/portal/kanban-view-builder.js +140 -0
  73. package/dist/engine/doc-generator/portal/kanban-view-builder.js.map +1 -0
  74. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts +27 -0
  75. package/dist/engine/doc-generator/portal/portal-breadcrumbs.d.ts.map +1 -0
  76. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js +139 -0
  77. package/dist/engine/doc-generator/portal/portal-breadcrumbs.js.map +1 -0
  78. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts +8 -0
  79. package/dist/engine/doc-generator/portal/portal-landing-cards.d.ts.map +1 -0
  80. package/dist/engine/doc-generator/portal/portal-landing-cards.js +177 -0
  81. package/dist/engine/doc-generator/portal/portal-landing-cards.js.map +1 -0
  82. package/dist/engine/doc-generator/portal/portal-navbar.d.ts +15 -0
  83. package/dist/engine/doc-generator/portal/portal-navbar.d.ts.map +1 -0
  84. package/dist/engine/doc-generator/portal/portal-navbar.js +143 -0
  85. package/dist/engine/doc-generator/portal/portal-navbar.js.map +1 -0
  86. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts +22 -0
  87. package/dist/engine/doc-generator/portal/portal-page-detector.d.ts.map +1 -0
  88. package/dist/engine/doc-generator/portal/portal-page-detector.js +58 -0
  89. package/dist/engine/doc-generator/portal/portal-page-detector.js.map +1 -0
  90. package/dist/engine/doc-generator/portal/portal-theme.d.ts +7 -0
  91. package/dist/engine/doc-generator/portal/portal-theme.d.ts.map +1 -0
  92. package/dist/engine/doc-generator/portal/portal-theme.js +53 -0
  93. package/dist/engine/doc-generator/portal/portal-theme.js.map +1 -0
  94. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts +5 -0
  95. package/dist/engine/doc-generator/portal/risk-gauge-svg.d.ts.map +1 -0
  96. package/dist/engine/doc-generator/portal/risk-gauge-svg.js +80 -0
  97. package/dist/engine/doc-generator/portal/risk-gauge-svg.js.map +1 -0
  98. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts +11 -0
  99. package/dist/engine/doc-generator/portal/risk-matrix-svg.d.ts.map +1 -0
  100. package/dist/engine/doc-generator/portal/risk-matrix-svg.js +181 -0
  101. package/dist/engine/doc-generator/portal/risk-matrix-svg.js.map +1 -0
  102. package/dist/engine/doc-generator/portal/risk-page.d.ts +7 -0
  103. package/dist/engine/doc-generator/portal/risk-page.d.ts.map +1 -0
  104. package/dist/engine/doc-generator/portal/risk-page.js +219 -0
  105. package/dist/engine/doc-generator/portal/risk-page.js.map +1 -0
  106. package/dist/engine/doc-generator/portal/roadmap-page.d.ts +7 -0
  107. package/dist/engine/doc-generator/portal/roadmap-page.d.ts.map +1 -0
  108. package/dist/engine/doc-generator/portal/roadmap-page.js +204 -0
  109. package/dist/engine/doc-generator/portal/roadmap-page.js.map +1 -0
  110. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts +4 -0
  111. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.d.ts.map +1 -0
  112. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js +50 -0
  113. package/dist/engine/doc-generator/portal/svg-charts/bar-chart.js.map +1 -0
  114. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts +16 -0
  115. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.d.ts.map +1 -0
  116. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js +45 -0
  117. package/dist/engine/doc-generator/portal/svg-charts/chart-utils.js.map +1 -0
  118. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts +16 -0
  119. package/dist/engine/doc-generator/portal/svg-charts/line-chart.d.ts.map +1 -0
  120. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js +159 -0
  121. package/dist/engine/doc-generator/portal/svg-charts/line-chart.js.map +1 -0
  122. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts +7 -0
  123. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.d.ts.map +1 -0
  124. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js +52 -0
  125. package/dist/engine/doc-generator/portal/svg-charts/pie-chart.js.map +1 -0
  126. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts +8 -0
  127. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.d.ts.map +1 -0
  128. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js +126 -0
  129. package/dist/engine/doc-generator/proposal/proposal-gantt-builder.js.map +1 -0
  130. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts +10 -0
  131. package/dist/engine/doc-generator/proposal/proposal-generator.d.ts.map +1 -0
  132. package/dist/engine/doc-generator/proposal/proposal-generator.js +93 -0
  133. package/dist/engine/doc-generator/proposal/proposal-generator.js.map +1 -0
  134. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts +7 -0
  135. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.d.ts.map +1 -0
  136. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js +31 -0
  137. package/dist/engine/doc-generator/proposal/proposal-html-wrapper.js.map +1 -0
  138. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts +12 -0
  139. package/dist/engine/doc-generator/proposal/proposal-i18n.d.ts.map +1 -0
  140. package/dist/engine/doc-generator/proposal/proposal-i18n.js +230 -0
  141. package/dist/engine/doc-generator/proposal/proposal-i18n.js.map +1 -0
  142. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts +8 -0
  143. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.d.ts.map +1 -0
  144. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js +32 -0
  145. package/dist/engine/doc-generator/proposal/proposal-kpi-builder.js.map +1 -0
  146. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts +14 -0
  147. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.d.ts.map +1 -0
  148. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js +248 -0
  149. package/dist/engine/doc-generator/proposal/proposal-section-builders-advanced.js.map +1 -0
  150. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts +13 -0
  151. package/dist/engine/doc-generator/proposal/proposal-section-builders.d.ts.map +1 -0
  152. package/dist/engine/doc-generator/proposal/proposal-section-builders.js +423 -0
  153. package/dist/engine/doc-generator/proposal/proposal-section-builders.js.map +1 -0
  154. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts +4 -0
  155. package/dist/engine/doc-generator/proposal/proposal-themes.d.ts.map +1 -0
  156. package/dist/engine/doc-generator/proposal/proposal-themes.js +194 -0
  157. package/dist/engine/doc-generator/proposal/proposal-themes.js.map +1 -0
  158. package/dist/engine/spec-summary-html.d.ts.map +1 -1
  159. package/dist/engine/spec-summary-html.js +17 -5
  160. package/dist/engine/spec-summary-html.js.map +1 -1
  161. package/dist/index.js +2 -0
  162. package/dist/index.js.map +1 -1
  163. package/dist/tools/generate-proposal.d.ts +3 -0
  164. package/dist/tools/generate-proposal.d.ts.map +1 -0
  165. package/dist/tools/generate-proposal.js +166 -0
  166. package/dist/tools/generate-proposal.js.map +1 -0
  167. package/dist/types/docs.d.ts +75 -0
  168. package/dist/types/docs.d.ts.map +1 -1
  169. package/dist/types/portal.d.ts +128 -0
  170. package/dist/types/portal.d.ts.map +1 -0
  171. package/dist/types/portal.js +3 -0
  172. package/dist/types/portal.js.map +1 -0
  173. package/dist/types/proposal.d.ts +57 -0
  174. package/dist/types/proposal.d.ts.map +1 -0
  175. package/dist/types/proposal.js +2 -0
  176. package/dist/types/proposal.js.map +1 -0
  177. package/package.json +1 -1
  178. package/src/config/license-plans.json +1 -0
@@ -0,0 +1,204 @@
1
+ import { getPortalThemeCSS } from './portal-theme.js';
2
+ import { buildNavbar } from './portal-navbar.js';
3
+ import { buildGanttChart } from '../proposal/proposal-gantt-builder.js';
4
+ /**
5
+ * Generate the full roadmap.html page for the Planu portal.
6
+ * Returns an HTML string ready to write to disk.
7
+ */
8
+ export function generateRoadmapPage(specs, ganttStartDate) {
9
+ const navbar = buildNavbar('roadmap', '', ['roadmap', 'dashboard']);
10
+ const ganttHtml = buildGanttSection(specs, ganttStartDate);
11
+ const phaseSummary = buildPhaseSummary(specs);
12
+ const milestonesHtml = buildMilestonesSection(specs);
13
+ return `<!DOCTYPE html>
14
+ <html lang="en">
15
+ <head>
16
+ <meta charset="UTF-8"/>
17
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
18
+ <title>Roadmap — Planu</title>
19
+ <style>
20
+ ${getPortalThemeCSS()}
21
+ ${ROADMAP_CSS}
22
+ </style>
23
+ </head>
24
+ <body>
25
+ ${navbar}
26
+ <main class="roadmap-main">
27
+ <h1 class="roadmap-title">🗺️ Roadmap</h1>
28
+ <section class="planu-card roadmap-section">
29
+ <h2>Gantt Chart</h2>
30
+ ${ganttHtml}
31
+ </section>
32
+ <section class="planu-card roadmap-section">
33
+ <h2>Phase Summary</h2>
34
+ ${phaseSummary}
35
+ </section>
36
+ <section class="planu-card roadmap-section">
37
+ <h2>Milestones</h2>
38
+ ${milestonesHtml}
39
+ </section>
40
+ </main>
41
+ </body>
42
+ </html>`;
43
+ }
44
+ // --- Gantt section ---
45
+ function buildGanttSection(specs, startDate) {
46
+ if (specs.length === 0) {
47
+ return '<p class="roadmap-empty">No specs to display.</p>';
48
+ }
49
+ const gantt = buildGanttChart(specs, undefined, startDate);
50
+ if (!gantt) {
51
+ return '<p class="roadmap-empty">Could not generate Gantt chart.</p>';
52
+ }
53
+ return gantt;
54
+ }
55
+ // --- Phase summary section ---
56
+ function buildPhaseSummary(specs) {
57
+ if (specs.length === 0) {
58
+ return '<p class="roadmap-empty">No specs available.</p>';
59
+ }
60
+ const tagMap = new Map();
61
+ for (const spec of specs) {
62
+ const tags = spec.tags.length > 0 ? spec.tags : ['untagged'];
63
+ const primaryTag = tags[0] ?? 'untagged';
64
+ if (!tagMap.has(primaryTag)) {
65
+ tagMap.set(primaryTag, []);
66
+ }
67
+ const tagSpecs = tagMap.get(primaryTag);
68
+ if (tagSpecs) {
69
+ tagSpecs.push(spec);
70
+ }
71
+ }
72
+ const cards = Array.from(tagMap.entries()).map(([tag, tagSpecs]) => {
73
+ const doneCount = tagSpecs.filter((s) => s.status === 'done').length;
74
+ const total = tagSpecs.length;
75
+ const pct = total > 0 ? Math.round((doneCount / total) * 100) : 0;
76
+ return `<div class="phase-card planu-card">
77
+ <div class="phase-tag">${escapeHtml(tag)}</div>
78
+ <div class="phase-progress-bar">
79
+ <div class="phase-progress-fill" style="width:${pct}%"></div>
80
+ </div>
81
+ <div class="phase-stats">${doneCount} / ${total} done (${pct}%)</div>
82
+ </div>`;
83
+ });
84
+ return `<div class="phase-grid">${cards.join('\n')}</div>`;
85
+ }
86
+ // --- Milestones section ---
87
+ function buildMilestonesSection(specs) {
88
+ if (specs.length === 0) {
89
+ return '<p class="roadmap-empty">No milestones found.</p>';
90
+ }
91
+ const sorted = [...specs].sort((a, b) => {
92
+ const da = a.actuals?.completedAt ?? a.updatedAt;
93
+ const db = b.actuals?.completedAt ?? b.updatedAt;
94
+ return da.localeCompare(db);
95
+ });
96
+ const items = sorted.map((spec) => {
97
+ const isDone = spec.status === 'done';
98
+ const date = spec.actuals?.completedAt ?? spec.updatedAt;
99
+ const dateLabel = date ? date.slice(0, 10) : '—';
100
+ const dotClass = isDone ? 'milestone-dot-done' : 'milestone-dot-pending';
101
+ const depLabels = spec.dependencies.length > 0
102
+ ? `<div class="milestone-deps">⤵ ${spec.dependencies.map(escapeHtml).join(', ')}</div>`
103
+ : '';
104
+ return `<div class="milestone-item">
105
+ <div class="milestone-dot ${dotClass}"></div>
106
+ <div class="milestone-body">
107
+ <div class="milestone-header">
108
+ <span class="milestone-id">${escapeHtml(spec.id)}</span>
109
+ <span class="milestone-title">${escapeHtml(spec.title)}</span>
110
+ <span class="milestone-date">${dateLabel}</span>
111
+ </div>
112
+ ${depLabels}
113
+ </div>
114
+ </div>`;
115
+ });
116
+ return `<div class="milestone-timeline">${items.join('\n')}</div>`;
117
+ }
118
+ // --- Helpers ---
119
+ function escapeHtml(str) {
120
+ return str
121
+ .replace(/&/g, '&amp;')
122
+ .replace(/</g, '&lt;')
123
+ .replace(/>/g, '&gt;')
124
+ .replace(/"/g, '&quot;');
125
+ }
126
+ const ROADMAP_CSS = `
127
+ .roadmap-main {
128
+ max-width: 1100px;
129
+ margin: 0 auto;
130
+ padding: 0 16px 40px;
131
+ }
132
+ .roadmap-title { font-size: 1.5rem; color: var(--planu-primary); margin-bottom: 20px; }
133
+ .roadmap-empty { color: #9ca3af; font-style: italic; padding: 12px 0; }
134
+ .roadmap-section { margin-bottom: 24px; }
135
+ .roadmap-section h2 {
136
+ font-size: 1.05rem;
137
+ color: var(--planu-secondary);
138
+ margin-bottom: 14px;
139
+ border-bottom: 1px solid var(--planu-border);
140
+ padding-bottom: 6px;
141
+ }
142
+ /* Gantt reuse */
143
+ .gantt-container { overflow-x: auto; }
144
+ .gantt-header { display: flex; margin-bottom: 4px; }
145
+ .gantt-header-label { width: 160px; flex-shrink: 0; font-size: 0.75rem; color: #9ca3af; }
146
+ .gantt-header-weeks { display: flex; flex: 1; gap: 2px; }
147
+ .gantt-week { flex: 1; font-size: 0.7rem; color: #9ca3af; text-align: center; }
148
+ .gantt-grid { display: flex; flex-direction: column; gap: 4px; }
149
+ .gantt-row { display: flex; align-items: center; height: 28px; }
150
+ .gantt-label { width: 160px; flex-shrink: 0; font-size: 0.78rem; color: #374151; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
151
+ .gantt-track { position: relative; flex: 1; height: 20px; background: #f3f4f6; border-radius: 4px; }
152
+ .gantt-bar {
153
+ position: absolute;
154
+ height: 100%;
155
+ border-radius: 4px;
156
+ color: white;
157
+ font-size: 0.68rem;
158
+ display: flex;
159
+ align-items: center;
160
+ justify-content: center;
161
+ white-space: nowrap;
162
+ overflow: hidden;
163
+ }
164
+ /* Phase cards */
165
+ .phase-grid {
166
+ display: grid;
167
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
168
+ gap: 12px;
169
+ }
170
+ .phase-card { padding: 12px 14px; }
171
+ .phase-tag { font-weight: 600; font-size: 0.85rem; color: var(--planu-primary); margin-bottom: 8px; }
172
+ .phase-progress-bar {
173
+ background: #e9ecef;
174
+ border-radius: 99px;
175
+ height: 8px;
176
+ overflow: hidden;
177
+ margin-bottom: 6px;
178
+ }
179
+ .phase-progress-fill { background: var(--planu-accent); height: 100%; border-radius: 99px; }
180
+ .phase-stats { font-size: 0.75rem; color: #6b7280; }
181
+ /* Milestones */
182
+ .milestone-timeline { display: flex; flex-direction: column; gap: 0; }
183
+ .milestone-item { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid #f3f4f6; }
184
+ .milestone-dot {
185
+ width: 14px;
186
+ height: 14px;
187
+ border-radius: 50%;
188
+ flex-shrink: 0;
189
+ margin-top: 3px;
190
+ }
191
+ .milestone-dot-done { background: var(--planu-success); }
192
+ .milestone-dot-pending { background: #e9ecef; border: 2px solid #9ca3af; }
193
+ .milestone-body { flex: 1; }
194
+ .milestone-header { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
195
+ .milestone-id { font-size: 0.72rem; color: #9ca3af; flex-shrink: 0; }
196
+ .milestone-title { font-size: 0.85rem; color: #2d3436; flex: 1; }
197
+ .milestone-date { font-size: 0.72rem; color: #6b7280; flex-shrink: 0; }
198
+ .milestone-deps { font-size: 0.72rem; color: #9ca3af; margin-top: 2px; }
199
+ @media print {
200
+ .roadmap-main { max-width: 100%; }
201
+ .gantt-container { overflow-x: visible; }
202
+ }
203
+ `;
204
+ //# sourceMappingURL=roadmap-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roadmap-page.js","sourceRoot":"","sources":["../../../../src/engine/doc-generator/portal/roadmap-page.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { BarChartData, BarChartOptions } from '../../../../types/portal.js';
2
+ /** Build a responsive SVG bar chart. Returns empty string when data is empty. */
3
+ export declare function buildSvgBarChart(data: BarChartData[], options?: BarChartOptions): string;
4
+ //# sourceMappingURL=bar-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bar-chart.d.ts","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/bar-chart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAKjF,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAyCxF"}
@@ -0,0 +1,50 @@
1
+ import { scaleLinear, svgText, CHART_COLORS, escapeXml } from './chart-utils.js';
2
+ const PADDING = { top: 40, right: 20, bottom: 60, left: 50 };
3
+ /** Build a responsive SVG bar chart. Returns empty string when data is empty. */
4
+ export function buildSvgBarChart(data, options) {
5
+ if (data.length === 0) {
6
+ return '';
7
+ }
8
+ const vbW = options?.width ?? 500;
9
+ const vbH = options?.height ?? 300;
10
+ const title = options?.title ?? '';
11
+ const innerW = vbW - PADDING.left - PADDING.right;
12
+ const innerH = vbH - PADDING.top - PADDING.bottom;
13
+ const maxVal = Math.max(...data.map((d) => d.value), 1);
14
+ const yScale = scaleLinear([0, maxVal], [innerH, 0]);
15
+ const barW = Math.max(2, Math.floor(innerW / data.length) - 4);
16
+ const bars = data.map((d, i) => {
17
+ const x = PADDING.left + i * (innerW / data.length) + (innerW / data.length - barW) / 2;
18
+ const barH = innerH - yScale(d.value);
19
+ const y = PADDING.top + yScale(d.value);
20
+ const color = d.color ?? CHART_COLORS[i % CHART_COLORS.length] ?? '#e94560';
21
+ const labelX = x + barW / 2;
22
+ const labelY = vbH - PADDING.bottom + 16;
23
+ const shortLabel = d.label.length > 10 ? d.label.slice(0, 9) + '…' : d.label;
24
+ return `<rect x="${x.toFixed(1)}" y="${y.toFixed(1)}" width="${barW}" height="${Math.max(0, barH).toFixed(1)}" fill="${escapeXml(color)}" rx="2"/>
25
+ ${svgText(labelX, labelY, shortLabel, { fontSize: 10, anchor: 'middle', fill: '#6b7280' })}
26
+ ${svgText(labelX, y - 4, String(d.value), { fontSize: 10, anchor: 'middle', fill: '#2d3436' })}`;
27
+ });
28
+ const yTicks = buildYTicks(maxVal, vbW, PADDING, innerH, yScale);
29
+ const titleEl = title
30
+ ? svgText(vbW / 2, 20, title, { fontSize: 13, anchor: 'middle', fill: '#1a1a2e' })
31
+ : '';
32
+ return `<svg viewBox="0 0 ${vbW} ${vbH}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbW}px">
33
+ ${titleEl}
34
+ ${yTicks}
35
+ ${bars.join('\n ')}
36
+ <line x1="${PADDING.left}" y1="${PADDING.top}" x2="${PADDING.left}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
37
+ <line x1="${PADDING.left}" y1="${PADDING.top + innerH}" x2="${PADDING.left + innerW}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
38
+ </svg>`;
39
+ }
40
+ function buildYTicks(maxVal, vbW, padding, _innerH, yScale) {
41
+ const tickCount = 4;
42
+ return Array.from({ length: tickCount + 1 }, (_, i) => {
43
+ const val = (maxVal / tickCount) * i;
44
+ const y = padding.top + yScale(val);
45
+ const label = Number.isInteger(val) ? String(val) : val.toFixed(1);
46
+ return `<line x1="${padding.left}" y1="${y.toFixed(1)}" x2="${padding.left + (vbW - padding.left - padding.right)}" y2="${y.toFixed(1)}" stroke="#f3f4f6" stroke-width="1"/>
47
+ ${svgText(padding.left - 6, y + 4, label, { fontSize: 9, anchor: 'end', fill: '#9ca3af' })}`;
48
+ }).join('\n ');
49
+ }
50
+ //# sourceMappingURL=bar-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bar-chart.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/bar-chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /** 8 visually distinct colours for chart series. */
2
+ export declare const CHART_COLORS: string[];
3
+ /**
4
+ * Create a linear scale function that maps values from [domainMin, domainMax]
5
+ * to [rangeMin, rangeMax].
6
+ */
7
+ export declare function scaleLinear(domain: [number, number], range: [number, number]): (val: number) => number;
8
+ /** Render an SVG <text> element. */
9
+ export declare function svgText(x: number, y: number, text: string, opts?: {
10
+ fontSize?: number;
11
+ anchor?: string;
12
+ fill?: string;
13
+ }): string;
14
+ /** Escape XML special chars for safe SVG embedding. */
15
+ export declare function escapeXml(str: string): string;
16
+ //# sourceMappingURL=chart-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-utils.d.ts","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/chart-utils.ts"],"names":[],"mappings":"AAEA,oDAAoD;AACpD,eAAO,MAAM,YAAY,EAAE,MAAM,EAWhC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EACxB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAQzB;AAED,oCAAoC;AACpC,wBAAgB,OAAO,CACrB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CAMR;AAED,uDAAuD;AACvD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7C"}
@@ -0,0 +1,45 @@
1
+ // Planu — Shared SVG chart utilities
2
+ /** 8 visually distinct colours for chart series. */
3
+ export const CHART_COLORS = [
4
+ '#e94560',
5
+ '#0891b2',
6
+ '#059669',
7
+ '#d97706',
8
+ '#7c3aed',
9
+ '#6366f1',
10
+ '#0f766e',
11
+ '#b45309',
12
+ '#db2777',
13
+ '#2563eb',
14
+ ];
15
+ /**
16
+ * Create a linear scale function that maps values from [domainMin, domainMax]
17
+ * to [rangeMin, rangeMax].
18
+ */
19
+ export function scaleLinear(domain, range) {
20
+ const [d0, d1] = domain;
21
+ const [r0, r1] = range;
22
+ const domainSpan = d1 - d0;
23
+ if (domainSpan === 0) {
24
+ return () => r0;
25
+ }
26
+ return (val) => r0 + ((val - d0) / domainSpan) * (r1 - r0);
27
+ }
28
+ /** Render an SVG <text> element. */
29
+ export function svgText(x, y, text, opts) {
30
+ const fontSize = opts?.fontSize ?? 12;
31
+ const anchor = opts?.anchor ?? 'start';
32
+ const fill = opts?.fill ?? '#2d3436';
33
+ const escaped = escapeXml(text);
34
+ return `<text x="${x}" y="${y}" font-size="${fontSize}" text-anchor="${anchor}" fill="${fill}">${escaped}</text>`;
35
+ }
36
+ /** Escape XML special chars for safe SVG embedding. */
37
+ export function escapeXml(str) {
38
+ return str
39
+ .replace(/&/g, '&amp;')
40
+ .replace(/</g, '&lt;')
41
+ .replace(/>/g, '&gt;')
42
+ .replace(/"/g, '&quot;')
43
+ .replace(/'/g, '&apos;');
44
+ }
45
+ //# sourceMappingURL=chart-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-utils.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/chart-utils.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,oDAAoD;AACpD,MAAM,CAAC,MAAM,YAAY,GAAa;IACpC,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,MAAwB,EACxB,KAAuB;IAEvB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;IACvB,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,CAAC;IAC3B,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAW,EAAU,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,OAAO,CACrB,CAAS,EACT,CAAS,EACT,IAAY,EACZ,IAA4D;IAE5D,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,OAAO,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,SAAS,CAAC;IACrC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,YAAY,CAAC,QAAQ,CAAC,gBAAgB,QAAQ,kBAAkB,MAAM,WAAW,IAAI,KAAK,OAAO,SAAS,CAAC;AACpH,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { LinePoint, LineChartOptions } from '../../../../types/portal.js';
2
+ /**
3
+ * Build a responsive SVG line chart for one or two series.
4
+ * When a second series is passed via options it is drawn with a dashed line.
5
+ * Returns empty string when points array is empty.
6
+ */
7
+ export declare function buildSvgLineChart(points: LinePoint[], options?: LineChartOptions): string;
8
+ /**
9
+ * Build a dual-series SVG line chart (real vs ideal).
10
+ * Returns empty string when either series is empty.
11
+ */
12
+ export declare function buildSvgDualLineChart(series1: LinePoint[], series2: LinePoint[], options?: LineChartOptions & {
13
+ label1?: string;
14
+ label2?: string;
15
+ }): string;
16
+ //# sourceMappingURL=line-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-chart.d.ts","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/line-chart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAK/E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAgEzF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,EAAE,EACpB,OAAO,EAAE,SAAS,EAAE,EACpB,OAAO,CAAC,EAAE,gBAAgB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,CA4ER"}
@@ -0,0 +1,159 @@
1
+ import { scaleLinear, svgText, CHART_COLORS, escapeXml } from './chart-utils.js';
2
+ const PADDING = { top: 40, right: 20, bottom: 50, left: 50 };
3
+ /**
4
+ * Build a responsive SVG line chart for one or two series.
5
+ * When a second series is passed via options it is drawn with a dashed line.
6
+ * Returns empty string when points array is empty.
7
+ */
8
+ export function buildSvgLineChart(points, options) {
9
+ if (points.length === 0) {
10
+ return '';
11
+ }
12
+ const vbW = options?.width ?? 500;
13
+ const vbH = options?.height ?? 300;
14
+ const title = options?.title ?? '';
15
+ const showDots = options?.showDots ?? true;
16
+ const innerW = vbW - PADDING.left - PADDING.right;
17
+ const innerH = vbH - PADDING.top - PADDING.bottom;
18
+ const xs = points.map((p) => p.x);
19
+ const ys = points.map((p) => p.y);
20
+ const minX = Math.min(...xs);
21
+ const maxX = Math.max(...xs, minX + 1);
22
+ const maxY = Math.max(...ys, 1);
23
+ const xScale = scaleLinear([minX, maxX], [0, innerW]);
24
+ const yScale = scaleLinear([0, maxY], [innerH, 0]);
25
+ const color0 = CHART_COLORS[0] ?? '#e94560';
26
+ const pathD = points
27
+ .map((p, i) => {
28
+ const px = (PADDING.left + xScale(p.x)).toFixed(1);
29
+ const py = (PADDING.top + yScale(p.y)).toFixed(1);
30
+ return `${i === 0 ? 'M' : 'L'} ${px} ${py}`;
31
+ })
32
+ .join(' ');
33
+ const dotsHtml = showDots
34
+ ? points
35
+ .map((p) => {
36
+ const cx = (PADDING.left + xScale(p.x)).toFixed(1);
37
+ const cy = (PADDING.top + yScale(p.y)).toFixed(1);
38
+ const dotLabel = p.label
39
+ ? svgText(Number(cx), Number(cy) - 8, p.label, {
40
+ fontSize: 9,
41
+ anchor: 'middle',
42
+ fill: '#6b7280',
43
+ })
44
+ : '';
45
+ return `<circle cx="${cx}" cy="${cy}" r="4" fill="${escapeXml(color0)}"/>${dotLabel}`;
46
+ })
47
+ .join('\n ')
48
+ : '';
49
+ const yTicks = buildYTicks(maxY, innerW, PADDING, innerH, yScale);
50
+ const xTicks = buildXTicks(points, xScale, PADDING, vbH);
51
+ const titleEl = title
52
+ ? svgText(vbW / 2, 20, title, { fontSize: 13, anchor: 'middle', fill: '#1a1a2e' })
53
+ : '';
54
+ return `<svg viewBox="0 0 ${vbW} ${vbH}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbW}px">
55
+ ${titleEl}
56
+ ${yTicks}
57
+ ${xTicks}
58
+ <path d="${pathD}" fill="none" stroke="${escapeXml(color0)}" stroke-width="2.5" stroke-linejoin="round"/>
59
+ ${dotsHtml}
60
+ <line x1="${PADDING.left}" y1="${PADDING.top}" x2="${PADDING.left}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
61
+ <line x1="${PADDING.left}" y1="${PADDING.top + innerH}" x2="${PADDING.left + innerW}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
62
+ </svg>`;
63
+ }
64
+ /**
65
+ * Build a dual-series SVG line chart (real vs ideal).
66
+ * Returns empty string when either series is empty.
67
+ */
68
+ export function buildSvgDualLineChart(series1, series2, options) {
69
+ if (series1.length === 0 && series2.length === 0) {
70
+ return '';
71
+ }
72
+ const vbW = options?.width ?? 500;
73
+ const vbH = options?.height ?? 300;
74
+ const title = options?.title ?? '';
75
+ const showDots = options?.showDots ?? true;
76
+ const innerW = vbW - PADDING.left - PADDING.right;
77
+ const innerH = vbH - PADDING.top - PADDING.bottom;
78
+ const allPoints = [...series1, ...series2];
79
+ const xs = allPoints.map((p) => p.x);
80
+ const ys = allPoints.map((p) => p.y);
81
+ const minX = Math.min(...xs, 0);
82
+ const maxX = Math.max(...xs, minX + 1);
83
+ const maxY = Math.max(...ys, 1);
84
+ const xScale = scaleLinear([minX, maxX], [0, innerW]);
85
+ const yScale = scaleLinear([0, maxY], [innerH, 0]);
86
+ const color0 = CHART_COLORS[0] ?? '#e94560';
87
+ const color1 = CHART_COLORS[1] ?? '#0891b2';
88
+ const makePath = (pts, color, dashed) => {
89
+ if (pts.length === 0) {
90
+ return '';
91
+ }
92
+ const d = pts
93
+ .map((p, i) => {
94
+ const px = (PADDING.left + xScale(p.x)).toFixed(1);
95
+ const py = (PADDING.top + yScale(p.y)).toFixed(1);
96
+ return `${i === 0 ? 'M' : 'L'} ${px} ${py}`;
97
+ })
98
+ .join(' ');
99
+ const dash = dashed ? ' stroke-dasharray="6 3"' : '';
100
+ return `<path d="${d}" fill="none" stroke="${escapeXml(color)}" stroke-width="2.5" stroke-linejoin="round"${dash}/>`;
101
+ };
102
+ const makeDots = (pts, color) => {
103
+ if (!showDots) {
104
+ return '';
105
+ }
106
+ return pts
107
+ .map((p) => {
108
+ const cx = (PADDING.left + xScale(p.x)).toFixed(1);
109
+ const cy = (PADDING.top + yScale(p.y)).toFixed(1);
110
+ return `<circle cx="${cx}" cy="${cy}" r="3" fill="${escapeXml(color)}"/>`;
111
+ })
112
+ .join('\n ');
113
+ };
114
+ const label1 = options?.label1 ?? 'Real';
115
+ const label2 = options?.label2 ?? 'Ideal';
116
+ const legendY = vbH - 8;
117
+ const legend = `${svgText(PADDING.left, legendY, label1, { fontSize: 10, anchor: 'start', fill: color0 })}
118
+ ${svgText(PADDING.left + 80, legendY, label2, { fontSize: 10, anchor: 'start', fill: color1 })}`;
119
+ const yTicks = buildYTicks(maxY, innerW, PADDING, innerH, yScale);
120
+ const titleEl = title
121
+ ? svgText(vbW / 2, 20, title, { fontSize: 13, anchor: 'middle', fill: '#1a1a2e' })
122
+ : '';
123
+ return `<svg viewBox="0 0 ${vbW} ${vbH}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbW}px">
124
+ ${titleEl}
125
+ ${yTicks}
126
+ ${makePath(series1, color0, false)}
127
+ ${makePath(series2, color1, true)}
128
+ ${makeDots(series1, color0)}
129
+ ${makeDots(series2, color1)}
130
+ ${legend}
131
+ <line x1="${PADDING.left}" y1="${PADDING.top}" x2="${PADDING.left}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
132
+ <line x1="${PADDING.left}" y1="${PADDING.top + innerH}" x2="${PADDING.left + innerW}" y2="${PADDING.top + innerH}" stroke="#e9ecef" stroke-width="1"/>
133
+ </svg>`;
134
+ }
135
+ function buildYTicks(maxVal, innerW, padding, _innerH, yScale) {
136
+ const tickCount = 4;
137
+ return Array.from({ length: tickCount + 1 }, (_, i) => {
138
+ const val = (maxVal / tickCount) * i;
139
+ const y = padding.top + yScale(val);
140
+ const label = Number.isInteger(val) ? String(val) : val.toFixed(1);
141
+ return `<line x1="${padding.left}" y1="${y.toFixed(1)}" x2="${(padding.left + innerW).toFixed(1)}" y2="${y.toFixed(1)}" stroke="#f3f4f6" stroke-width="1"/>
142
+ ${svgText(padding.left - 6, y + 4, label, { fontSize: 9, anchor: 'end', fill: '#9ca3af' })}`;
143
+ }).join('\n ');
144
+ }
145
+ function buildXTicks(points, xScale, padding, vbH) {
146
+ const maxTicks = 6;
147
+ const step = Math.max(1, Math.ceil(points.length / maxTicks));
148
+ return points
149
+ .filter((_, i) => i % step === 0)
150
+ .map((p) => {
151
+ const x = padding.left + xScale(p.x);
152
+ const y = vbH - padding.bottom + 14;
153
+ const lbl = p.label ?? String(p.x);
154
+ const short = lbl.length > 8 ? lbl.slice(0, 7) + '…' : lbl;
155
+ return svgText(x, y, short, { fontSize: 9, anchor: 'middle', fill: '#9ca3af' });
156
+ })
157
+ .join('\n ');
158
+ }
159
+ //# sourceMappingURL=line-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-chart.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/line-chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PieSlice } from '../../../../types/portal.js';
2
+ /**
3
+ * Build a responsive SVG pie chart.
4
+ * Returns empty string when slices array is empty or all values are zero.
5
+ */
6
+ export declare function buildSvgPieChart(slices: PieSlice[], size?: number): string;
7
+ //# sourceMappingURL=pie-chart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie-chart.d.ts","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/pie-chart.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAG5D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA0D1E"}
@@ -0,0 +1,52 @@
1
+ import { svgText, escapeXml } from './chart-utils.js';
2
+ /**
3
+ * Build a responsive SVG pie chart.
4
+ * Returns empty string when slices array is empty or all values are zero.
5
+ */
6
+ export function buildSvgPieChart(slices, size) {
7
+ if (slices.length === 0) {
8
+ return '';
9
+ }
10
+ const total = slices.reduce((s, p) => s + p.value, 0);
11
+ if (total === 0) {
12
+ return '';
13
+ }
14
+ const vbSize = size ?? 220;
15
+ const cx = vbSize / 2;
16
+ const cy = vbSize / 2;
17
+ const r = (vbSize / 2) * 0.65;
18
+ let startAngle = -Math.PI / 2; // start at top
19
+ const paths = [];
20
+ for (const slice of slices) {
21
+ const angle = (slice.value / total) * 2 * Math.PI;
22
+ const endAngle = startAngle + angle;
23
+ const largeArc = angle > Math.PI ? 1 : 0;
24
+ const x1 = cx + r * Math.cos(startAngle);
25
+ const y1 = cy + r * Math.sin(startAngle);
26
+ const x2 = cx + r * Math.cos(endAngle);
27
+ const y2 = cy + r * Math.sin(endAngle);
28
+ const d = [
29
+ `M ${cx.toFixed(1)} ${cy.toFixed(1)}`,
30
+ `L ${x1.toFixed(2)} ${y1.toFixed(2)}`,
31
+ `A ${r.toFixed(1)} ${r.toFixed(1)} 0 ${largeArc} 1 ${x2.toFixed(2)} ${y2.toFixed(2)}`,
32
+ 'Z',
33
+ ].join(' ');
34
+ paths.push(`<path d="${d}" fill="${escapeXml(slice.color)}" stroke="white" stroke-width="1.5"/>`);
35
+ startAngle = endAngle;
36
+ }
37
+ // Legend below the pie
38
+ const legendItems = slices.map((s, i) => {
39
+ const lx = 8;
40
+ const ly = vbSize + 14 + i * 16;
41
+ const pct = ((s.value / total) * 100).toFixed(1);
42
+ const short = s.label.length > 20 ? s.label.slice(0, 19) + '…' : s.label;
43
+ return `<rect x="${lx}" y="${ly - 9}" width="10" height="10" fill="${escapeXml(s.color)}" rx="2"/>
44
+ ${svgText(lx + 14, ly, `${short}: ${pct}%`, { fontSize: 10, anchor: 'start', fill: '#4b5563' })}`;
45
+ });
46
+ const totalHeight = vbSize + 14 + slices.length * 16;
47
+ return `<svg viewBox="0 0 ${vbSize} ${totalHeight}" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:${vbSize}px">
48
+ ${paths.join('\n ')}
49
+ ${legendItems.join('\n ')}
50
+ </svg>`;
51
+ }
52
+ //# sourceMappingURL=pie-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie-chart.js","sourceRoot":"","sources":["../../../../../src/engine/doc-generator/portal/svg-charts/pie-chart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Spec } from '../../../types/index.js';
2
+ import type { ProposalPhase } from '../../../types/docs.js';
3
+ /**
4
+ * Build a CSS Grid Gantt chart from specs and optional phases.
5
+ * Returns an HTML string with the full Gantt visualization.
6
+ */
7
+ export declare function buildGanttChart(specs: Spec[], phases?: ProposalPhase[], _startDate?: string): string;
8
+ //# sourceMappingURL=proposal-gantt-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-gantt-builder.d.ts","sourceRoot":"","sources":["../../../../src/engine/doc-generator/proposal/proposal-gantt-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,wBAAwB,CAAC;AA6FtE;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,CAAC,EAAE,aAAa,EAAE,EACxB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAyCR"}