@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.
- package/.github/workflows/ci.yml +103 -0
- package/.gitignore +1 -0
- package/package.json +17 -5
- package/scripts/postinstall.mjs +2 -4
- package/src/category/index.ts +3 -1
- package/src/components/ProductionBreadcrumb.astro +132 -0
- package/src/components/ProductionWidget.astro +182 -0
- package/src/entries.ts +4 -0
- package/src/i18n/header-ui.ts +15 -0
- package/src/i18n/language-ui.ts +9 -0
- package/src/i18n/languages.ts +24 -0
- package/src/identity/brands.ts +5 -0
- package/src/index.ts +1 -0
- package/src/layouts/ProductionCategoryPage.astro +184 -0
- package/src/layouts/ProductionPage.astro +209 -0
- package/src/layouts/ProductionUtilityPage.astro +235 -0
- package/src/mfe/assets.ts +15 -0
- package/src/mfe/category-ui.ts +25 -0
- package/src/mfe/routes.ts +50 -0
- package/src/pages/[locale]/[utilities]/[categories]/[category]/[slug].astro +100 -0
- package/src/pages/[locale]/[utilities]/[categories]/[category].astro +44 -0
- package/src/pages/index.astro +1 -1
- package/src/pages/utilidades/[slug].astro +90 -0
- package/src/pages/utilidades/categorias/[category].astro +38 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tests/translation_copy.test.ts +1 -1
- package/src/tool/access-to-information-request-builder/access-to-information-request-builder.css +577 -0
- package/src/tool/access-to-information-request-builder/bibliography.astro +6 -0
- package/src/tool/access-to-information-request-builder/bibliography.ts +6 -0
- package/src/tool/access-to-information-request-builder/component.astro +106 -0
- package/src/tool/access-to-information-request-builder/contract.test.ts +17 -0
- package/src/tool/access-to-information-request-builder/controller.ts +135 -0
- package/src/tool/access-to-information-request-builder/dom-views.ts +59 -0
- package/src/tool/access-to-information-request-builder/entry.ts +27 -0
- package/src/tool/access-to-information-request-builder/evaluator.ts +27 -0
- package/src/tool/access-to-information-request-builder/i18n/de.ts +52 -0
- package/src/tool/access-to-information-request-builder/i18n/en.ts +76 -0
- package/src/tool/access-to-information-request-builder/i18n/es.ts +52 -0
- package/src/tool/access-to-information-request-builder/i18n/fr.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/id.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/it.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/ja.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/ko.ts +50 -0
- package/src/tool/access-to-information-request-builder/i18n/nl.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/pl.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/pt.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/ru.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/sv.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/tr.ts +49 -0
- package/src/tool/access-to-information-request-builder/i18n/zh.ts +49 -0
- package/src/tool/access-to-information-request-builder/index.ts +11 -0
- package/src/tool/access-to-information-request-builder/logic.test.ts +68 -0
- package/src/tool/access-to-information-request-builder/logic.ts +138 -0
- package/src/tool/access-to-information-request-builder/seo.astro +15 -0
- package/src/tool/access-to-information-request-builder/storage.ts +27 -0
- package/src/tool/access-to-information-request-builder/ui.ts +154 -0
- package/src/tool/access-to-information-request-builder/validation.ts +7 -0
- package/src/tool/parliamentary-voting-analyzer/bibliography.astro +14 -0
- package/src/tool/parliamentary-voting-analyzer/bibliography.ts +6 -0
- package/src/tool/parliamentary-voting-analyzer/component.astro +63 -0
- package/src/tool/parliamentary-voting-analyzer/contract.test.ts +16 -0
- package/src/tool/parliamentary-voting-analyzer/controller.ts +65 -0
- package/src/tool/parliamentary-voting-analyzer/dom-views.ts +63 -0
- package/src/tool/parliamentary-voting-analyzer/entry.ts +27 -0
- package/src/tool/parliamentary-voting-analyzer/evaluator.ts +12 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/de.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/en.ts +79 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/es.ts +49 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/fr.ts +43 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/id.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/it.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/ja.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/ko.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/nl.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/pl.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/pt.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/ru.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/sv.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/tr.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/i18n/zh.ts +45 -0
- package/src/tool/parliamentary-voting-analyzer/index.ts +11 -0
- package/src/tool/parliamentary-voting-analyzer/logic.test.ts +52 -0
- package/src/tool/parliamentary-voting-analyzer/logic.ts +279 -0
- package/src/tool/parliamentary-voting-analyzer/parliamentary-voting-analyzer.css +491 -0
- package/src/tool/parliamentary-voting-analyzer/seo.astro +14 -0
- package/src/tool/parliamentary-voting-analyzer/storage.ts +25 -0
- package/src/tool/parliamentary-voting-analyzer/ui.ts +98 -0
- package/src/tools.ts +4 -0
- package/src/types.ts +2 -4
- package/src/worker.ts +9 -0
- package/tsconfig.json +14 -5
- package/src/pages/[locale]/[slug].astro +0 -166
- package/src/pages/[locale].astro +0 -253
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createPreset, emptyDraft, type RequestDraft } from './logic';
|
|
2
|
+
import { renderRequest } from './dom-views';
|
|
3
|
+
import { clearDraft, loadDraft, saveDraft } from './storage';
|
|
4
|
+
import type { AccessRequestUI } from './ui';
|
|
5
|
+
|
|
6
|
+
interface ControllerState {
|
|
7
|
+
draft: RequestDraft;
|
|
8
|
+
ui: AccessRequestUI;
|
|
9
|
+
root: HTMLElement;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function mountAccessRequestBuilder(root: HTMLElement, ui: AccessRequestUI): void {
|
|
13
|
+
const state: ControllerState = { draft: loadDraft() ?? cloneDraft(emptyDraft), ui, root };
|
|
14
|
+
bindInputs(state);
|
|
15
|
+
bindPresets(state);
|
|
16
|
+
bindActions(state);
|
|
17
|
+
renderState(state);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function cloneDraft(draft: RequestDraft): RequestDraft {
|
|
21
|
+
return { ...draft, items: [...draft.items] };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function bindInputs(state: ControllerState): void {
|
|
25
|
+
const fields = state.root.querySelectorAll<HTMLInputElement | HTMLTextAreaElement>('[data-field]');
|
|
26
|
+
fields.forEach((field) => field.addEventListener('input', () => {
|
|
27
|
+
updateField(state, field);
|
|
28
|
+
renderState(state);
|
|
29
|
+
}));
|
|
30
|
+
state.root.querySelectorAll<HTMLButtonElement>('[data-format-option]').forEach((button) => button.addEventListener('click', () => {
|
|
31
|
+
state.draft.preferredFormat = button.dataset.formatOption ?? '';
|
|
32
|
+
syncFormatMenu(state);
|
|
33
|
+
renderState(state);
|
|
34
|
+
}));
|
|
35
|
+
state.root.querySelector<HTMLButtonElement>('[data-format-trigger]')?.addEventListener('click', () => toggleFormatMenu(state));
|
|
36
|
+
document.addEventListener('click', (event) => closeFormatMenu(state, event));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function updateField(state: ControllerState, field: HTMLInputElement | HTMLTextAreaElement): void {
|
|
40
|
+
const key = field.dataset.field as keyof RequestDraft;
|
|
41
|
+
if (key === 'items') return;
|
|
42
|
+
if (key === 'noAttachments' || key === 'savedCopy') state.draft[key] = (field as HTMLInputElement).checked;
|
|
43
|
+
else state.draft[key] = field.value as never;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function bindPresets(state: ControllerState): void {
|
|
47
|
+
state.root.querySelectorAll<HTMLButtonElement>('[data-preset]').forEach((button) => button.addEventListener('click', () => {
|
|
48
|
+
const preset = button.dataset.preset;
|
|
49
|
+
if (preset === 'records' || preset === 'spending' || preset === 'meetings') {
|
|
50
|
+
state.draft = createPreset(preset);
|
|
51
|
+
syncForm(state);
|
|
52
|
+
renderItems(state);
|
|
53
|
+
renderState(state);
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function bindActions(state: ControllerState): void {
|
|
59
|
+
state.root.querySelector<HTMLButtonElement>('[data-generate]')?.addEventListener('click', () => renderState(state));
|
|
60
|
+
state.root.querySelector<HTMLButtonElement>('[data-add-item]')?.addEventListener('click', () => {
|
|
61
|
+
state.draft.items.push('');
|
|
62
|
+
renderItems(state);
|
|
63
|
+
renderState(state);
|
|
64
|
+
});
|
|
65
|
+
state.root.addEventListener('click', (event) => {
|
|
66
|
+
const target = event.target as HTMLElement;
|
|
67
|
+
const removeButton = target.closest<HTMLButtonElement>('[data-remove-item]');
|
|
68
|
+
if (!removeButton) return;
|
|
69
|
+
const index = Number(removeButton.dataset.removeItem);
|
|
70
|
+
if (state.draft.items.length > 1) state.draft.items.splice(index, 1);
|
|
71
|
+
renderItems(state);
|
|
72
|
+
renderState(state);
|
|
73
|
+
});
|
|
74
|
+
state.root.querySelector<HTMLButtonElement>('[data-reset]')?.addEventListener('click', () => {
|
|
75
|
+
state.draft = cloneDraft(emptyDraft);
|
|
76
|
+
clearDraft();
|
|
77
|
+
syncForm(state);
|
|
78
|
+
renderItems(state);
|
|
79
|
+
renderState(state);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function renderState(state: ControllerState): void {
|
|
84
|
+
saveDraft(state.draft);
|
|
85
|
+
renderRequest(state.root.querySelector<HTMLElement>('[data-request-result]') as HTMLElement, state.draft, state.ui);
|
|
86
|
+
syncChecklist(state);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function renderItems(state: ControllerState): void {
|
|
90
|
+
const list = state.root.querySelector<HTMLElement>('[data-request-lines]');
|
|
91
|
+
if (!list) return;
|
|
92
|
+
list.innerHTML = state.draft.items.map((item, index) => `<div class="request-line"><label for="request-item-${index}">${state.ui.itemNumber} ${index + 1}</label><textarea id="request-item-${index}" data-item-index="${index}" rows="3" placeholder="${state.ui.itemPlaceholder}">${item.replace(/&/g, '&').replace(/</g, '<')}</textarea>${state.draft.items.length > 1 ? `<button type="button" data-remove-item="${index}">${state.ui.removeItem}</button>` : ''}</div>`).join('');
|
|
93
|
+
list.querySelectorAll<HTMLTextAreaElement>('[data-item-index]').forEach((field) => field.addEventListener('input', () => {
|
|
94
|
+
state.draft.items[Number(field.dataset.itemIndex)] = field.value;
|
|
95
|
+
renderState(state);
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function syncForm(state: ControllerState): void {
|
|
100
|
+
state.root.querySelectorAll<HTMLInputElement | HTMLTextAreaElement>('[data-field]').forEach((field) => {
|
|
101
|
+
const key = field.dataset.field as keyof RequestDraft;
|
|
102
|
+
if (key === 'noAttachments' || key === 'savedCopy') (field as HTMLInputElement).checked = Boolean(state.draft[key]);
|
|
103
|
+
else if (key !== 'items') field.value = String(state.draft[key] ?? '');
|
|
104
|
+
});
|
|
105
|
+
syncFormatMenu(state);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function syncFormatMenu(state: ControllerState): void {
|
|
109
|
+
const trigger = state.root.querySelector<HTMLButtonElement>('[data-format-trigger]');
|
|
110
|
+
const options = state.root.querySelectorAll<HTMLButtonElement>('[data-format-option]');
|
|
111
|
+
const chosen = Array.from(options).find((option) => option.dataset.formatOption === state.draft.preferredFormat);
|
|
112
|
+
if (trigger) trigger.textContent = chosen?.textContent?.trim() || state.ui.formatPlaceholder;
|
|
113
|
+
options.forEach((option) => option.setAttribute('aria-selected', String(option.dataset.formatOption === state.draft.preferredFormat)));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function toggleFormatMenu(state: ControllerState): void {
|
|
117
|
+
const menu = state.root.querySelector<HTMLElement>('[data-format-menu]');
|
|
118
|
+
const trigger = state.root.querySelector<HTMLButtonElement>('[data-format-trigger]');
|
|
119
|
+
if (!menu || !trigger) return;
|
|
120
|
+
const open = menu.hidden;
|
|
121
|
+
menu.hidden = !open;
|
|
122
|
+
trigger.setAttribute('aria-expanded', String(open));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function closeFormatMenu(state: ControllerState, event: Event): void {
|
|
126
|
+
const menu = state.root.querySelector<HTMLElement>('[data-format-menu]');
|
|
127
|
+
if (!menu || menu.hidden || (event.target as HTMLElement).closest('[data-format-picker]')) return;
|
|
128
|
+
menu.hidden = true;
|
|
129
|
+
state.root.querySelector<HTMLButtonElement>('[data-format-trigger]')?.setAttribute('aria-expanded', 'false');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function syncChecklist(state: ControllerState): void {
|
|
133
|
+
const values: Record<string, string> = { recipient: state.draft.recipient, subject: state.draft.subject, geography: state.draft.geography, delivery: state.draft.delivery };
|
|
134
|
+
Object.entries(values).forEach(([key, value]) => state.root.querySelector(`[data-filled="${key}"]`)?.classList.toggle('is-filled', Boolean(value.trim())));
|
|
135
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { buildRequestMarkdown, type ChecklistItem, type RequestDraft } from './logic';
|
|
2
|
+
import { evaluateForDisplay } from './evaluator';
|
|
3
|
+
import type { AccessRequestUI } from './ui';
|
|
4
|
+
|
|
5
|
+
function escapeHtml(value: string): string {
|
|
6
|
+
return value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function checklistLabel(item: ChecklistItem, ui: AccessRequestUI): string {
|
|
10
|
+
const labels = { recipient: ui.checklistRecipient, scope: ui.checklistScope, period: ui.checklistPeriod, format: ui.checklistFormat, attachments: ui.checklistAttachments, copy: ui.checklistCopy };
|
|
11
|
+
return labels[item.key];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function checklistState(item: ChecklistItem): string {
|
|
15
|
+
if (item.complete) return 'complete';
|
|
16
|
+
if (item.caution) return 'caution';
|
|
17
|
+
return 'review';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function checklistMarker(item: ChecklistItem): string {
|
|
21
|
+
if (item.complete) return 'OK';
|
|
22
|
+
if (item.caution) return '!';
|
|
23
|
+
return '.';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderChecklist(items: ChecklistItem[], ui: AccessRequestUI): string {
|
|
27
|
+
return items.map((item) => {
|
|
28
|
+
const state = checklistState(item);
|
|
29
|
+
const marker = checklistMarker(item);
|
|
30
|
+
return `<li class="trail-check trail-check-${state}"><span aria-hidden="true">${marker}</span><span>${escapeHtml(checklistLabel(item, ui))}</span><strong>${item.complete ? escapeHtml(ui.completeLabel) : escapeHtml(ui.reviewLabel)}</strong></li>`;
|
|
31
|
+
}).join('');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderWarnings(messages: { text: string; severity: string }[], ui: AccessRequestUI): string {
|
|
35
|
+
if (messages.length === 0) return '';
|
|
36
|
+
return `<div class="trail-warnings" role="status"><p class="trail-warnings-title">${escapeHtml(ui.reviewWarningsHeading)}</p><ul>${messages.map((message) => `<li class="trail-warning-${message.severity}">${escapeHtml(message.text)}</li>`).join('')}</ul></div>`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function renderRequest(root: HTMLElement, draft: RequestDraft, ui: AccessRequestUI): void {
|
|
40
|
+
const evaluation = evaluateForDisplay(draft, ui);
|
|
41
|
+
const markdown = buildRequestMarkdown(draft);
|
|
42
|
+
const hasContent = Boolean(draft.subject.trim() || draft.items.some((item) => item.trim()));
|
|
43
|
+
const output = hasContent ? `<textarea class="request-markdown" data-request-markdown rows="18" spellcheck="false">${escapeHtml(markdown)}</textarea>` : `<p class="request-empty">${escapeHtml(ui.noResult)}</p>`;
|
|
44
|
+
root.innerHTML = `<div class="request-output"><div class="output-heading"><div><span class="eyebrow">${escapeHtml(ui.resultHeading)}</span><p>${escapeHtml(ui.resultIntro)}</p></div><div class="output-actions"><button type="button" data-copy-request ${hasContent ? '' : 'disabled'}>${escapeHtml(ui.copyAction)}</button><button type="button" data-print-request ${hasContent ? '' : 'disabled'}>${escapeHtml(ui.printAction)}</button></div></div>${output}<p class="copy-confirmation" data-copy-confirmation hidden>${escapeHtml(ui.copied)}</p></div><div class="trace-strip"><div class="trace-heading"><span class="eyebrow">${escapeHtml(ui.checklistHeading)}</span><strong>${evaluation.valid ? escapeHtml(ui.statusReady) : escapeHtml(ui.statusReview)}</strong></div><ul class="trail-checklist">${renderChecklist(evaluation.checklist, ui)}</ul>${renderWarnings(evaluation.messages, ui)}</div>`;
|
|
45
|
+
root.querySelector<HTMLButtonElement>('[data-copy-request]')?.addEventListener('click', () => copyRequest(root, markdown, ui));
|
|
46
|
+
root.querySelector<HTMLButtonElement>('[data-print-request]')?.addEventListener('click', () => window.print());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function copyRequest(root: HTMLElement, markdown: string, ui: AccessRequestUI): Promise<void> {
|
|
50
|
+
try {
|
|
51
|
+
const editable = root.querySelector<HTMLTextAreaElement>('[data-request-markdown]');
|
|
52
|
+
await navigator.clipboard.writeText(editable?.value ?? markdown);
|
|
53
|
+
const confirmation = root.querySelector<HTMLElement>('[data-copy-confirmation]');
|
|
54
|
+
if (confirmation) {
|
|
55
|
+
confirmation.textContent = ui.copied;
|
|
56
|
+
confirmation.hidden = false;
|
|
57
|
+
}
|
|
58
|
+
} catch {}
|
|
59
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CivicToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
+
import type { AccessRequestUI } from './ui';
|
|
3
|
+
|
|
4
|
+
export type AccessRequestLocaleContent = ToolLocaleContent<AccessRequestUI>;
|
|
5
|
+
|
|
6
|
+
export const accessToInformationRequestBuilder: CivicToolEntry<AccessRequestUI> = {
|
|
7
|
+
id: 'access-to-information-request-builder',
|
|
8
|
+
phase: 'localized',
|
|
9
|
+
icons: { bg: 'mdi:file-document-edit-outline', fg: 'mdi:arrow-right-bold' },
|
|
10
|
+
i18n: {
|
|
11
|
+
de: () => import('./i18n/de').then((module) => module.content),
|
|
12
|
+
en: () => import('./i18n/en').then((module) => module.content),
|
|
13
|
+
es: () => import('./i18n/es').then((module) => module.content),
|
|
14
|
+
fr: () => import('./i18n/fr').then((module) => module.content),
|
|
15
|
+
id: () => import('./i18n/id').then((module) => module.content),
|
|
16
|
+
it: () => import('./i18n/it').then((module) => module.content),
|
|
17
|
+
ja: () => import('./i18n/ja').then((module) => module.content),
|
|
18
|
+
ko: () => import('./i18n/ko').then((module) => module.content),
|
|
19
|
+
nl: () => import('./i18n/nl').then((module) => module.content),
|
|
20
|
+
pl: () => import('./i18n/pl').then((module) => module.content),
|
|
21
|
+
pt: () => import('./i18n/pt').then((module) => module.content),
|
|
22
|
+
ru: () => import('./i18n/ru').then((module) => module.content),
|
|
23
|
+
sv: () => import('./i18n/sv').then((module) => module.content),
|
|
24
|
+
tr: () => import('./i18n/tr').then((module) => module.content),
|
|
25
|
+
zh: () => import('./i18n/zh').then((module) => module.content),
|
|
26
|
+
},
|
|
27
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AccessRequestUI } from './ui';
|
|
2
|
+
import { evaluateDraft, type DraftEvaluation, type RequestDraft } from './logic';
|
|
3
|
+
|
|
4
|
+
export interface WarningMessage {
|
|
5
|
+
text: string;
|
|
6
|
+
severity: 'review' | 'caution';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const warningText: Record<string, keyof AccessRequestUI> = {
|
|
10
|
+
'missing-recipient': 'missingRecipient',
|
|
11
|
+
'missing-items': 'missingItems',
|
|
12
|
+
'missing-period': 'missingPeriod',
|
|
13
|
+
'broad-item': 'broadItem',
|
|
14
|
+
'missing-format': 'missingFormat',
|
|
15
|
+
'missing-geography': 'missingGeography',
|
|
16
|
+
'missing-delivery': 'missingDelivery',
|
|
17
|
+
'no-copy': 'noCopyWarning',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function evaluateForDisplay(draft: RequestDraft, ui: AccessRequestUI): DraftEvaluation & { messages: WarningMessage[] } {
|
|
21
|
+
const evaluation = evaluateDraft(draft);
|
|
22
|
+
const messages = evaluation.warnings.map((code) => ({
|
|
23
|
+
text: ui[warningText[code] ?? 'statusReview'] ?? ui.statusReview,
|
|
24
|
+
severity: code === 'broad-item' ? 'caution' as const : 'review' as const,
|
|
25
|
+
}));
|
|
26
|
+
return { ...evaluation, messages };
|
|
27
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { AccessRequestLocaleContent } from '../entry';
|
|
4
|
+
import type { AccessRequestUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const ui: AccessRequestUI = {
|
|
7
|
+
eyebrow: 'CIVIC PAPER TRAIL', introHeading: 'Formuliere die Frage, bevor sie deinen Schreibtisch verlässt.', introText: 'Beginne mit dem Ziel, nenne pro Zeile genau einen anfragbaren Datensatz und ergänze die Grenzen, die das Auffinden erleichtern.', targetHeading: 'Ziel festlegen', targetPrompt: 'Wer kann antworten?', questionPrompt: 'Ein Datensatz pro Zeile', boundaryHeading: 'Grenzen ziehen', boundaryPrompt: 'Was macht ihn auffindbar?', reviewWarningsHeading: 'Vor dem Senden prüfen',
|
|
8
|
+
recipientLabel: 'Behörde oder Empfänger', recipientPlaceholder: 'Amt, Behörde, Archiv oder Organisation', subjectLabel: 'Thema', subjectPlaceholder: 'Die Unterlagen oder Informationen, die du finden möchtest', itemsLabel: 'Angeforderte Informationen', itemPlaceholder: 'Frage nach einem identifizierbaren Datensatz, Dokument oder Feld', addItem: 'Weitere Anfragezeile hinzufügen', removeItem: 'Diese Zeile entfernen', periodLabel: 'Zeitraum', periodFrom: 'Von', periodTo: 'Bis', geographyLabel: 'Geografischer Umfang', geographyPlaceholder: 'Stadt, Bezirk, Standort, Programmgebiet oder landesweit', formatLabel: 'Bevorzugtes Format', formatPlaceholder: 'Lieferformat auswählen', formatEmail: 'Elektronische Kopie per E-Mail', formatCsv: 'Maschinenlesbare Tabelle wie CSV', formatPdf: 'Durchsuchbares PDF oder Dokument', formatOriginal: 'Von der Behörde gespeichertes Originalformat', deliveryLabel: 'Antwortdetails', deliveryPlaceholder: 'E-Mail-Adresse, Postanschrift oder sicherer Antwortweg', contactLabel: 'Optionale Kontaktdaten', contactPlaceholder: 'Telefon, Aktenzeichen oder bevorzugter Antwortkanal', attachmentsLabel: 'Anhänge oder Kennungen', attachmentsPlaceholder: 'Dateinamen, Aktenzeichen, Links oder Kontext zum Auffinden', noAttachments: 'Keine Anhänge oder Kennungen erforderlich', savedCopy: 'Ich habe eine Kopie des fertigen Textes gespeichert', presetLabel: 'Mit einem fokussierten Beispiel beginnen', presetRecords: 'Sitzungsunterlagen', presetSpending: 'Ausgabenunterlagen', presetMeetings: 'Dienstleistungsbeschwerden', generateAction: 'Anfrageentwurf erstellen', resetAction: 'Entwurf löschen', resultHeading: 'Anfrageentwurf', resultIntro: 'Prüfe alle Angaben und bearbeite den finalen Text vor dem Kopieren. Hinweise und Warnungen bleiben außerhalb des gesendeten Textes.', copyAction: 'Markdown kopieren', printAction: 'Drucken oder als PDF speichern', copied: 'In die Zwischenablage kopiert', noResult: 'Füge einen Empfänger, ein Thema und mindestens eine Anfragezeile hinzu, um die Spur zu sehen.', checklistHeading: 'Nachvollziehbarkeit vor dem Senden', completeLabel: 'Bereit', reviewLabel: 'Prüfen', checklistRecipient: 'Empfänger genannt', checklistScope: 'Jede Zeile bezeichnet einen anfragbaren Datensatz', checklistPeriod: 'Zeitraum begrenzt', checklistFormat: 'Bevorzugtes Format genannt', checklistAttachments: 'Anhänge und Kennungen berücksichtigt', checklistCopy: 'Kopie für die eigenen Unterlagen gespeichert', methodHeading: 'Angewandte Methode', methodText: 'Der Builder macht aus einem breiten Thema eine nachvollziehbare Anfrage: ein Datensatz pro Zeile, ein benannter Empfänger, ein klarer Zeitraum, eine geografische Grenze, ein bevorzugtes Format und ein nutzbarer Antwortweg. Er ordnet nur deine Angaben und ergänzt niemals Rechtsgrundlage, Frist, Behörde oder Tatsachenbehauptung.', limitsHeading: 'Was dieses Tool nicht entscheidet', limitsText: 'Es ermittelt nicht die zuständige Behörde, keine gesetzliche Frist, keine Offenlegungsgarantie und reicht die Anfrage nicht ein. Es ordnet Unterlagen nicht nach lokalem Recht ein und bietet keine Rechtsberatung. Prüfe vor dem Senden die aktuellen Hinweise der empfangenden Stelle.', edgeCasesHeading: 'Sonderfälle und Datenhinweise', edgeCasesText: 'Breite Formulierungen wie "alle Dokumente" sind schwer zu durchsuchen. Vermeide undefinierte Begriffe, uneinheitliche Datumsbedeutungen, unnötige personenbezogene Daten und die Bitte um eine neue Analyse, wenn du einen vorhandenen Datensatz brauchst. Formate sind möglicherweise nicht verfügbar.', statusReady: 'Der Entwurf enthält die vollständige Mindestspur.', statusReview: 'Der Entwurf ist ein brauchbarer Anfang, muss aber geprüft werden.', missingRecipient: 'Nenne vor dem Senden die Behörde oder den Empfänger.', missingItems: 'Füge mindestens einen konkreten Datensatz hinzu.', missingPeriod: 'Füge Anfang und Ende hinzu oder erkläre die fehlende Grenze.', broadItem: 'Diese Zeile könnte zu breit sein. Nenne Datensatztyp, Feld, Ereignis oder messbare Menge.', missingFormat: 'Wähle, wie die Information geliefert werden soll.', missingGeography: 'Nenne einen Ort oder erkläre, warum die Anfrage landesweit gilt.', missingDelivery: 'Nenne einen Antwortweg für den Empfänger.', noCopyWarning: 'Speichere den finalen Text und die Einreichungsdaten vor dem Senden.', itemNumber: 'Anfragezeile',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const softwareApplication: SoftwareApplication = { '@type': 'SoftwareApplication', name: 'Builder für Informationszugangsanfragen', applicationCategory: 'UtilitiesApplication', operatingSystem: 'Any', description: 'Erstelle einen präzisen, nachvollziehbaren Antrag mit Umfang, Zeitraum, Format und Antwortweg.', url: 'https://gamebob.dev/de/antrag-informationszugang-erstellen', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' } };
|
|
12
|
+
const faqPage: FAQPage = { '@type': 'FAQPage', mainEntity: [
|
|
13
|
+
{ '@type': 'Question', name: 'Was sollte ich anfordern?', acceptedAnswer: { '@type': 'Answer', text: 'Frage nach einem identifizierbaren Datensatz, Dokument, Feld oder messbaren Zähler. Trenne unabhängige Datensätze in verschiedene Anfragezeilen.' } },
|
|
14
|
+
{ '@type': 'Question', name: 'Kennt das Tool die zuständige Behörde?', acceptedAnswer: { '@type': 'Answer', text: 'Nein. Du musst den wahrscheinlichen Empfänger ermitteln und seine aktuellen Hinweise prüfen. Der Builder bestimmt weder Zuständigkeit noch Fristen oder Ausnahmen.' } },
|
|
15
|
+
{ '@type': 'Question', name: 'Warum sind Zeitraum und geografischer Umfang wichtig?', acceptedAnswer: { '@type': 'Answer', text: 'Sie begrenzen die Suche und verringern Mehrdeutigkeit. Verwende an beiden Enden dieselbe Datumsbedeutung und nenne den betroffenen Ort oder das Programm.' } },
|
|
16
|
+
{ '@type': 'Question', name: 'Kann ich personenbezogene oder sensible Daten anfordern?', acceptedAnswer: { '@type': 'Answer', text: 'Füge nur notwendige und angemessene Angaben ein. Zugangs- und Datenschutzregeln unterscheiden sich, daher solltest du die aktuellen Hinweise des Empfängers prüfen.' } },
|
|
17
|
+
] };
|
|
18
|
+
const howTo: HowTo = { '@type': 'HowTo', name: 'Eine präzise Informationsanfrage formulieren', step: [
|
|
19
|
+
{ '@type': 'HowToStep', name: 'Empfänger nennen', text: 'Trage die Behörde, Abteilung, das Archiv oder die Organisation ein, die die Information vermutlich besitzt, und prüfe ihren aktuellen Anfrageweg.' },
|
|
20
|
+
{ '@type': 'HowToStep', name: 'Information aufteilen', text: 'Schreibe pro Zeile genau einen anfragbaren Datensatz. Nenne Datensatztyp, Felder, Ereignis oder Zähler statt eines ganzen Themenbereichs.' },
|
|
21
|
+
{ '@type': 'HowToStep', name: 'Suche begrenzen', text: 'Ergänze Anfangsdatum, Enddatum, geografischen Umfang und Kennungen, die beim Auffinden helfen.' },
|
|
22
|
+
{ '@type': 'HowToStep', name: 'Antwortdetails wählen', text: 'Nenne ein bevorzugtes Format und einen zuverlässigen Antwortweg, ohne die Verfügbarkeit eines Formats vorauszusetzen.' },
|
|
23
|
+
{ '@type': 'HowToStep', name: 'Prüfen und Kopie behalten', text: 'Lies das Markdown, bearbeite Prüfpunkte, speichere Text und Einreichungsdaten und sende über den bestätigten Kanal.' },
|
|
24
|
+
] };
|
|
25
|
+
|
|
26
|
+
export const content: AccessRequestLocaleContent = { slug: 'antrag-informationszugang-erstellen', title: 'Builder für Informationszugangsanfragen', description: 'Formuliere eine präzise Informationsanfrage mit Empfänger, einzelnen Anfragezeilen, Zeitraum, geografischem Umfang, Lieferformat und Prüfliste.', ui, seo: [
|
|
27
|
+
{ type: 'title', text: 'Eine auffindbare Informationsanfrage schreiben', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Eine Anfrage kann höflich und dennoch schwer zu beantworten sein, wenn ihr Thema zu breit ist, Daten fehlen oder mehrere unabhängige Fragen vermischt werden. Dieser Builder macht aus deinen Angaben eine prüfbare Spur: Empfänger, gesuchte Unterlagen, Zeitraum, Ort und möglicher Antwortweg.' },
|
|
29
|
+
{ type: 'title', text: 'Der Suche eine Grenze geben', level: 2 },
|
|
30
|
+
{ type: 'paragraph', html: 'Verwende an beiden Enden dieselbe Bedeutung für das Datum, etwa Veröffentlichungsdatum, Sitzungstag oder Zahlungsdatum. Ergänze Ort, Programm, Standort oder Organisation. Wenn eine Grenze wirklich unbekannt ist, zeige sie in der Prüfliste und rate nicht.' },
|
|
31
|
+
{ type: 'table', headers: ['Anfragedetail', 'Nützliche Formulierung', 'Unterstützte Entscheidung'], rows: [['Informationssatz', 'Endgültige Tagesordnungen und genehmigte Protokolle', 'Welche Unterlagen sollen gesucht werden?'], ['Zeitraum', 'Vom 01.01.2025 bis 31.12.2025', 'Welche Unterlagen gehören dazu?'], ['Geografischer Umfang', 'Dienstleistungsbereich Nordbezirk', 'Welcher Ort ist gemeint?'], ['Format', 'Maschinenlesbare Tabelle wie CSV', 'Wie kann das Ergebnis geprüft werden?']] },
|
|
32
|
+
{ type: 'title', text: 'Den Entwurf vor dem Senden prüfen', level: 2 },
|
|
33
|
+
{ type: 'paragraph', html: 'Der erzeugte Text hält deine Fakten zusammen und trennt Hinweise von dem Text, den du sendest. Ein vollständiger Prüfpunk bedeutet, dass das Mindestdetail vorhanden ist. Eine Warnung zu breiter Sprache fordert dich auf, Datensatz, Feld, Ereignis oder messbare Menge genauer zu benennen.' },
|
|
34
|
+
{ type: 'list', items: ['Bestätige, dass der Empfänger diese Art Anfrage aktuell annimmt.', 'Prüfe, dass jede Zeile genau einen identifizierbaren Datensatz verlangt.', 'Verwende einen geschlossenen Zeitraum und eine passende geografische Grenze.', 'Nenne ein bevorzugtes Format, ohne die Erstellung einer neuen Datei vorauszusetzen.', 'Speichere Anhänge, Kennungen, finalen Text und Einreichungskanal.'] },
|
|
35
|
+
{ type: 'tip', title: 'Präzise bedeutet nicht vollständig', html: 'Eine kurze Anfrage mit Datensatztyp, Zeitraum und Kennungen ist oft leichter zu suchen als eine lange Erzählung. Behalte Kontext, der beim Auffinden hilft, und entferne Hintergrund ohne Einfluss auf die Frage.' },
|
|
36
|
+
{ type: 'title', text: 'Was der Builder nicht entscheiden kann', level: 2 },
|
|
37
|
+
{ type: 'paragraph', html: 'Dies ist ein länderübergreifendes Schreibwerkzeug. Es findet weder die zuständige Behörde noch eine gesetzliche Frist, garantiert Offenlegung oder ein Format, reicht die Anfrage ein oder bietet Rechtsberatung. Für diese Fragen gelten die aktuellen Regeln der empfangenden Stelle.' },
|
|
38
|
+
{ type: 'tip', title: 'Die Beweisspur aufbewahren', html: 'Speichere den genauen Text, Datum, Empfänger, Anhänge und eine Bestätigung. So kannst du die Antwort mit der tatsächlich gestellten Frage vergleichen.' },
|
|
39
|
+
{ type: 'title', text: 'Eine brauchbare Antwort vorbereiten', level: 2 },
|
|
40
|
+
{ type: 'paragraph', html: 'Nenne die Felder oder den Dokumenttyp, die für dein Ziel wichtig sind, und bewahre Anfrage und Antwort gemeinsam auf.' },
|
|
41
|
+
], faq: [
|
|
42
|
+
{ question: 'Was sollte ich anfordern?', answer: 'Frage nach einem identifizierbaren Datensatz, Dokument, Feld oder messbaren Zähler und trenne unabhängige Datensätze.' },
|
|
43
|
+
{ question: 'Kennt das Tool die zuständige Behörde?', answer: 'Nein. Prüfe Empfänger, Zuständigkeit, Frist, Ausnahmen und Kanal anhand aktueller lokaler Hinweise.' },
|
|
44
|
+
{ question: 'Warum sind Zeitraum und Ort wichtig?', answer: 'Sie begrenzen die Suche. Nutze dieselbe Datumsbedeutung und nenne den betroffenen Ort oder das Programm.' },
|
|
45
|
+
{ question: 'Kann ich sensible Daten anfordern?', answer: 'Füge nur notwendige Angaben ein und prüfe die aktuellen Zugangs- und Datenschutzhinweise.' },
|
|
46
|
+
], bibliography, howTo: [
|
|
47
|
+
{ name: 'Empfänger nennen', text: 'Trage die wahrscheinliche Behörde ein und prüfe ihren aktuellen Anfrageweg.' },
|
|
48
|
+
{ name: 'Information aufteilen', text: 'Schreibe pro Zeile einen identifizierbaren Datensatz, ein Feld oder einen Zähler.' },
|
|
49
|
+
{ name: 'Suche begrenzen', text: 'Ergänze passende Anfangs- und Enddaten, Ort und Kennungen.' },
|
|
50
|
+
{ name: 'Antwortdetails wählen', text: 'Nenne Format und Antwortweg, ohne eine neue Datei vorauszusetzen.' },
|
|
51
|
+
{ name: 'Prüfen und Kopie behalten', text: 'Bearbeite Warnungen und speichere Text und Einreichungsdaten.' },
|
|
52
|
+
], schemas: [softwareApplication, faqPage, howTo] as unknown as Record<string, unknown>[] };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { AccessRequestLocaleContent } from '../entry';
|
|
4
|
+
import { ui } from '../ui';
|
|
5
|
+
|
|
6
|
+
const softwareApplication: SoftwareApplication = {
|
|
7
|
+
'@type': 'SoftwareApplication',
|
|
8
|
+
name: 'Access to Information Request Builder',
|
|
9
|
+
applicationCategory: 'UtilitiesApplication',
|
|
10
|
+
operatingSystem: 'Any',
|
|
11
|
+
description: 'Draft a precise, traceable information request with clear scope, dates, format, and delivery details.',
|
|
12
|
+
url: 'https://gamebob.dev/en/access-to-information-request-builder',
|
|
13
|
+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const faqPage: FAQPage = {
|
|
17
|
+
'@type': 'FAQPage',
|
|
18
|
+
mainEntity: [
|
|
19
|
+
{ '@type': 'Question', name: 'What should I ask for?', acceptedAnswer: { '@type': 'Answer', text: 'Ask for an identifiable information set, record, field, or measurable count. Separate unrelated sets into different request lines so the recipient can search and answer each one.' } },
|
|
20
|
+
{ '@type': 'Question', name: 'Does this tool know which authority to contact?', acceptedAnswer: { '@type': 'Answer', text: 'No. You must identify the likely recipient and check its current instructions. The builder does not determine jurisdiction, deadlines, exemptions, or filing channels.' } },
|
|
21
|
+
{ '@type': 'Question', name: 'Why do dates and geographic scope matter?', acceptedAnswer: { '@type': 'Answer', text: 'They narrow the search boundary and reduce ambiguity. Use a start and end date with the same meaning, and name the place, programme area, or organisation covered by the request.' } },
|
|
22
|
+
{ '@type': 'Question', name: 'Can I request personal or sensitive information?', acceptedAnswer: { '@type': 'Answer', text: 'Only include personal details that are necessary and appropriate for your situation. Access rules and privacy limits differ by jurisdiction, so review the recipient\'s guidance before sending.' } },
|
|
23
|
+
],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const howTo: HowTo = {
|
|
27
|
+
'@type': 'HowTo',
|
|
28
|
+
name: 'Draft a precise information request',
|
|
29
|
+
step: [
|
|
30
|
+
{ '@type': 'HowToStep', name: 'Name the recipient', text: 'Enter the authority, department, archive, or organisation you believe holds the information, then verify its current request channel.' },
|
|
31
|
+
{ '@type': 'HowToStep', name: 'Split the information', text: 'Write one requestable set per line. Name the record type, fields, event, or count instead of asking for everything about a topic.' },
|
|
32
|
+
{ '@type': 'HowToStep', name: 'Bound the search', text: 'Add a start date, end date, geographic scope, and any record identifiers that help the recipient find the material.' },
|
|
33
|
+
{ '@type': 'HowToStep', name: 'Choose delivery details', text: 'State a preferred format and a reliable reply route, while recognising that the available format may depend on the records held.' },
|
|
34
|
+
{ '@type': 'HowToStep', name: 'Review and keep a copy', text: 'Read the generated Markdown, resolve the review items, save the final text and submission details, then send it through the verified channel.' },
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const content: AccessRequestLocaleContent = {
|
|
39
|
+
slug: 'access-to-information-request-builder',
|
|
40
|
+
title: 'Access to Information Request Builder',
|
|
41
|
+
description: 'Draft a precise information request with a named recipient, specific request lines, clear dates, geographic scope, delivery format, and a pre-send checklist.',
|
|
42
|
+
ui,
|
|
43
|
+
seo: [
|
|
44
|
+
{ type: 'title', text: 'Write an Information Request Someone Can Find', level: 2 },
|
|
45
|
+
{ type: 'paragraph', html: 'A request can be polite and still be difficult to answer when its subject is broad, its dates are missing, or it combines several unrelated questions. This builder turns the details you already know into a reviewable paper trail: who should receive the request, what records are sought, which period and place matter, and how a reply could be delivered.' },
|
|
46
|
+
{ type: 'paragraph', html: 'The strongest input is not a legal phrase. It is a concrete description of an information set, such as a transaction table with named fields, approved minutes for a defined period, or a monthly count for a named service. Separate lines make it easier to spot an unclear noun, an unbounded date, or a request for a new analysis rather than an existing record.' },
|
|
47
|
+
{ type: 'title', text: 'Give the Search a Boundary', level: 2 },
|
|
48
|
+
{ type: 'paragraph', html: 'Use the same time meaning at both ends of the period: publication date, meeting date, payment date, or another meaning that you can explain. Add a place, programme, site, or organisation when the topic could otherwise refer to several areas. If a boundary is genuinely unknown, leave it visible in the checklist and resolve it before sending instead of guessing.' },
|
|
49
|
+
{ type: 'table', headers: ['Request detail', 'Useful wording', 'Decision it supports'], rows: [['Information set', 'Final agendas and approved minutes', 'Which records should be searched?'], ['Time period', 'From 2025-01-01 to 2025-12-31', 'Which records are inside the request?'], ['Geographic scope', 'North district service area', 'Which place or programme is relevant?'], ['Format', 'Machine-readable table such as CSV', 'How can the result be reused or checked?']] },
|
|
50
|
+
{ type: 'title', text: 'Review the Draft Before You Send It', level: 2 },
|
|
51
|
+
{ type: 'paragraph', html: 'The generated text keeps your facts together and places guidance in a separate review strip. A green checklist item means the minimum detail is present; a review item means you should supply or confirm a boundary. A warning about broad wording is a prompt to name the record, field, event, or measurable set more precisely.' },
|
|
52
|
+
{ type: 'list', items: ['Confirm that the recipient is the body currently accepting this kind of request.', 'Check that every line asks for one identifiable information set rather than a whole subject area.', 'Use a closed date range and a geographic boundary that match the question.', 'State a preferred format without assuming the recipient must create a new file.', 'Record attachments, identifiers, the final text, and the channel used to submit it.'] },
|
|
53
|
+
{ type: 'tip', title: 'Specific does not mean exhaustive', html: 'A short request with a named record type, bounded period, and useful identifiers is often easier to search than a long narrative. Keep context that helps locate the records, but remove background that does not change what you are asking for.' },
|
|
54
|
+
{ type: 'title', text: 'Know What the Builder Cannot Decide', level: 2 },
|
|
55
|
+
{ type: 'paragraph', html: 'This is a country-agnostic writing aid. It does not identify the competent authority, calculate a statutory deadline, decide whether information must be disclosed, guarantee a particular format, file the request, or provide legal advice. The receiving body\'s current rules remain the source for those questions.' },
|
|
56
|
+
{ type: 'paragraph', html: 'Take extra care with personal or sensitive data, undefined terms, mixed date meanings, and requests that ask an organisation to create an opinion or analysis it may not hold. The tool can make those risks visible, but only you and the relevant authority can decide what is appropriate under the applicable regime.' },
|
|
57
|
+
{ type: 'tip', title: 'Keep the evidence trail', html: 'Save the exact text you submitted, the date, the destination, attachments, and any acknowledgement. That record helps you compare the reply with the question you actually asked and correct the next request without relying on memory.' },
|
|
58
|
+
],
|
|
59
|
+
faq: [
|
|
60
|
+
{ question: 'What should I ask for?', answer: 'Ask for an identifiable information set, record, field, or measurable count. Separate unrelated sets into different request lines.' },
|
|
61
|
+
{ question: 'Does this tool know which authority to contact?', answer: 'No. Verify the recipient, jurisdiction, deadline, exemptions, and filing channel using current local guidance.' },
|
|
62
|
+
{ question: 'Why do dates and geographic scope matter?', answer: 'They narrow the search boundary and reduce ambiguity. Use matching date meanings and name the place or programme covered.' },
|
|
63
|
+
{ question: 'Can I request personal or sensitive information?', answer: 'Include only details that are necessary and appropriate, then check the recipient\'s current privacy and access guidance.' },
|
|
64
|
+
],
|
|
65
|
+
bibliography,
|
|
66
|
+
howTo: [
|
|
67
|
+
{ name: 'Name the recipient', text: 'Enter the likely authority or organisation and verify its current request channel.' },
|
|
68
|
+
{ name: 'Split the information', text: 'Write one identifiable record, field, information set, or count per line.' },
|
|
69
|
+
{ name: 'Bound the search', text: 'Add matching start and end dates, geographic scope, and useful identifiers.' },
|
|
70
|
+
{ name: 'Choose delivery details', text: 'State a preferred format and a reply route without assuming a new format can be created.' },
|
|
71
|
+
{ name: 'Review and keep a copy', text: 'Resolve checklist warnings and save the final text with the submission details.' },
|
|
72
|
+
],
|
|
73
|
+
schemas: [softwareApplication, faqPage, howTo] as unknown as Record<string, unknown>[],
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const englishContent = content;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { AccessRequestLocaleContent } from '../entry';
|
|
4
|
+
import type { AccessRequestUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const ui: AccessRequestUI = {
|
|
7
|
+
eyebrow: 'CIVIC PAPER TRAIL', introHeading: 'Da forma a la pregunta antes de enviarla.', introText: 'Empieza por el destino, nombra un conjunto de información por línea y añade los límites que permiten localizar el registro.', targetHeading: 'Fija el destino', targetPrompt: '¿Quién puede responder?', questionPrompt: 'Un conjunto cada vez', boundaryHeading: 'Dibuja los límites', boundaryPrompt: '¿Qué lo hace localizable?', reviewWarningsHeading: 'Revisar antes de enviar',
|
|
8
|
+
recipientLabel: 'Autoridad o destinatario', recipientPlaceholder: 'Departamento, organismo, archivo u organización', subjectLabel: 'Asunto', subjectPlaceholder: 'Los registros o datos que quieres localizar', itemsLabel: 'Información solicitada', itemPlaceholder: 'Pide un conjunto de información, registro o campo identificable', addItem: 'Añadir otra línea de solicitud', removeItem: 'Eliminar esta línea', periodLabel: 'Periodo', periodFrom: 'Desde', periodTo: 'Hasta', geographyLabel: 'Ámbito geográfico', geographyPlaceholder: 'Ciudad, distrito, sede, zona del programa o nacional', formatLabel: 'Formato preferido', formatPlaceholder: 'Elige un formato de entrega', formatEmail: 'Copia electrónica por correo', formatCsv: 'Tabla legible por máquinas como CSV', formatPdf: 'PDF o documento con búsqueda', formatOriginal: 'Formato original que conserve la autoridad', deliveryLabel: 'Datos de entrega', deliveryPlaceholder: 'Correo, dirección postal o una vía segura de respuesta', contactLabel: 'Contacto opcional', contactPlaceholder: 'Teléfono, referencia o canal de respuesta preferido', attachmentsLabel: 'Adjuntos o identificadores', attachmentsPlaceholder: 'Nombres de archivo, números de registro, enlaces o contexto útil', noAttachments: 'No hacen falta adjuntos ni identificadores', savedCopy: 'He guardado una copia del texto final', presetLabel: 'Empieza con un ejemplo concreto', presetRecords: 'Registros de reuniones', presetSpending: 'Registros de gastos', presetMeetings: 'Quejas sobre servicios', generateAction: 'Crear borrador de solicitud', resetAction: 'Borrar borrador', resultHeading: 'Borrador de solicitud', resultIntro: 'Revisa cada dato y edita el texto final antes de copiarlo. Las orientaciones y advertencias quedan fuera del texto que enviarás.', copyAction: 'Copiar Markdown', printAction: 'Imprimir o guardar como PDF', copied: 'Copiado al portapapeles', noResult: 'Añade un destinatario, un asunto y al menos una línea para ver la trazabilidad.', checklistHeading: 'Trazabilidad antes del envío', completeLabel: 'Listo', reviewLabel: 'Revisar', checklistRecipient: 'El destinatario está nombrado', checklistScope: 'Cada línea identifica un conjunto solicitables', checklistPeriod: 'El periodo está acotado', checklistFormat: 'El formato preferido está indicado', checklistAttachments: 'Adjuntos e identificadores están contemplados', checklistCopy: 'Hay una copia guardada', methodHeading: 'Método aplicado', methodText: 'El creador convierte un tema amplio en una solicitud trazable: un conjunto por línea, un destinatario, un intervalo de fechas, un límite geográfico, un formato preferido y una vía de respuesta. Solo ordena los datos que aportas y nunca añade una base legal, un plazo, una autoridad o un hecho.', limitsHeading: 'Lo que esta herramienta no decide', limitsText: 'No identifica la autoridad competente, calcula plazos legales, garantiza la divulgación, presenta la solicitud, clasifica registros según la ley local ni ofrece asesoramiento jurídico. Comprueba las instrucciones vigentes del organismo receptor antes de enviarla.', edgeCasesHeading: 'Casos especiales y avisos de datos', edgeCasesText: 'Expresiones amplias como "todos los documentos" pueden ser difíciles de buscar. Evita términos indefinidos, significados mezclados de las fechas, datos personales innecesarios y peticiones de un análisis nuevo cuando necesitas un registro existente. Puede que algunos formatos no estén disponibles.', statusReady: 'El borrador contiene la trazabilidad mínima completa.', statusReview: 'El borrador sirve como punto de partida, pero necesita revisión.', missingRecipient: 'Nombra la autoridad o el destinatario antes de enviar.', missingItems: 'Añade al menos un conjunto de información específico.', missingPeriod: 'Añade fecha inicial y final o explica el límite que falta.', broadItem: 'Esta línea puede ser demasiado amplia. Nombra un tipo de registro, campo, evento o conjunto medible.', missingFormat: 'Elige cómo quieres recibir la información.', missingGeography: 'Añade un lugar o explica por qué la solicitud es nacional.', missingDelivery: 'Añade una vía para que el destinatario responda.', noCopyWarning: 'Guarda el texto final y los datos del envío antes de enviarlo.', itemNumber: 'Línea de solicitud',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const softwareApplication: SoftwareApplication = { '@type': 'SoftwareApplication', name: 'Creador de solicitudes de acceso a la información', applicationCategory: 'UtilitiesApplication', operatingSystem: 'Any', description: 'Redacta una solicitud precisa y trazable con alcance, fechas, formato y vía de respuesta.', url: 'https://gamebob.dev/es/redactor-solicitud-acceso-informacion', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' } };
|
|
12
|
+
const faqPage: FAQPage = { '@type': 'FAQPage', mainEntity: [
|
|
13
|
+
{ '@type': 'Question', name: '¿Qué debería solicitar?', acceptedAnswer: { '@type': 'Answer', text: 'Pide un conjunto de información, registro, campo o recuento medible que se pueda identificar. Separa los conjuntos independientes en líneas distintas.' } },
|
|
14
|
+
{ '@type': 'Question', name: '¿La herramienta sabe a qué autoridad debo escribir?', acceptedAnswer: { '@type': 'Answer', text: 'No. Debes identificar al destinatario probable y comprobar sus instrucciones actuales. El creador no determina la jurisdicción, los plazos ni las excepciones.' } },
|
|
15
|
+
{ '@type': 'Question', name: '¿Por qué importan las fechas y el ámbito geográfico?', acceptedAnswer: { '@type': 'Answer', text: 'Acotan la búsqueda y reducen la ambigüedad. Usa el mismo significado para ambas fechas y nombra el lugar o programa incluido.' } },
|
|
16
|
+
{ '@type': 'Question', name: '¿Puedo solicitar datos personales o sensibles?', acceptedAnswer: { '@type': 'Answer', text: 'Incluye solo los datos necesarios y adecuados. Las reglas de acceso y privacidad cambian según la jurisdicción, así que revisa las indicaciones del destinatario.' } },
|
|
17
|
+
] };
|
|
18
|
+
const howTo: HowTo = { '@type': 'HowTo', name: 'Redactar una solicitud de información precisa', step: [
|
|
19
|
+
{ '@type': 'HowToStep', name: 'Nombra al destinatario', text: 'Introduce la autoridad, departamento, archivo u organización que probablemente conserva la información y verifica su canal vigente.' },
|
|
20
|
+
{ '@type': 'HowToStep', name: 'Separa la información', text: 'Escribe un conjunto solicitables por línea. Nombra el tipo de registro, sus campos, el evento o el recuento.' },
|
|
21
|
+
{ '@type': 'HowToStep', name: 'Acota la búsqueda', text: 'Añade fecha inicial, fecha final, ámbito geográfico e identificadores que faciliten localizar el material.' },
|
|
22
|
+
{ '@type': 'HowToStep', name: 'Elige los datos de entrega', text: 'Indica un formato preferido y una vía fiable de respuesta, sin dar por hecho que podrán crear un formato nuevo.' },
|
|
23
|
+
{ '@type': 'HowToStep', name: 'Revisa y guarda una copia', text: 'Lee el Markdown, resuelve los avisos, guarda el texto y los datos del envío y utiliza el canal verificado.' },
|
|
24
|
+
] };
|
|
25
|
+
|
|
26
|
+
export const content: AccessRequestLocaleContent = { slug: 'redactor-solicitud-acceso-informacion', title: 'Creador de solicitudes de acceso a la información', description: 'Redacta una solicitud precisa con destinatario, líneas concretas, fechas, ámbito geográfico, formato y lista de comprobación.', ui, seo: [
|
|
27
|
+
{ type: 'title', text: 'Escribe una solicitud de información que se pueda localizar', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Una solicitud puede ser educada y aun así difícil de responder cuando el asunto es amplio, faltan fechas o mezcla preguntas independientes. Este creador convierte los datos que ya conoces en una trazabilidad revisable: quién recibe la solicitud, qué registros buscas, qué periodo y lugar importan y cómo podrían entregarte la respuesta.' },
|
|
29
|
+
{ type: 'title', text: 'Pon un límite a la búsqueda', level: 2 },
|
|
30
|
+
{ type: 'paragraph', html: 'Usa el mismo significado para las dos fechas: fecha de publicación, reunión, pago u otro criterio que puedas explicar. Añade lugar, programa, sede u organización. Si un límite es realmente desconocido, déjalo visible en la lista y resuélvelo antes de enviar en lugar de inventarlo.' },
|
|
31
|
+
{ type: 'table', headers: ['Detalle', 'Redacción útil', 'Decisión que ayuda'], rows: [['Conjunto de información', 'Agendas finales y actas aprobadas', '¿Qué registros hay que buscar?'], ['Periodo', 'Del 01/01/2025 al 31/12/2025', '¿Qué registros entran?'], ['Ámbito geográfico', 'Zona de servicios del distrito norte', '¿Qué lugar o programa corresponde?'], ['Formato', 'Tabla legible por máquinas como CSV', '¿Cómo se puede reutilizar o comprobar?']] },
|
|
32
|
+
{ type: 'title', text: 'Revisa el borrador antes de enviarlo', level: 2 },
|
|
33
|
+
{ type: 'paragraph', html: 'El texto generado mantiene juntos tus datos y deja las orientaciones en una franja de revisión separada. Un elemento completo indica que existe el detalle mínimo; una advertencia te pide concretar un nombre, una fecha, un lugar o un conjunto medible.' },
|
|
34
|
+
{ type: 'list', items: ['Confirma que el destinatario acepta actualmente este tipo de solicitud.', 'Comprueba que cada línea pide un conjunto identificable y no un tema entero.', 'Usa un periodo cerrado y un ámbito geográfico coherente.', 'Indica un formato preferido sin suponer que el organismo deba crear un archivo nuevo.', 'Guarda adjuntos, identificadores, texto final y canal de envío.'] },
|
|
35
|
+
{ type: 'tip', title: 'Concreto no significa exhaustivo', html: 'Una solicitud corta con un tipo de registro, un periodo y buenos identificadores suele ser más fácil de buscar que una narración larga. Conserva el contexto útil y elimina lo que no cambie la petición.' },
|
|
36
|
+
{ type: 'title', text: 'Conoce los límites del creador', level: 2 },
|
|
37
|
+
{ type: 'paragraph', html: 'Es una ayuda de redacción independiente del país. No identifica la autoridad competente, calcula plazos, garantiza la divulgación, presenta la solicitud, decide excepciones ni ofrece asesoramiento jurídico. Para esas cuestiones manda la guía vigente del organismo receptor.' },
|
|
38
|
+
{ type: 'tip', title: 'Conserva la trazabilidad', html: 'Guarda el texto exacto, la fecha, el destinatario, los adjuntos y cualquier acuse. Así podrás comparar la respuesta con la pregunta que realmente hiciste.' },
|
|
39
|
+
{ type: 'title', text: 'Preparar una respuesta aprovechable', level: 2 },
|
|
40
|
+
{ type: 'paragraph', html: 'Indica los campos o el tipo de registro que necesitas y conserva juntos la solicitud y cualquier respuesta recibida.' },
|
|
41
|
+
], faq: [
|
|
42
|
+
{ question: '¿Qué debería solicitar?', answer: 'Pide un conjunto de información, registro, campo o recuento identificable y separa los conjuntos independientes.' },
|
|
43
|
+
{ question: '¿La herramienta sabe a qué autoridad escribir?', answer: 'No. Verifica destinatario, jurisdicción, plazo, excepciones y canal con información local vigente.' },
|
|
44
|
+
{ question: '¿Por qué importan las fechas y el lugar?', answer: 'Acotan la búsqueda. Usa el mismo significado para las fechas y nombra el lugar o programa.' },
|
|
45
|
+
{ question: '¿Puedo solicitar datos sensibles?', answer: 'Incluye solo los datos necesarios y revisa las indicaciones actuales de acceso y privacidad.' },
|
|
46
|
+
], bibliography, howTo: [
|
|
47
|
+
{ name: 'Nombra al destinatario', text: 'Introduce la autoridad probable y verifica su canal actual.' },
|
|
48
|
+
{ name: 'Separa la información', text: 'Escribe un registro, campo o conjunto identificable por línea.' },
|
|
49
|
+
{ name: 'Acota la búsqueda', text: 'Añade fechas coherentes, ámbito geográfico e identificadores.' },
|
|
50
|
+
{ name: 'Elige los datos de entrega', text: 'Indica formato y vía de respuesta sin suponer un archivo nuevo.' },
|
|
51
|
+
{ name: 'Revisa y guarda una copia', text: 'Resuelve los avisos y guarda el texto junto con los datos del envío.' },
|
|
52
|
+
], schemas: [softwareApplication, faqPage, howTo] as unknown as Record<string, unknown>[] };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
|
|
2
|
+
import { bibliography } from '../bibliography';
|
|
3
|
+
import type { AccessRequestLocaleContent } from '../entry';
|
|
4
|
+
import type { AccessRequestUI } from '../ui';
|
|
5
|
+
|
|
6
|
+
const ui: AccessRequestUI = {
|
|
7
|
+
eyebrow: 'CIVIC PAPER TRAIL', introHeading: 'Cadrez la question avant de l envoyer.', introText: 'Commencez par le destinataire, indiquez un ensemble demandable par ligne, puis ajoutez les limites qui rendent le document repérable.', targetHeading: 'Définir le destinataire', targetPrompt: 'Qui peut répondre ?', questionPrompt: 'Un ensemble à la fois', boundaryHeading: 'Tracer les limites', boundaryPrompt: 'Qu est-ce qui le rend repérable ?', reviewWarningsHeading: 'Vérifier avant l envoi',
|
|
8
|
+
recipientLabel: 'Autorité ou destinataire', recipientPlaceholder: 'Service, organisme, archive ou organisation', subjectLabel: 'Objet', subjectPlaceholder: 'Les documents ou informations à retrouver', itemsLabel: 'Informations demandées', itemPlaceholder: 'Demandez un ensemble, document ou champ identifiable', addItem: 'Ajouter une ligne de demande', removeItem: 'Supprimer cette ligne', periodLabel: 'Période', periodFrom: 'Du', periodTo: 'Au', geographyLabel: 'Périmètre géographique', geographyPlaceholder: 'Ville, district, site, zone de programme ou national', formatLabel: 'Format souhaité', formatPlaceholder: 'Choisir un format de remise', formatEmail: 'Copie électronique par courriel', formatCsv: 'Tableau lisible par machine comme CSV', formatPdf: 'PDF ou document interrogeable', formatOriginal: 'Format original détenu par l autorité', deliveryLabel: 'Modalités de réponse', deliveryPlaceholder: 'Adresse électronique, postale ou moyen sûr de répondre', contactLabel: 'Coordonnées facultatives', contactPlaceholder: 'Téléphone, référence ou canal de réponse préféré', attachmentsLabel: 'Pièces jointes ou identifiants', attachmentsPlaceholder: 'Noms de fichiers, numéros, liens ou contexte utile', noAttachments: 'Aucune pièce jointe ou identifiant nécessaire', savedCopy: 'J ai enregistré une copie du texte final', presetLabel: 'Partir d un exemple ciblé', presetRecords: 'Documents de réunions', presetSpending: 'Documents de dépenses', presetMeetings: 'Réclamations sur les services', generateAction: 'Créer le brouillon', resetAction: 'Effacer le brouillon', resultHeading: 'Brouillon de demande', resultIntro: 'Vérifiez chaque fait et modifiez le texte final avant de le copier. Les conseils et avertissements restent hors du texte envoyé.', copyAction: 'Copier le Markdown', printAction: 'Imprimer ou enregistrer en PDF', copied: 'Copié dans le presse-papiers', noResult: 'Ajoutez un destinataire, un objet et au moins une ligne pour voir la trace.', checklistHeading: 'Traçabilité avant envoi', completeLabel: 'Prêt', reviewLabel: 'À vérifier', checklistRecipient: 'Destinataire nommé', checklistScope: 'Chaque ligne désigne un ensemble demandable', checklistPeriod: 'Période délimitée', checklistFormat: 'Format souhaité indiqué', checklistAttachments: 'Pièces et identifiants pris en compte', checklistCopy: 'Une copie est conservée', methodHeading: 'Méthode appliquée', methodText: 'Le générateur transforme un sujet large en demande traçable: un ensemble par ligne, un destinataire nommé, une période claire, une limite géographique, un format souhaité et un moyen de réponse utilisable. Il réorganise seulement vos indications et n ajoute jamais de base juridique, délai, autorité ou fait.', limitsHeading: 'Ce que l outil ne décide pas', limitsText: 'Il n identifie pas l autorité compétente, ne détermine pas de délai légal, ne garantit pas la communication, ne dépose pas la demande, ne classe pas un document selon le droit local et ne fournit pas de conseil juridique. Vérifiez les consignes actuelles du destinataire.', edgeCasesHeading: 'Cas particuliers et données', edgeCasesText: 'Des expressions larges comme "tous les documents" sont difficiles à rechercher. Évitez les termes indéfinis, les sens de date mélangés, les données personnelles inutiles et les demandes d analyse nouvelle quand vous cherchez un document existant. Certains formats peuvent être indisponibles.', statusReady: 'Le brouillon contient la trace minimale complète.', statusReview: 'Le brouillon est un bon point de départ mais doit être vérifié.', missingRecipient: 'Nommez l autorité ou le destinataire avant l envoi.', missingItems: 'Ajoutez au moins un ensemble d informations précis.', missingPeriod: 'Ajoutez un début et une fin ou expliquez la limite absente.', broadItem: 'Cette ligne semble peut-être trop large. Nommez un type, champ, événement ou ensemble mesurable.', missingFormat: 'Choisissez le mode de remise des informations.', missingGeography: 'Ajoutez un lieu ou expliquez pourquoi la demande est nationale.', missingDelivery: 'Ajoutez un moyen permettant au destinataire de répondre.', noCopyWarning: 'Enregistrez le texte final et les détails d envoi avant de transmettre.', itemNumber: 'Ligne de demande',
|
|
9
|
+
};
|
|
10
|
+
const softwareApplication: SoftwareApplication = { '@type': 'SoftwareApplication', name: 'Générateur de demande d accès à l information', applicationCategory: 'UtilitiesApplication', operatingSystem: 'Any', description: 'Rédigez une demande précise et traçable avec périmètre, dates, format et moyen de réponse.', url: 'https://gamebob.dev/fr/redacteur-demande-acces-information', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' } };
|
|
11
|
+
const faqPage: FAQPage = { '@type': 'FAQPage', mainEntity: [
|
|
12
|
+
{ '@type': 'Question', name: 'Que dois-je demander ?', acceptedAnswer: { '@type': 'Answer', text: 'Demandez un ensemble, document, champ ou décompte mesurable identifiable. Séparez les ensembles indépendants en lignes différentes.' } },
|
|
13
|
+
{ '@type': 'Question', name: 'L outil connaît-il l autorité à contacter ?', acceptedAnswer: { '@type': 'Answer', text: 'Non. Identifiez le destinataire probable et vérifiez ses consignes actuelles. L outil ne détermine ni compétence, ni délai, ni exception.' } },
|
|
14
|
+
{ '@type': 'Question', name: 'Pourquoi les dates et le périmètre comptent-ils ?', acceptedAnswer: { '@type': 'Answer', text: 'Ils réduisent la recherche et l ambiguïté. Donnez le même sens aux deux dates et nommez le lieu ou le programme concerné.' } },
|
|
15
|
+
{ '@type': 'Question', name: 'Puis-je demander des données personnelles ?', acceptedAnswer: { '@type': 'Answer', text: 'N incluez que les données nécessaires et appropriées. Les règles d accès et de confidentialité varient, vérifiez donc les consignes du destinataire.' } },
|
|
16
|
+
] };
|
|
17
|
+
const howTo: HowTo = { '@type': 'HowTo', name: 'Rédiger une demande d information précise', step: [
|
|
18
|
+
{ '@type': 'HowToStep', name: 'Nommer le destinataire', text: 'Saisissez l autorité, le service, l archive ou l organisation qui détient probablement l information et vérifiez son canal actuel.' },
|
|
19
|
+
{ '@type': 'HowToStep', name: 'Séparer l information', text: 'Écrivez un ensemble demandable par ligne et nommez le type de document, les champs, l événement ou le décompte.' },
|
|
20
|
+
{ '@type': 'HowToStep', name: 'Délimiter la recherche', text: 'Ajoutez les dates, le périmètre géographique et les identifiants qui facilitent la localisation.' },
|
|
21
|
+
{ '@type': 'HowToStep', name: 'Choisir la remise', text: 'Indiquez un format souhaité et un moyen fiable de réponse sans supposer qu un nouveau fichier sera créé.' },
|
|
22
|
+
{ '@type': 'HowToStep', name: 'Vérifier et garder une copie', text: 'Lisez le Markdown, corrigez les points à revoir, conservez le texte et les détails d envoi puis utilisez le canal vérifié.' },
|
|
23
|
+
] };
|
|
24
|
+
export const content: AccessRequestLocaleContent = { slug: 'redacteur-demande-acces-information', title: 'Générateur de demande d accès à l information', description: 'Rédigez une demande précise avec destinataire, lignes ciblées, dates, périmètre, format et liste avant envoi.', ui, seo: [
|
|
25
|
+
{ type: 'title', text: 'Écrire une demande d information repérable', level: 2 },
|
|
26
|
+
{ type: 'paragraph', html: 'Une demande peut être polie et difficile à traiter si son sujet est vaste, ses dates absentes ou ses questions mélangées. Ce générateur transforme les détails connus en trace vérifiable: destinataire, documents recherchés, période, lieu et mode de réponse.' },
|
|
27
|
+
{ type: 'title', text: 'Donner une limite à la recherche', level: 2 },
|
|
28
|
+
{ type: 'paragraph', html: 'Utilisez le même sens pour les deux dates: publication, réunion, paiement ou autre sens explicable. Ajoutez un lieu, un programme, un site ou une organisation. Si une limite est inconnue, laissez-le visible et ne devinez pas.' },
|
|
29
|
+
{ type: 'table', headers: ['Détail', 'Formulation utile', 'Décision soutenue'], rows: [['Ensemble', 'Ordres du jour finaux et procès-verbaux approuvés', 'Quels documents rechercher ?'], ['Période', 'Du 01/01/2025 au 31/12/2025', 'Quels documents inclure ?'], ['Périmètre', 'Zone de service du district nord', 'Quel lieu est concerné ?'], ['Format', 'Tableau lisible par machine comme CSV', 'Comment vérifier le résultat ?']] },
|
|
30
|
+
{ type: 'title', text: 'Vérifier le brouillon avant envoi', level: 2 },
|
|
31
|
+
{ type: 'paragraph', html: 'Le texte produit rassemble vos faits et place les conseils dans une zone séparée. Un élément complet signale la présence du minimum attendu ; un avertissement invite à préciser un document, un champ, une date, un lieu ou un ensemble mesurable.' },
|
|
32
|
+
{ type: 'list', items: ['Confirmez que le destinataire accepte actuellement ce type de demande.', 'Vérifiez que chaque ligne vise un ensemble identifiable, non un sujet entier.', 'Utilisez une période fermée et un périmètre cohérent.', 'Indiquez un format préféré sans imposer la création d un fichier.', 'Conservez les pièces, identifiants, texte final et canal utilisé.'] },
|
|
33
|
+
{ type: 'tip', title: 'Précis ne veut pas dire exhaustif', html: 'Une demande courte avec un type de document, une période et des identifiants utiles est souvent plus facile à rechercher qu un long récit. Gardez le contexte qui aide à localiser.' },
|
|
34
|
+
{ type: 'title', text: 'Connaître les limites du générateur', level: 2 },
|
|
35
|
+
{ type: 'paragraph', html: 'C est une aide de rédaction indépendante du pays. Elle n identifie pas l autorité, ne calcule pas de délai, ne garantit pas la communication, ne dépose pas la demande et ne donne pas de conseil juridique. Les règles actuelles du destinataire restent déterminantes.' },
|
|
36
|
+
{ type: 'tip', title: 'Conserver la trace', html: 'Archivez le texte exact, la date, le destinataire, les pièces et tout accusé. Vous pourrez comparer la réponse avec la question réellement envoyée.' },
|
|
37
|
+
{ type: 'title', text: 'Préparer une réponse exploitable', level: 2 },
|
|
38
|
+
{ type: 'paragraph', html: 'Indiquez les champs ou le type de document utiles à votre objectif, puis gardez une copie de la demande et de toute réponse reçue.' },
|
|
39
|
+
], faq: [
|
|
40
|
+
{ question: 'Que dois-je demander ?', answer: 'Demandez un document, champ, ensemble ou décompte identifiable et séparez les ensembles indépendants.' },
|
|
41
|
+
{ question: 'L outil connaît-il l autorité ?', answer: 'Non. Vérifiez destinataire, compétence, délai, exceptions et canal avec les consignes locales actuelles.' },
|
|
42
|
+
{ question: 'Pourquoi les dates et le lieu comptent-ils ?', answer: 'Ils bornent la recherche. Utilisez le même sens pour les dates et nommez le lieu ou programme.' },
|
|
43
|
+
{ question: 'Puis-je demander des données sensibles ?', answer: 'Incluez seulement les données nécessaires et vérifiez les règles actuelles d accès et de confidentialité.' },
|
|
44
|
+
], bibliography, howTo: [
|
|
45
|
+
{ name: 'Nommer le destinataire', text: 'Saisissez l autorité probable et vérifiez son canal actuel.' },
|
|
46
|
+
{ name: 'Séparer l information', text: 'Écrivez un document, champ ou ensemble identifiable par ligne.' },
|
|
47
|
+
{ name: 'Délimiter la recherche', text: 'Ajoutez dates cohérentes, périmètre et identifiants.' },
|
|
48
|
+
{ name: 'Choisir la remise', text: 'Indiquez format et moyen de réponse sans supposer un nouveau fichier.' },
|
|
49
|
+
{ name: 'Vérifier et garder une copie', text: 'Corrigez les avertissements et conservez texte et détails d envoi.' },
|
|
50
|
+
], schemas: [softwareApplication, faqPage, howTo] as unknown as Record<string, unknown>[] };
|