88 localizedGuidance ,
99} from './grip.js' ;
1010import { t } from '../i18n/strings.js' ;
11+ import { entryForCode , hasSelfEvaluation } from './assessment.js' ;
1112
1213// ─── Colour palette (mirrors CSS variables) ──────────────────────────────────
1314const COLORS = {
@@ -53,8 +54,10 @@ function dateLocale(lang) {
5354}
5455
5556// Builds the Markdown body for a single measure, mirroring the detail shown in
56- // the app and the PDF/PPTX exports.
57- function measureMarkdown ( measure , lang ) {
57+ // the app and the PDF/PPTX exports. When an assessment state is supplied the
58+ // user's self-evaluation (status + note) is rendered just below the summary,
59+ // matching the on-screen ordering.
60+ function measureMarkdown ( measure , lang , assessment ) {
5861 const lines = [ ] ;
5962 const title = localized ( measure , 'title' , lang ) ;
6063 const typeLabel =
@@ -71,6 +74,26 @@ function measureMarkdown(measure, lang) {
7174 lines . push ( localized ( measure , 'summary' , lang ) ) ;
7275 lines . push ( '' ) ;
7376
77+ // Self-evaluation (user-provided status + note)
78+ if ( assessment ) {
79+ const entry = entryForCode ( assessment , measure . code ) ;
80+ lines . push ( `### ${ t ( lang , 'selfEvaluationTitle' ) } ` ) ;
81+ lines . push ( '' ) ;
82+ if ( hasSelfEvaluation ( entry ) ) {
83+ lines . push (
84+ `**${ t ( lang , 'assessmentStatusLabel' ) } :** ${ t ( lang , `status_${ entry . status } ` ) } `
85+ ) ;
86+ lines . push ( '' ) ;
87+ if ( entry . note && entry . note . trim ( ) !== '' ) {
88+ lines . push ( `**${ t ( lang , 'assessmentNoteLabel' ) } :** ${ entry . note . trim ( ) } ` ) ;
89+ lines . push ( '' ) ;
90+ }
91+ } else {
92+ lines . push ( `_${ t ( lang , 'selfEvaluationNone' ) } _` ) ;
93+ lines . push ( '' ) ;
94+ }
95+ }
96+
7497 // Practical guidance
7598 const guidance = localizedGuidance ( measure , lang ) ;
7699 if ( guidance ) {
@@ -159,8 +182,10 @@ function measureMarkdown(measure, lang) {
159182 * triggers a client-side download. No data leaves the browser.
160183 *
161184 * @param {string } lang Active UI language ('nl' | 'en' | 'fr')
185+ * @param {object } [assessment] Optional self-evaluation state (state.measures
186+ * keyed by measure code) whose status/note are rendered per measure.
162187 */
163- export function exportMarkdown ( lang ) {
188+ export function exportMarkdown ( lang , assessment ) {
164189 const measures = getMeasures ( ) ;
165190 const today = new Date ( ) . toLocaleDateString ( dateLocale ( lang ) , {
166191 year : 'numeric' ,
@@ -175,7 +200,7 @@ export function exportMarkdown(lang) {
175200 '' ,
176201 today ,
177202 '' ,
178- ...measures . map ( ( measure ) => measureMarkdown ( measure , lang ) ) ,
203+ ...measures . map ( ( measure ) => measureMarkdown ( measure , lang , assessment ) ) ,
179204 ] ;
180205
181206 const markdown = parts . join ( '\n' ) ;
@@ -261,6 +286,57 @@ function guidanceRuns(measure, lang) {
261286 return runs ;
262287}
263288
289+ // Builds the stacked text runs for the self-evaluation block (status + note).
290+ function selfEvaluationRuns ( entry , lang ) {
291+ const runs = [
292+ {
293+ text : t ( lang , 'selfEvaluationTitle' ) ,
294+ options : {
295+ bold : true ,
296+ fontSize : 13 ,
297+ color : COLORS . accentInk ,
298+ breakLine : true ,
299+ paraSpaceBefore : 8 ,
300+ } ,
301+ } ,
302+ ] ;
303+
304+ if ( ! hasSelfEvaluation ( entry ) ) {
305+ runs . push ( {
306+ text : t ( lang , 'selfEvaluationNone' ) ,
307+ options : { italic : true , fontSize : 11 , color : COLORS . inkFaint , breakLine : true } ,
308+ } ) ;
309+ return runs ;
310+ }
311+
312+ runs . push ( {
313+ text : `${ t ( lang , 'assessmentStatusLabel' ) } : ` ,
314+ options : { bold : true , fontSize : 11 , color : COLORS . ink } ,
315+ } ) ;
316+ runs . push ( {
317+ text : t ( lang , `status_${ entry . status } ` ) ,
318+ options : {
319+ fontSize : 11 ,
320+ color : COLORS . inkSoft ,
321+ breakLine : true ,
322+ paraSpaceAfter : 4 ,
323+ } ,
324+ } ) ;
325+
326+ if ( entry . note && entry . note . trim ( ) !== '' ) {
327+ runs . push ( {
328+ text : `${ t ( lang , 'assessmentNoteLabel' ) } : ` ,
329+ options : { bold : true , fontSize : 11 , color : COLORS . ink } ,
330+ } ) ;
331+ runs . push ( {
332+ text : entry . note . trim ( ) ,
333+ options : { fontSize : 11 , color : COLORS . inkSoft , breakLine : true } ,
334+ } ) ;
335+ }
336+
337+ return runs ;
338+ }
339+
264340// Builds the stacked text runs for the right "mapping + standards" column.
265341function mappingRuns ( measure , lang ) {
266342 const runs = [
@@ -382,8 +458,10 @@ function mappingRuns(measure, lang) {
382458 * documentation links, and the standards mapping with control references.
383459 *
384460 * @param {string } lang Active UI language ('nl' | 'en' | 'fr')
461+ * @param {object } [assessment] Optional self-evaluation state (state.measures
462+ * keyed by measure code) whose status/note are rendered per measure slide.
385463 */
386- export async function exportPPTX ( lang ) {
464+ export async function exportPPTX ( lang , assessment ) {
387465 const measures = getMeasures ( ) ;
388466 const pptx = new PptxGenJS ( ) ;
389467
@@ -535,8 +613,12 @@ export async function exportPPTX(lang) {
535613 fit : 'shrink' ,
536614 } ) ;
537615
538- // Left column — practical guidance
539- slide . addText ( guidanceRuns ( measure , lang ) , {
616+ // Left column — practical guidance (plus self-evaluation when present)
617+ const leftRuns = guidanceRuns ( measure , lang ) ;
618+ if ( assessment ) {
619+ leftRuns . push ( ...selfEvaluationRuns ( entryForCode ( assessment , measure . code ) , lang ) ) ;
620+ }
621+ slide . addText ( leftRuns , {
540622 x : 0.35 ,
541623 y : 2.12 ,
542624 w : 6.1 ,
0 commit comments