@jjlmoya/utils-civic 1.7.0 → 1.9.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 (94) hide show
  1. package/.github/workflows/ci.yml +103 -0
  2. package/.gitignore +1 -0
  3. package/package.json +17 -5
  4. package/scripts/postinstall.mjs +2 -4
  5. package/src/category/index.ts +3 -1
  6. package/src/components/ProductionBreadcrumb.astro +132 -0
  7. package/src/components/ProductionWidget.astro +182 -0
  8. package/src/entries.ts +4 -0
  9. package/src/i18n/header-ui.ts +15 -0
  10. package/src/i18n/language-ui.ts +9 -0
  11. package/src/i18n/languages.ts +24 -0
  12. package/src/identity/brands.ts +5 -0
  13. package/src/index.ts +1 -0
  14. package/src/layouts/ProductionCategoryPage.astro +184 -0
  15. package/src/layouts/ProductionPage.astro +209 -0
  16. package/src/layouts/ProductionUtilityPage.astro +235 -0
  17. package/src/mfe/assets.ts +15 -0
  18. package/src/mfe/category-ui.ts +25 -0
  19. package/src/mfe/routes.ts +50 -0
  20. package/src/pages/[locale]/[utilities]/[categories]/[category]/[slug].astro +100 -0
  21. package/src/pages/[locale]/[utilities]/[categories]/[category].astro +44 -0
  22. package/src/pages/index.astro +1 -1
  23. package/src/pages/utilidades/[slug].astro +90 -0
  24. package/src/pages/utilidades/categorias/[category].astro +38 -0
  25. package/src/tests/locale_completeness.test.ts +1 -1
  26. package/src/tests/tool_validation.test.ts +1 -1
  27. package/src/tests/translation_copy.test.ts +1 -1
  28. package/src/tool/access-to-information-request-builder/access-to-information-request-builder.css +577 -0
  29. package/src/tool/access-to-information-request-builder/bibliography.astro +6 -0
  30. package/src/tool/access-to-information-request-builder/bibliography.ts +6 -0
  31. package/src/tool/access-to-information-request-builder/component.astro +106 -0
  32. package/src/tool/access-to-information-request-builder/contract.test.ts +17 -0
  33. package/src/tool/access-to-information-request-builder/controller.ts +135 -0
  34. package/src/tool/access-to-information-request-builder/dom-views.ts +59 -0
  35. package/src/tool/access-to-information-request-builder/entry.ts +27 -0
  36. package/src/tool/access-to-information-request-builder/evaluator.ts +27 -0
  37. package/src/tool/access-to-information-request-builder/i18n/de.ts +52 -0
  38. package/src/tool/access-to-information-request-builder/i18n/en.ts +76 -0
  39. package/src/tool/access-to-information-request-builder/i18n/es.ts +52 -0
  40. package/src/tool/access-to-information-request-builder/i18n/fr.ts +50 -0
  41. package/src/tool/access-to-information-request-builder/i18n/id.ts +50 -0
  42. package/src/tool/access-to-information-request-builder/i18n/it.ts +50 -0
  43. package/src/tool/access-to-information-request-builder/i18n/ja.ts +50 -0
  44. package/src/tool/access-to-information-request-builder/i18n/ko.ts +50 -0
  45. package/src/tool/access-to-information-request-builder/i18n/nl.ts +49 -0
  46. package/src/tool/access-to-information-request-builder/i18n/pl.ts +49 -0
  47. package/src/tool/access-to-information-request-builder/i18n/pt.ts +49 -0
  48. package/src/tool/access-to-information-request-builder/i18n/ru.ts +49 -0
  49. package/src/tool/access-to-information-request-builder/i18n/sv.ts +49 -0
  50. package/src/tool/access-to-information-request-builder/i18n/tr.ts +49 -0
  51. package/src/tool/access-to-information-request-builder/i18n/zh.ts +49 -0
  52. package/src/tool/access-to-information-request-builder/index.ts +11 -0
  53. package/src/tool/access-to-information-request-builder/logic.test.ts +68 -0
  54. package/src/tool/access-to-information-request-builder/logic.ts +138 -0
  55. package/src/tool/access-to-information-request-builder/seo.astro +15 -0
  56. package/src/tool/access-to-information-request-builder/storage.ts +27 -0
  57. package/src/tool/access-to-information-request-builder/ui.ts +154 -0
  58. package/src/tool/access-to-information-request-builder/validation.ts +7 -0
  59. package/src/tool/parliamentary-voting-analyzer/bibliography.astro +14 -0
  60. package/src/tool/parliamentary-voting-analyzer/bibliography.ts +6 -0
  61. package/src/tool/parliamentary-voting-analyzer/component.astro +63 -0
  62. package/src/tool/parliamentary-voting-analyzer/contract.test.ts +16 -0
  63. package/src/tool/parliamentary-voting-analyzer/controller.ts +65 -0
  64. package/src/tool/parliamentary-voting-analyzer/dom-views.ts +63 -0
  65. package/src/tool/parliamentary-voting-analyzer/entry.ts +27 -0
  66. package/src/tool/parliamentary-voting-analyzer/evaluator.ts +12 -0
  67. package/src/tool/parliamentary-voting-analyzer/i18n/de.ts +45 -0
  68. package/src/tool/parliamentary-voting-analyzer/i18n/en.ts +79 -0
  69. package/src/tool/parliamentary-voting-analyzer/i18n/es.ts +49 -0
  70. package/src/tool/parliamentary-voting-analyzer/i18n/fr.ts +43 -0
  71. package/src/tool/parliamentary-voting-analyzer/i18n/id.ts +45 -0
  72. package/src/tool/parliamentary-voting-analyzer/i18n/it.ts +45 -0
  73. package/src/tool/parliamentary-voting-analyzer/i18n/ja.ts +45 -0
  74. package/src/tool/parliamentary-voting-analyzer/i18n/ko.ts +45 -0
  75. package/src/tool/parliamentary-voting-analyzer/i18n/nl.ts +45 -0
  76. package/src/tool/parliamentary-voting-analyzer/i18n/pl.ts +45 -0
  77. package/src/tool/parliamentary-voting-analyzer/i18n/pt.ts +45 -0
  78. package/src/tool/parliamentary-voting-analyzer/i18n/ru.ts +45 -0
  79. package/src/tool/parliamentary-voting-analyzer/i18n/sv.ts +45 -0
  80. package/src/tool/parliamentary-voting-analyzer/i18n/tr.ts +45 -0
  81. package/src/tool/parliamentary-voting-analyzer/i18n/zh.ts +45 -0
  82. package/src/tool/parliamentary-voting-analyzer/index.ts +11 -0
  83. package/src/tool/parliamentary-voting-analyzer/logic.test.ts +52 -0
  84. package/src/tool/parliamentary-voting-analyzer/logic.ts +279 -0
  85. package/src/tool/parliamentary-voting-analyzer/parliamentary-voting-analyzer.css +491 -0
  86. package/src/tool/parliamentary-voting-analyzer/seo.astro +14 -0
  87. package/src/tool/parliamentary-voting-analyzer/storage.ts +25 -0
  88. package/src/tool/parliamentary-voting-analyzer/ui.ts +98 -0
  89. package/src/tools.ts +4 -0
  90. package/src/types.ts +2 -4
  91. package/src/worker.ts +9 -0
  92. package/tsconfig.json +14 -5
  93. package/src/pages/[locale]/[slug].astro +0 -166
  94. package/src/pages/[locale].astro +0 -253
@@ -0,0 +1,577 @@
1
+ main {
2
+ min-width: 0;
3
+ }
4
+
5
+ .access-request-builder {
6
+ --n-paper: #fffdf7;
7
+ --n-ink: #17252a;
8
+ --n-muted: #5c6c70;
9
+ --n-line: #d8dfda;
10
+ --n-accent: #b64c35;
11
+ --n-accent-soft: #f5e4dc;
12
+ --n-teal: #1d6c6a;
13
+ --n-teal-soft: #dceeea;
14
+ --n-warning: #8c5a18;
15
+ --n-warning-soft: #f9eed5;
16
+ --n-on-accent: #fff;
17
+ --n-paper-tint: #fbf3eb;
18
+
19
+
20
+ display: grid;
21
+ gap: 1.25rem;
22
+ color: var(--n-ink);
23
+ }
24
+
25
+ .theme-dark .access-request-builder {
26
+ --n-paper: #1c2425;
27
+ --n-ink: #f4f0e6;
28
+ --n-muted: #b4c1bc;
29
+ --n-line: #40504e;
30
+ --n-accent: #f08262;
31
+ --n-accent-soft: #482c27;
32
+ --n-teal: #75d1c4;
33
+ --n-teal-soft: #203d3a;
34
+ --n-warning: #f2c56d;
35
+ --n-warning-soft: #46351d;
36
+ --n-on-accent: #17252a;
37
+ --n-paper-tint: #2b2825;
38
+ }
39
+
40
+ .request-workbench,
41
+ .request-result,
42
+ .request-guidance {
43
+ background: var(--n-paper);
44
+ border: 1px solid var(--n-line);
45
+ border-radius: 1.25rem;
46
+ }
47
+
48
+ .request-workbench {
49
+ overflow: visible;
50
+ box-shadow: 0 1rem 2rem rgba(23, 37, 42, 0.08);
51
+ }
52
+
53
+ .request-intro {
54
+ display: flex;
55
+ justify-content: space-between;
56
+ gap: 2rem;
57
+ padding: 2rem 2.25rem 1.5rem;
58
+ border-bottom: 1px solid var(--n-line);
59
+ }
60
+
61
+ .request-intro h2 {
62
+ max-width: 30rem;
63
+ margin: .35rem 0 0;
64
+ font-size: clamp(1.5rem, 3vw, 2.35rem);
65
+ line-height: 1.05;
66
+ letter-spacing: -.04em;
67
+ }
68
+
69
+ .request-intro p {
70
+ max-width: 20rem;
71
+ margin: 1.4rem 0 0;
72
+ color: var(--n-muted);
73
+ line-height: 1.55;
74
+ }
75
+
76
+ .eyebrow {
77
+ color: var(--n-accent);
78
+ font-size: .7rem;
79
+ font-weight: 800;
80
+ letter-spacing: .16em;
81
+ text-transform: uppercase;
82
+ }
83
+
84
+ .preset-row {
85
+ display: flex;
86
+ flex-wrap: wrap;
87
+ align-items: center;
88
+ gap: .55rem;
89
+ padding: .9rem 2.25rem;
90
+ background: var(--n-accent-soft);
91
+ color: var(--n-accent);
92
+ font-size: .82rem;
93
+ font-weight: 700;
94
+ }
95
+
96
+ .preset-row button,
97
+ .text-action,
98
+ .secondary-action,
99
+ .output-actions button {
100
+ border: 1px solid var(--n-line);
101
+ border-radius: 999px;
102
+ padding: .55rem .8rem;
103
+ background: var(--n-paper);
104
+ color: var(--n-ink);
105
+ cursor: pointer;
106
+ font: inherit;
107
+ }
108
+
109
+ .preset-row button:hover,
110
+ .text-action:hover,
111
+ .secondary-action:hover,
112
+ .output-actions button:hover {
113
+ border-color: var(--n-accent);
114
+ color: var(--n-accent);
115
+ }
116
+
117
+ .request-flow {
118
+ display: grid;
119
+ grid-template-columns: repeat(3, 1fr);
120
+ }
121
+
122
+ .flow-section {
123
+ min-width: 0;
124
+ padding: 1.5rem 1.5rem 1.75rem;
125
+ border-right: 1px solid var(--n-line);
126
+ }
127
+
128
+ .flow-section:last-child {
129
+ border-right: 0;
130
+ }
131
+
132
+ .section-marker {
133
+ color: var(--n-accent);
134
+ font-size: .75rem;
135
+ font-weight: 800;
136
+ letter-spacing: .1em;
137
+ }
138
+
139
+ .section-heading {
140
+ display: flex;
141
+ align-items: baseline;
142
+ justify-content: space-between;
143
+ gap: .75rem;
144
+ margin: .45rem 0 1.2rem;
145
+ }
146
+
147
+ .section-heading h3 {
148
+ margin: 0;
149
+ font-size: 1.05rem;
150
+ }
151
+
152
+ .section-heading span {
153
+ color: var(--n-muted);
154
+ font-size: .72rem;
155
+ }
156
+
157
+ .section-content > label,
158
+ .field-label,
159
+ .period-fieldset legend,
160
+ .request-notes > label {
161
+ display: block;
162
+ margin: .9rem 0 .35rem;
163
+ color: var(--n-muted);
164
+ font-size: .75rem;
165
+ font-weight: 750;
166
+ }
167
+
168
+ .access-request-builder input[type="text"],
169
+ .access-request-builder input[type="date"],
170
+ .access-request-builder textarea,
171
+ .format-trigger {
172
+ width: 100%;
173
+ border: 1px solid var(--n-line);
174
+ border-radius: .55rem;
175
+ padding: .7rem .75rem;
176
+ background: transparent;
177
+ color: var(--n-ink);
178
+ font: inherit;
179
+ line-height: 1.35;
180
+ }
181
+
182
+ .access-request-builder textarea {
183
+ resize: vertical;
184
+ }
185
+ .access-request-builder input:focus,
186
+ .access-request-builder textarea:focus,
187
+ .format-trigger:focus {
188
+ outline: 2px solid var(--n-teal);
189
+ outline-offset: 2px;
190
+ }
191
+
192
+ .request-line + .request-line {
193
+ margin-top: 1rem;
194
+ }
195
+
196
+ .request-line label {
197
+ display: block;
198
+ margin-bottom: .35rem;
199
+ color: var(--n-muted);
200
+ font-size: .75rem;
201
+ font-weight: 750;
202
+ }
203
+
204
+ .request-line button {
205
+ margin-top: .35rem;
206
+ border: 0;
207
+ background: transparent;
208
+ color: var(--n-accent);
209
+ cursor: pointer;
210
+ font: inherit;
211
+ font-size: .75rem;
212
+ }
213
+
214
+ .text-action {
215
+ margin-top: 1rem;
216
+ border: 0;
217
+ padding-left: 0;
218
+ background: transparent;
219
+ color: var(--n-teal);
220
+ font-size: .82rem;
221
+ font-weight: 750;
222
+ }
223
+
224
+ .period-fieldset {
225
+ margin: 0;
226
+ padding: 0;
227
+ border: 0;
228
+ }
229
+
230
+ .date-grid {
231
+ display: grid;
232
+ grid-template-columns: 1fr 1fr;
233
+ gap: .6rem;
234
+ }
235
+
236
+ .date-grid label {
237
+ color: var(--n-muted);
238
+ font-size: .72rem;
239
+ }
240
+
241
+ .date-grid input {
242
+ margin-top: .35rem;
243
+ }
244
+
245
+ .format-picker {
246
+ position: relative;
247
+ }
248
+
249
+ .format-trigger {
250
+ display: flex;
251
+ justify-content: space-between;
252
+ text-align: left;
253
+ cursor: pointer;
254
+ }
255
+
256
+ .format-trigger::after {
257
+ content: '⌄';
258
+ color: var(--n-accent);
259
+ }
260
+
261
+ .format-menu {
262
+ position: absolute;
263
+ z-index: 3;
264
+ top: 100%;
265
+ right: 0;
266
+ left: 0;
267
+ display: grid;
268
+ margin-top: .3rem;
269
+ border: 1px solid var(--n-line);
270
+ border-radius: .55rem;
271
+ background: var(--n-paper);
272
+ box-shadow: 0 .8rem 1.5rem rgba(23, 37, 42, 0.15);
273
+ }
274
+
275
+ .format-menu[hidden] {
276
+ display: none;
277
+ }
278
+
279
+ .format-menu button {
280
+ border: 0;
281
+ border-bottom: 1px solid var(--n-line);
282
+ padding: .65rem .75rem;
283
+ background: transparent;
284
+ color: var(--n-ink);
285
+ text-align: left;
286
+ cursor: pointer;
287
+ font: inherit;
288
+ font-size: .82rem;
289
+ }
290
+
291
+ .format-menu button:last-child {
292
+ border-bottom: 0;
293
+ }
294
+ .format-menu button:hover,
295
+ .format-menu button[aria-selected="true"] {
296
+ background: var(--n-teal-soft);
297
+ color: var(--n-teal);
298
+ }
299
+
300
+ .request-notes {
301
+ display: grid;
302
+ grid-template-columns: 1fr 1fr;
303
+ gap: 1rem;
304
+ padding: 1.25rem 2.25rem;
305
+ border-top: 1px solid var(--n-line);
306
+ }
307
+
308
+ .request-notes > label {
309
+ margin: 0;
310
+ }
311
+
312
+ .request-notes .check-row {
313
+ display: flex;
314
+ align-items: center;
315
+ gap: .5rem;
316
+ color: var(--n-ink);
317
+ font-size: .78rem;
318
+ font-weight: 500;
319
+ }
320
+
321
+ .check-row input {
322
+ accent-color: var(--n-teal);
323
+ }
324
+
325
+ .request-actions {
326
+ display: flex;
327
+ gap: .7rem;
328
+ padding: 0 2.25rem 1.75rem;
329
+ }
330
+
331
+ .primary-action {
332
+ border: 0;
333
+ border-radius: .55rem;
334
+ padding: .8rem 1rem;
335
+ background: var(--n-teal);
336
+ color: var(--n-on-accent);
337
+ cursor: pointer;
338
+ font: inherit;
339
+ font-weight: 800;
340
+ }
341
+
342
+ .secondary-action {
343
+ border-radius: .55rem;
344
+ }
345
+
346
+ .request-result {
347
+ overflow: hidden;
348
+ }
349
+
350
+ .request-output {
351
+ padding: 1.5rem 2rem;
352
+ }
353
+
354
+ .output-heading {
355
+ display: flex;
356
+ justify-content: space-between;
357
+ gap: 1.5rem;
358
+ align-items: start;
359
+ }
360
+
361
+ .output-heading p {
362
+ max-width: 38rem;
363
+ margin: .4rem 0 0;
364
+ color: var(--n-muted);
365
+ font-size: .86rem;
366
+ line-height: 1.45;
367
+ }
368
+
369
+ .output-actions {
370
+ display: flex;
371
+ flex-wrap: wrap;
372
+ gap: .5rem;
373
+ justify-content: end;
374
+ }
375
+
376
+ .output-actions button {
377
+ border-radius: .45rem;
378
+ font-size: .78rem;
379
+ }
380
+
381
+ .output-actions button:disabled {
382
+ cursor: not-allowed;
383
+ opacity: .45;
384
+ }
385
+
386
+ .request-markdown {
387
+ display: block;
388
+ margin: 1.25rem 0 0;
389
+ padding: 1.25rem;
390
+ overflow-x: auto;
391
+ min-height: 22rem;
392
+ border-left: 3px solid var(--n-accent);
393
+ background: var(--n-paper-tint);
394
+ color: var(--n-ink);
395
+ font: .86rem/1.65 ui-monospace, SFMono-Regular, Consolas, monospace;
396
+ white-space: pre-wrap;
397
+ resize: vertical;
398
+ }
399
+
400
+ .request-empty {
401
+ margin: 1.25rem 0 0;
402
+ padding: 1.25rem;
403
+ border: 1px dashed var(--n-line);
404
+ color: var(--n-muted);
405
+ }
406
+
407
+ .copy-confirmation {
408
+ margin: .7rem 0 0;
409
+ color: var(--n-teal);
410
+ font-size: .8rem;
411
+ font-weight: 700;
412
+ }
413
+
414
+ .trace-strip {
415
+ display: grid;
416
+ grid-template-columns: 1fr 2fr;
417
+ gap: 1.5rem;
418
+ padding: 1.35rem 2rem;
419
+ border-top: 1px solid var(--n-line);
420
+ background: var(--n-teal-soft);
421
+ }
422
+
423
+ .trace-heading {
424
+ display: grid;
425
+ align-content: start;
426
+ gap: .45rem;
427
+ }
428
+
429
+ .trace-heading strong {
430
+ font-size: .88rem;
431
+ line-height: 1.35;
432
+ }
433
+
434
+ .trail-checklist {
435
+ display: grid;
436
+ grid-template-columns: repeat(2, 1fr);
437
+ gap: .55rem;
438
+ margin: 0;
439
+ padding: 0;
440
+ list-style: none;
441
+ }
442
+
443
+ .trail-check {
444
+ display: grid;
445
+ grid-template-columns: 1.2rem 1fr;
446
+ align-items: center;
447
+ gap: .35rem;
448
+ color: var(--n-ink);
449
+ font-size: .76rem;
450
+ }
451
+
452
+ .trail-check > span:first-child {
453
+ display: grid;
454
+ place-items: center;
455
+ width: 1.1rem;
456
+ height: 1.1rem;
457
+ border-radius: 50%;
458
+ background: var(--n-paper);
459
+ color: var(--n-muted);
460
+ font-weight: 800;
461
+ }
462
+
463
+ .trail-check-complete > span:first-child,
464
+ .trail-check-caution > span:first-child {
465
+ color: var(--n-on-accent);
466
+ }
467
+
468
+ .trail-check-complete > span:first-child {
469
+ background: var(--n-teal);
470
+ }
471
+
472
+ .trail-check-caution > span:first-child {
473
+ background: var(--n-warning);
474
+ }
475
+
476
+ .trail-check strong {
477
+ grid-column: 2;
478
+ color: var(--n-muted);
479
+ font-size: .65rem;
480
+ text-transform: uppercase;
481
+ }
482
+
483
+ .trail-warnings {
484
+ grid-column: 1 / -1;
485
+ border-top: 1px solid var(--n-line);
486
+ padding-top: .8rem;
487
+ }
488
+
489
+ .trail-warnings-title {
490
+ margin: 0 0 .35rem;
491
+ color: var(--n-warning);
492
+ font-size: .75rem;
493
+ font-weight: 800;
494
+ }
495
+
496
+ .trail-warnings ul {
497
+ display: flex;
498
+ flex-wrap: wrap;
499
+ gap: .45rem 1.2rem;
500
+ margin: 0;
501
+ padding-left: 1rem;
502
+ color: var(--n-ink);
503
+ font-size: .75rem;
504
+ }
505
+
506
+ .request-guidance {
507
+ display: grid;
508
+ grid-template-columns: repeat(3, 1fr);
509
+ }
510
+
511
+ .request-guidance section {
512
+ padding: 1.25rem 1.5rem;
513
+ border-right: 1px solid var(--n-line);
514
+ }
515
+
516
+ .request-guidance section:last-child {
517
+ border-right: 0;
518
+ }
519
+
520
+ .request-guidance h2 {
521
+ margin: 0 0 .55rem;
522
+ font-size: 1rem;
523
+ }
524
+
525
+ .request-guidance p {
526
+ margin: 0;
527
+ color: var(--n-muted);
528
+ font-size: .82rem;
529
+ line-height: 1.55;
530
+ }
531
+
532
+ @media (max-width: 850px) {
533
+ .request-flow,
534
+ .request-guidance { grid-template-columns: 1fr; }
535
+ .flow-section,
536
+ .request-guidance section {
537
+ border-right: 0;
538
+ border-bottom: 1px solid var(--n-line);
539
+ }
540
+ .flow-section:last-child,
541
+ .request-guidance section:last-child { border-bottom: 0; }
542
+ .request-intro,
543
+ .output-heading { display: grid; }
544
+ .output-actions { justify-content: start; }
545
+ .trace-strip { grid-template-columns: 1fr; }
546
+ }
547
+
548
+ @media (max-width: 560px) {
549
+ .request-intro,
550
+ .preset-row,
551
+ .request-notes,
552
+ .request-actions,
553
+ .request-output,
554
+ .trace-strip {
555
+ padding-right: 1rem;
556
+ padding-left: 1rem;
557
+ }
558
+ .request-notes { grid-template-columns: 1fr; }
559
+ .trail-checklist { grid-template-columns: 1fr; }
560
+ }
561
+
562
+ @media print {
563
+ .request-workbench,
564
+ .request-guidance,
565
+ .trace-strip,
566
+ .output-actions,
567
+ .copy-confirmation { display: none; }
568
+ .request-result {
569
+ border: 0;
570
+ box-shadow: none;
571
+ }
572
+
573
+ .request-markdown {
574
+ border: 0;
575
+ background: transparent;
576
+ }
577
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography } from '@jjlmoya/utils-shared';
3
+ import { bibliography } from './bibliography';
4
+ ---
5
+
6
+ <Bibliography links={bibliography} />
@@ -0,0 +1,6 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ { name: 'Information Commissioner\'s Office, How to write an effective request for information', url: 'https://ico.org.uk/for-the-public/official-information/preparing-and-submitting-your-information-request/' },
5
+ { name: 'CNIL, Droit d\'accès aux documents administratifs', url: 'https://www.cnil.fr/fr/definition/droit-dacces-aux-documents-administratifs' },
6
+ ];
@@ -0,0 +1,106 @@
1
+ ---
2
+ import type { AccessRequestUI } from './ui';
3
+
4
+ interface Props {
5
+ ui: AccessRequestUI;
6
+ }
7
+
8
+ const { ui } = Astro.props as Props;
9
+ ---
10
+
11
+ <div class="access-request-builder" data-access-request-builder>
12
+ <div class="request-workbench">
13
+ <div class="request-intro">
14
+ <div>
15
+ <span class="eyebrow">{ui.eyebrow}</span>
16
+ <h2>{ui.introHeading}</h2>
17
+ </div>
18
+ <p>{ui.introText}</p>
19
+ </div>
20
+
21
+ <div class="preset-row" aria-label={ui.presetLabel}>
22
+ <span>{ui.presetLabel}</span>
23
+ <button type="button" data-preset="records">{ui.presetRecords}</button>
24
+ <button type="button" data-preset="spending">{ui.presetSpending}</button>
25
+ <button type="button" data-preset="meetings">{ui.presetMeetings}</button>
26
+ </div>
27
+
28
+ <div class="request-flow">
29
+ <section class="flow-section flow-target">
30
+ <div class="section-marker">01</div>
31
+ <div class="section-content">
32
+ <div class="section-heading"><h3>{ui.targetHeading}</h3><span>{ui.targetPrompt}</span></div>
33
+ <label for="request-recipient">{ui.recipientLabel}</label>
34
+ <input id="request-recipient" data-field="recipient" type="text" placeholder={ui.recipientPlaceholder} />
35
+ <label for="request-subject">{ui.subjectLabel}</label>
36
+ <input id="request-subject" data-field="subject" type="text" placeholder={ui.subjectPlaceholder} />
37
+ </div>
38
+ </section>
39
+
40
+ <section class="flow-section flow-question">
41
+ <div class="section-marker">02</div>
42
+ <div class="section-content">
43
+ <div class="section-heading"><h3>{ui.itemsLabel}</h3><span>{ui.questionPrompt}</span></div>
44
+ <div data-request-lines class="request-lines">
45
+ <div class="request-line">
46
+ <label for="request-item-0">{ui.itemNumber} 1</label>
47
+ <textarea id="request-item-0" data-item-index="0" rows="3" placeholder={ui.itemPlaceholder}></textarea>
48
+ </div>
49
+ </div>
50
+ <button class="text-action" type="button" data-add-item>+ {ui.addItem}</button>
51
+ </div>
52
+ </section>
53
+
54
+ <section class="flow-section flow-boundary">
55
+ <div class="section-marker">03</div>
56
+ <div class="section-content">
57
+ <div class="section-heading"><h3>{ui.boundaryHeading}</h3><span>{ui.boundaryPrompt}</span></div>
58
+ <fieldset class="period-fieldset">
59
+ <legend>{ui.periodLabel}</legend>
60
+ <div class="date-grid"><label for="request-period-from">{ui.periodFrom}<input id="request-period-from" data-field="periodFrom" type="date" /></label><label for="request-period-to">{ui.periodTo}<input id="request-period-to" data-field="periodTo" type="date" /></label></div>
61
+ </fieldset>
62
+ <label for="request-geography">{ui.geographyLabel}</label>
63
+ <input id="request-geography" data-field="geography" type="text" placeholder={ui.geographyPlaceholder} />
64
+ <div class="format-picker" data-format-picker>
65
+ <span class="field-label">{ui.formatLabel}</span>
66
+ <button type="button" class="format-trigger" data-format-trigger aria-expanded="false">{ui.formatPlaceholder}</button>
67
+ <div class="format-menu" data-format-menu hidden role="listbox">
68
+ <button type="button" data-format-option={ui.formatEmail} aria-selected="false" role="option">{ui.formatEmail}</button>
69
+ <button type="button" data-format-option={ui.formatCsv} aria-selected="false" role="option">{ui.formatCsv}</button>
70
+ <button type="button" data-format-option={ui.formatPdf} aria-selected="false" role="option">{ui.formatPdf}</button>
71
+ <button type="button" data-format-option={ui.formatOriginal} aria-selected="false" role="option">{ui.formatOriginal}</button>
72
+ </div>
73
+ </div>
74
+ <label for="request-delivery">{ui.deliveryLabel}</label>
75
+ <input id="request-delivery" data-field="delivery" type="text" placeholder={ui.deliveryPlaceholder} />
76
+ </div>
77
+ </section>
78
+ </div>
79
+
80
+ <div class="request-notes">
81
+ <label for="request-attachments">{ui.attachmentsLabel}<textarea id="request-attachments" data-field="attachments" rows="2" placeholder={ui.attachmentsPlaceholder}></textarea></label>
82
+ <label for="request-contact">{ui.contactLabel}<textarea id="request-contact" data-field="contact" rows="2" placeholder={ui.contactPlaceholder}></textarea></label>
83
+ <label class="check-row"><input type="checkbox" data-field="noAttachments" /> <span>{ui.noAttachments}</span></label>
84
+ <label class="check-row"><input type="checkbox" data-field="savedCopy" /> <span>{ui.savedCopy}</span></label>
85
+ </div>
86
+
87
+ <div class="request-actions"><button class="primary-action" type="button" data-generate>{ui.generateAction}</button><button class="secondary-action" type="button" data-reset>{ui.resetAction}</button></div>
88
+ </div>
89
+
90
+ <div class="request-result" data-request-result aria-live="polite"></div>
91
+
92
+ <div class="request-guidance">
93
+ <section><h2>{ui.methodHeading}</h2><p>{ui.methodText}</p></section>
94
+ <section><h2>{ui.limitsHeading}</h2><p>{ui.limitsText}</p></section>
95
+ <section><h2>{ui.edgeCasesHeading}</h2><p>{ui.edgeCasesText}</p></section>
96
+ </div>
97
+ </div>
98
+
99
+ <script is:inline type="application/json" data-access-request-ui set:html={JSON.stringify(ui)}></script>
100
+
101
+ <script>
102
+ import { mountAccessRequestBuilder } from './controller';
103
+ const root = document.querySelector<HTMLElement>('[data-access-request-builder]');
104
+ const data = document.querySelector<HTMLScriptElement>('[data-access-request-ui]');
105
+ if (root && data) mountAccessRequestBuilder(root, JSON.parse(data.textContent || '{}'));
106
+ </script>
@@ -0,0 +1,17 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { accessToInformationRequestBuilder } from './entry';
3
+ import { ACCESS_TO_INFORMATION_REQUEST_BUILDER_TOOL } from './index';
4
+
5
+ describe('access to information request builder runtime contract', () => {
6
+ it('exposes all locale loaders and page component loaders', async () => {
7
+ const locales = ['de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'] as const;
8
+ for (const locale of locales) {
9
+ const content = await accessToInformationRequestBuilder.i18n[locale]?.();
10
+ expect(content?.ui).toBeDefined();
11
+ expect(content?.schemas?.length).toBe(3);
12
+ }
13
+ expect(typeof ACCESS_TO_INFORMATION_REQUEST_BUILDER_TOOL.Component).toBe('function');
14
+ expect(typeof ACCESS_TO_INFORMATION_REQUEST_BUILDER_TOOL.SEOComponent).toBe('function');
15
+ expect(typeof ACCESS_TO_INFORMATION_REQUEST_BUILDER_TOOL.BibliographyComponent).toBe('function');
16
+ });
17
+ });