accessify-widget 0.1.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 (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/accessify.min.js +2 -0
  4. package/dist/accessify.min.js.map +1 -0
  5. package/dist/accessify.mjs +6 -0
  6. package/dist/accessify.mjs.map +1 -0
  7. package/dist/alt-text-CLxbmwG6.js +567 -0
  8. package/dist/alt-text-CLxbmwG6.js.map +1 -0
  9. package/dist/animation-stop-DXebPS8D.js +88 -0
  10. package/dist/animation-stop-DXebPS8D.js.map +1 -0
  11. package/dist/auto-scan-pg-09o7A.js +885 -0
  12. package/dist/auto-scan-pg-09o7A.js.map +1 -0
  13. package/dist/big-cursor-B2UKu9dQ.js +88 -0
  14. package/dist/big-cursor-B2UKu9dQ.js.map +1 -0
  15. package/dist/color-blind-0LFng55r.js +108 -0
  16. package/dist/color-blind-0LFng55r.js.map +1 -0
  17. package/dist/contrast-DCkE0NXZ.js +64 -0
  18. package/dist/contrast-DCkE0NXZ.js.map +1 -0
  19. package/dist/dyslexia-font-wONgIy2T.js +77 -0
  20. package/dist/dyslexia-font-wONgIy2T.js.map +1 -0
  21. package/dist/focus-highlight-CjERyyUF.js +93 -0
  22. package/dist/focus-highlight-CjERyyUF.js.map +1 -0
  23. package/dist/hide-images-DJwmsV2C.js +39 -0
  24. package/dist/hide-images-DJwmsV2C.js.map +1 -0
  25. package/dist/index-CUQfpnwR.js +6520 -0
  26. package/dist/index-CUQfpnwR.js.map +1 -0
  27. package/dist/keyboard-nav-BdPyLaZt.js +312 -0
  28. package/dist/keyboard-nav-BdPyLaZt.js.map +1 -0
  29. package/dist/line-height-BT98qgEF.js +54 -0
  30. package/dist/line-height-BT98qgEF.js.map +1 -0
  31. package/dist/link-highlight-DBGm067Y.js +87 -0
  32. package/dist/link-highlight-DBGm067Y.js.map +1 -0
  33. package/dist/loader.min.js +1 -0
  34. package/dist/page-structure-2X8mOSpC.js +166 -0
  35. package/dist/page-structure-2X8mOSpC.js.map +1 -0
  36. package/dist/reading-guide-VT8NciIL.js +122 -0
  37. package/dist/reading-guide-VT8NciIL.js.map +1 -0
  38. package/dist/reading-mask-BABChuCz.js +76 -0
  39. package/dist/reading-mask-BABChuCz.js.map +1 -0
  40. package/dist/saturation-D8ZXpWAN.js +59 -0
  41. package/dist/saturation-D8ZXpWAN.js.map +1 -0
  42. package/dist/spacing-DENai3JU.js +106 -0
  43. package/dist/spacing-DENai3JU.js.map +1 -0
  44. package/dist/text-align-BDRPqPvl.js +51 -0
  45. package/dist/text-align-BDRPqPvl.js.map +1 -0
  46. package/dist/text-simplify-CELklw5A.js +223 -0
  47. package/dist/text-simplify-CELklw5A.js.map +1 -0
  48. package/dist/text-size-B-uv436p.js +69 -0
  49. package/dist/text-size-B-uv436p.js.map +1 -0
  50. package/dist/tts-02b9iV0h.js +505 -0
  51. package/dist/tts-02b9iV0h.js.map +1 -0
  52. package/dist/widget.js +2 -0
  53. package/dist/widget.js.map +1 -0
  54. package/package.json +61 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-align-BDRPqPvl.js","sources":["../src/features/text-align.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\ntype AlignMode = 'off' | 'left' | 'center' | 'right' | 'justify';\n\nexport default function createTextAlignModule(): FeatureModule {\n let currentMode: AlignMode = 'off';\n const STYLE_ID = 'accessify-text-align';\n const STORAGE_KEY = 'accessify-text-align-mode';\n\n function applyStyles(mode: AlignMode) {\n let styleEl = document.getElementById(STYLE_ID);\n if (mode === 'off') {\n styleEl?.remove();\n return;\n }\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n styleEl.textContent = `\n body, body * {\n text-align: ${mode} !important;\n }\n `;\n }\n\n function activate() {\n const saved = localStorage.getItem(STORAGE_KEY) as AlignMode;\n currentMode = saved || 'left';\n applyStyles(currentMode);\n }\n\n function deactivate() {\n currentMode = 'off';\n applyStyles('off');\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'text-align',\n name: () => 'Text Align',\n description: 'Change text alignment across the page',\n icon: 'text-align',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'text-align', enabled: currentMode !== 'off', value: currentMode }),\n setState: (mode: AlignMode) => {\n currentMode = mode;\n applyStyles(mode);\n localStorage.setItem(STORAGE_KEY, mode);\n },\n };\n}\n"],"names":[],"mappings":"AAIA,SAAwB,wBAAuC;AAC7D,MAAI,cAAyB;AAC7B,QAAM,WAAW;AACjB,QAAM,cAAc;AAEpB,WAAS,YAAY,MAAiB;AACpC,QAAI,UAAU,SAAS,eAAe,QAAQ;AAC9C,QAAI,SAAS,OAAO;AAClB,eAAS,OAAA;AACT;AAAA,IACF;AACA,QAAI,CAAC,SAAS;AACZ,gBAAU,SAAS,cAAc,OAAO;AACxC,cAAQ,KAAK;AACb,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AACA,YAAQ,cAAc;AAAA;AAAA,sBAEJ,IAAI;AAAA;AAAA;AAAA,EAGxB;AAEA,WAAS,WAAW;AAClB,UAAM,QAAQ,aAAa,QAAQ,WAAW;AAC9C,kBAAc,SAAS;AACvB,gBAAY,WAAW;AAAA,EACzB;AAEA,WAAS,aAAa;AACpB,kBAAc;AACd,gBAAY,KAAK;AACjB,iBAAa,WAAW,WAAW;AAAA,EACrC;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,MAAM;AAAA,IACZ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU,OAAqB,EAAE,IAAI,cAAc,SAAS,gBAAgB,OAAO,OAAO;IAC1F,UAAU,CAAC,SAAoB;AAC7B,oBAAc;AACd,kBAAY,IAAI;AAChB,mBAAa,QAAQ,aAAa,IAAI;AAAA,IACxC;AAAA,EAAA;AAEJ;"}
@@ -0,0 +1,223 @@
1
+ function createTextSimplifyModule(aiService, lang = "de") {
2
+ let enabled = false;
3
+ let level = "einfache";
4
+ let savedParagraphs = [];
5
+ let abortController = null;
6
+ let overlayEl = null;
7
+ const STORAGE_KEY = "accessify-text-simplify";
8
+ const SIMPLIFIED_ATTR = "data-accessify-simplified";
9
+ const ORIGINAL_ATTR = "data-accessify-original";
10
+ function getTextElements() {
11
+ const selectors = "p, li, td, th, blockquote, figcaption, .hero-subtitle, h1, h2, h3, h4, h5, h6";
12
+ const elements = [];
13
+ const seen = /* @__PURE__ */ new Set();
14
+ document.querySelectorAll(selectors).forEach((el) => {
15
+ const htmlEl = el;
16
+ if (htmlEl.closest("#accessify-root")) return;
17
+ if (htmlEl.offsetParent === null && htmlEl.style.display !== "fixed") return;
18
+ const text = htmlEl.textContent?.trim() || "";
19
+ if (text.length < 20) return;
20
+ if (seen.has(htmlEl)) return;
21
+ let dominated = false;
22
+ for (const s of seen) {
23
+ if (s.contains(htmlEl)) {
24
+ dominated = true;
25
+ break;
26
+ }
27
+ }
28
+ if (dominated) return;
29
+ seen.add(htmlEl);
30
+ elements.push(htmlEl);
31
+ });
32
+ return elements;
33
+ }
34
+ function markLoading(el) {
35
+ el.style.opacity = "0.5";
36
+ el.style.transition = "opacity 0.3s ease";
37
+ }
38
+ function clearLoading(el) {
39
+ el.style.opacity = "";
40
+ el.style.transition = "";
41
+ }
42
+ function showProgress(current, total) {
43
+ if (!overlayEl) {
44
+ overlayEl = document.createElement("div");
45
+ overlayEl.setAttribute("role", "status");
46
+ overlayEl.setAttribute("aria-live", "polite");
47
+ Object.assign(overlayEl.style, {
48
+ position: "fixed",
49
+ bottom: "80px",
50
+ right: "24px",
51
+ zIndex: "2147483645",
52
+ padding: "10px 18px",
53
+ background: "#1a1a2e",
54
+ color: "#4ea8de",
55
+ borderRadius: "10px",
56
+ boxShadow: "0 4px 20px rgba(0,0,0,0.3)",
57
+ fontFamily: "system-ui, -apple-system, sans-serif",
58
+ fontSize: "13px",
59
+ fontWeight: "600",
60
+ display: "flex",
61
+ alignItems: "center",
62
+ gap: "8px"
63
+ });
64
+ document.body.appendChild(overlayEl);
65
+ }
66
+ const pct = Math.round(current / total * 100);
67
+ const label = lang.startsWith("de") ? `Wird vereinfacht... ${current}/${total} (${pct}%)` : `Simplifying... ${current}/${total} (${pct}%)`;
68
+ overlayEl.innerHTML = `<span style="display:inline-block;width:14px;height:14px;border:2px solid rgba(78,168,222,0.3);border-top-color:#4ea8de;border-radius:50%;animation:accessify-autospin 0.6s linear infinite"></span> ${label}`;
69
+ if (!document.getElementById("accessify-autospin-style")) {
70
+ const style = document.createElement("style");
71
+ style.id = "accessify-autospin-style";
72
+ style.textContent = "@keyframes accessify-autospin { to { transform: rotate(360deg); } }";
73
+ document.head.appendChild(style);
74
+ }
75
+ }
76
+ function showDone(count) {
77
+ if (overlayEl) {
78
+ const label = lang.startsWith("de") ? `${count} Textabschnitte vereinfacht` : `${count} text sections simplified`;
79
+ overlayEl.innerHTML = `<span style="color:#22c55e">✓</span> ${label}`;
80
+ overlayEl.style.color = "#22c55e";
81
+ setTimeout(() => removeProgress(), 3e3);
82
+ }
83
+ }
84
+ function showError(msg) {
85
+ if (overlayEl) {
86
+ overlayEl.innerHTML = `<span style="color:#ef4444">✕</span> ${msg}`;
87
+ overlayEl.style.color = "#ef4444";
88
+ setTimeout(() => removeProgress(), 5e3);
89
+ }
90
+ }
91
+ function removeProgress() {
92
+ overlayEl?.remove();
93
+ overlayEl = null;
94
+ document.getElementById("accessify-autospin-style")?.remove();
95
+ }
96
+ async function simplifyPage() {
97
+ if (!aiService) {
98
+ showProgress(0, 1);
99
+ showError(lang.startsWith("de") ? "Kein API-Key konfiguriert" : "No API key configured");
100
+ return;
101
+ }
102
+ const elements = getTextElements();
103
+ if (elements.length === 0) return;
104
+ abortController = new AbortController();
105
+ savedParagraphs = [];
106
+ for (const el of elements) {
107
+ savedParagraphs.push({ el, originalText: el.textContent || "" });
108
+ el.setAttribute(ORIGINAL_ATTR, el.innerHTML);
109
+ markLoading(el);
110
+ }
111
+ showProgress(0, elements.length);
112
+ let completed = 0;
113
+ let totalSimplified = 0;
114
+ for (const el of elements) {
115
+ if (abortController.signal.aborted) break;
116
+ const text = el.textContent?.trim() || "";
117
+ if (text.length < 20) {
118
+ clearLoading(el);
119
+ completed++;
120
+ showProgress(completed, elements.length);
121
+ continue;
122
+ }
123
+ try {
124
+ const simplified = await aiService.simplifyText(text, level, lang);
125
+ if (abortController?.signal.aborted) return;
126
+ if (simplified && simplified !== text) {
127
+ el.textContent = simplified;
128
+ el.setAttribute(SIMPLIFIED_ATTR, "true");
129
+ totalSimplified++;
130
+ }
131
+ } catch (err) {
132
+ if (err?.message?.includes("429")) {
133
+ await new Promise((r) => setTimeout(r, 8e3));
134
+ try {
135
+ const retry = await aiService.simplifyText(text, level, lang);
136
+ if (abortController?.signal.aborted) return;
137
+ if (retry && retry !== text) {
138
+ el.textContent = retry;
139
+ el.setAttribute(SIMPLIFIED_ATTR, "true");
140
+ totalSimplified++;
141
+ }
142
+ } catch {
143
+ }
144
+ } else {
145
+ console.warn("[Accessify] Failed to simplify:", err);
146
+ }
147
+ } finally {
148
+ clearLoading(el);
149
+ completed++;
150
+ if (!abortController?.signal.aborted) {
151
+ showProgress(completed, elements.length);
152
+ }
153
+ }
154
+ }
155
+ if (!abortController?.signal.aborted) {
156
+ showDone(totalSimplified);
157
+ }
158
+ }
159
+ function restorePage() {
160
+ for (const { el } of savedParagraphs) {
161
+ const original = el.getAttribute(ORIGINAL_ATTR);
162
+ if (original !== null) {
163
+ el.innerHTML = original;
164
+ el.removeAttribute(ORIGINAL_ATTR);
165
+ el.removeAttribute(SIMPLIFIED_ATTR);
166
+ clearLoading(el);
167
+ }
168
+ }
169
+ savedParagraphs = [];
170
+ }
171
+ function loadPreferences() {
172
+ const saved = localStorage.getItem(STORAGE_KEY);
173
+ if (saved) {
174
+ try {
175
+ const parsed = JSON.parse(saved);
176
+ if (parsed.level === "einfache" || parsed.level === "leichte") {
177
+ level = parsed.level;
178
+ }
179
+ } catch {
180
+ }
181
+ }
182
+ }
183
+ function savePreferences() {
184
+ localStorage.setItem(STORAGE_KEY, JSON.stringify({ level }));
185
+ }
186
+ function activate() {
187
+ if (enabled) return;
188
+ enabled = true;
189
+ loadPreferences();
190
+ simplifyPage();
191
+ }
192
+ function deactivate() {
193
+ enabled = false;
194
+ abortController?.abort();
195
+ abortController = null;
196
+ restorePage();
197
+ removeProgress();
198
+ }
199
+ return {
200
+ id: "text-simplify",
201
+ name: () => lang.startsWith("de") ? "Text vereinfachen" : "Simplify Text",
202
+ description: lang.startsWith("de") ? "Text in Einfache Sprache umwandeln" : "Simplify text for easier understanding",
203
+ icon: "simplify-text",
204
+ category: "ai",
205
+ activate,
206
+ deactivate,
207
+ getState: () => ({
208
+ id: "text-simplify",
209
+ enabled,
210
+ value: { level }
211
+ }),
212
+ setState: (newState) => {
213
+ if (newState.level && (newState.level === "einfache" || newState.level === "leichte")) {
214
+ level = newState.level;
215
+ savePreferences();
216
+ }
217
+ }
218
+ };
219
+ }
220
+ export {
221
+ createTextSimplifyModule as default
222
+ };
223
+ //# sourceMappingURL=text-simplify-CELklw5A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-simplify-CELklw5A.js","sources":["../src/features/text-simplify.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Text Simplification Feature (Auto-mode)\n// ---------------------------------------------------------------------------\n// When activated, automatically finds all visible text blocks on the page\n// and replaces them with simplified versions via the AI service.\n// When deactivated, restores the original text.\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState, AIService } from '../types';\n\ntype SimplifyLevel = 'einfache' | 'leichte';\n\ninterface TextSimplifyState {\n level: SimplifyLevel;\n}\n\ninterface SavedParagraph {\n el: HTMLElement;\n originalText: string;\n}\n\nexport default function createTextSimplifyModule(\n aiService?: AIService,\n lang: string = 'de',\n): FeatureModule {\n let enabled = false;\n let level: SimplifyLevel = 'einfache';\n let savedParagraphs: SavedParagraph[] = [];\n let abortController: AbortController | null = null;\n let overlayEl: HTMLDivElement | null = null;\n\n const STORAGE_KEY = 'accessify-text-simplify';\n const SIMPLIFIED_ATTR = 'data-accessify-simplified';\n const ORIGINAL_ATTR = 'data-accessify-original';\n\n // -------------------------------------------------------------------------\n // Find text-heavy elements on the page\n // -------------------------------------------------------------------------\n\n function getTextElements(): HTMLElement[] {\n const selectors = 'p, li, td, th, blockquote, figcaption, .hero-subtitle, h1, h2, h3, h4, h5, h6';\n const elements: HTMLElement[] = [];\n const seen = new Set<HTMLElement>();\n\n document.querySelectorAll(selectors).forEach((el) => {\n const htmlEl = el as HTMLElement;\n\n // Skip if inside the widget itself\n if (htmlEl.closest('#accessify-root')) return;\n // Skip hidden elements\n if (htmlEl.offsetParent === null && htmlEl.style.display !== 'fixed') return;\n // Skip elements with very little text\n const text = htmlEl.textContent?.trim() || '';\n if (text.length < 20) return;\n // Skip duplicates\n if (seen.has(htmlEl)) return;\n // Skip nested: if parent is already in our list, skip\n let dominated = false;\n for (const s of seen) {\n if (s.contains(htmlEl)) { dominated = true; break; }\n }\n if (dominated) return;\n\n seen.add(htmlEl);\n elements.push(htmlEl);\n });\n\n return elements;\n }\n\n // -------------------------------------------------------------------------\n // Loading overlay on individual elements\n // -------------------------------------------------------------------------\n\n function markLoading(el: HTMLElement) {\n el.style.opacity = '0.5';\n el.style.transition = 'opacity 0.3s ease';\n }\n\n function clearLoading(el: HTMLElement) {\n el.style.opacity = '';\n el.style.transition = '';\n }\n\n // -------------------------------------------------------------------------\n // Global progress indicator\n // -------------------------------------------------------------------------\n\n function showProgress(current: number, total: number) {\n if (!overlayEl) {\n overlayEl = document.createElement('div');\n overlayEl.setAttribute('role', 'status');\n overlayEl.setAttribute('aria-live', 'polite');\n Object.assign(overlayEl.style, {\n position: 'fixed',\n bottom: '80px',\n right: '24px',\n zIndex: '2147483645',\n padding: '10px 18px',\n background: '#1a1a2e',\n color: '#4ea8de',\n borderRadius: '10px',\n boxShadow: '0 4px 20px rgba(0,0,0,0.3)',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: '13px',\n fontWeight: '600',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n });\n document.body.appendChild(overlayEl);\n }\n\n const pct = Math.round((current / total) * 100);\n const label = lang.startsWith('de')\n ? `Wird vereinfacht... ${current}/${total} (${pct}%)`\n : `Simplifying... ${current}/${total} (${pct}%)`;\n overlayEl.innerHTML = `<span style=\"display:inline-block;width:14px;height:14px;border:2px solid rgba(78,168,222,0.3);border-top-color:#4ea8de;border-radius:50%;animation:accessify-autospin 0.6s linear infinite\"></span> ${label}`;\n\n // Inject keyframe if not present\n if (!document.getElementById('accessify-autospin-style')) {\n const style = document.createElement('style');\n style.id = 'accessify-autospin-style';\n style.textContent = '@keyframes accessify-autospin { to { transform: rotate(360deg); } }';\n document.head.appendChild(style);\n }\n }\n\n function showDone(count: number) {\n if (overlayEl) {\n const label = lang.startsWith('de')\n ? `${count} Textabschnitte vereinfacht`\n : `${count} text sections simplified`;\n overlayEl.innerHTML = `<span style=\"color:#22c55e\">✓</span> ${label}`;\n overlayEl.style.color = '#22c55e';\n setTimeout(() => removeProgress(), 3000);\n }\n }\n\n function showError(msg: string) {\n if (overlayEl) {\n overlayEl.innerHTML = `<span style=\"color:#ef4444\">✕</span> ${msg}`;\n overlayEl.style.color = '#ef4444';\n setTimeout(() => removeProgress(), 5000);\n }\n }\n\n function removeProgress() {\n overlayEl?.remove();\n overlayEl = null;\n document.getElementById('accessify-autospin-style')?.remove();\n }\n\n // -------------------------------------------------------------------------\n // Core: simplify all text blocks\n // -------------------------------------------------------------------------\n\n async function simplifyPage() {\n if (!aiService) {\n showProgress(0, 1);\n showError(lang.startsWith('de')\n ? 'Kein API-Key konfiguriert'\n : 'No API key configured');\n return;\n }\n\n const elements = getTextElements();\n if (elements.length === 0) return;\n\n abortController = new AbortController();\n savedParagraphs = [];\n\n // Save originals and dim all elements\n for (const el of elements) {\n savedParagraphs.push({ el, originalText: el.textContent || '' });\n el.setAttribute(ORIGINAL_ATTR, el.innerHTML);\n markLoading(el);\n }\n\n showProgress(0, elements.length);\n\n let completed = 0;\n let totalSimplified = 0;\n\n // Process one element at a time — reliable with any model (including reasoning)\n for (const el of elements) {\n if (abortController.signal.aborted) break;\n\n const text = el.textContent?.trim() || '';\n if (text.length < 20) {\n clearLoading(el);\n completed++;\n showProgress(completed, elements.length);\n continue;\n }\n\n try {\n const simplified = await aiService!.simplifyText(text, level, lang);\n if (abortController?.signal.aborted) return;\n\n if (simplified && simplified !== text) {\n el.textContent = simplified;\n el.setAttribute(SIMPLIFIED_ATTR, 'true');\n totalSimplified++;\n }\n } catch (err: any) {\n // On rate limit, wait and retry once\n if (err?.message?.includes('429')) {\n await new Promise((r) => setTimeout(r, 8000));\n try {\n const retry = await aiService!.simplifyText(text, level, lang);\n if (abortController?.signal.aborted) return;\n if (retry && retry !== text) {\n el.textContent = retry;\n el.setAttribute(SIMPLIFIED_ATTR, 'true');\n totalSimplified++;\n }\n } catch { /* skip this element */ }\n } else {\n console.warn('[Accessify] Failed to simplify:', err);\n }\n } finally {\n clearLoading(el);\n completed++;\n if (!abortController?.signal.aborted) {\n showProgress(completed, elements.length);\n }\n }\n }\n\n if (!abortController?.signal.aborted) {\n showDone(totalSimplified);\n }\n }\n\n // -------------------------------------------------------------------------\n // Restore original text\n // -------------------------------------------------------------------------\n\n function restorePage() {\n for (const { el } of savedParagraphs) {\n const original = el.getAttribute(ORIGINAL_ATTR);\n if (original !== null) {\n el.innerHTML = original;\n el.removeAttribute(ORIGINAL_ATTR);\n el.removeAttribute(SIMPLIFIED_ATTR);\n clearLoading(el);\n }\n }\n savedParagraphs = [];\n }\n\n // -------------------------------------------------------------------------\n // Preferences\n // -------------------------------------------------------------------------\n\n function loadPreferences() {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n if (parsed.level === 'einfache' || parsed.level === 'leichte') {\n level = parsed.level;\n }\n } catch {\n // use defaults\n }\n }\n }\n\n function savePreferences() {\n localStorage.setItem(STORAGE_KEY, JSON.stringify({ level }));\n }\n\n // -------------------------------------------------------------------------\n // Module lifecycle\n // -------------------------------------------------------------------------\n\n function activate() {\n if (enabled) return;\n enabled = true;\n loadPreferences();\n simplifyPage();\n }\n\n function deactivate() {\n enabled = false;\n abortController?.abort();\n abortController = null;\n restorePage();\n removeProgress();\n }\n\n // -------------------------------------------------------------------------\n // FeatureModule interface\n // -------------------------------------------------------------------------\n\n return {\n id: 'text-simplify',\n name: () => (lang.startsWith('de') ? 'Text vereinfachen' : 'Simplify Text'),\n description: lang.startsWith('de')\n ? 'Text in Einfache Sprache umwandeln'\n : 'Simplify text for easier understanding',\n icon: 'simplify-text',\n category: 'ai',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'text-simplify',\n enabled,\n value: { level } as TextSimplifyState,\n }),\n setState: (newState: Partial<TextSimplifyState>) => {\n if (newState.level && (newState.level === 'einfache' || newState.level === 'leichte')) {\n level = newState.level;\n savePreferences();\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ function createTextSizeModule() {
2
+ let currentSize = 100;
3
+ let originalFontSize = "";
4
+ const STYLE_ID = "accessify-text-size";
5
+ const STORAGE_KEY = "accessify-text-size";
6
+ const MIN_SIZE = 100;
7
+ const MAX_SIZE = 200;
8
+ const STEP = 10;
9
+ function applySize(percent) {
10
+ let styleEl = document.getElementById(STYLE_ID);
11
+ if (percent === 100) {
12
+ styleEl?.remove();
13
+ if (originalFontSize) {
14
+ document.documentElement.style.fontSize = originalFontSize;
15
+ } else {
16
+ document.documentElement.style.removeProperty("font-size");
17
+ }
18
+ return;
19
+ }
20
+ if (!styleEl) {
21
+ styleEl = document.createElement("style");
22
+ styleEl.id = STYLE_ID;
23
+ document.head.appendChild(styleEl);
24
+ }
25
+ const scale = percent / 100;
26
+ document.documentElement.style.fontSize = `${scale * 100}%`;
27
+ styleEl.textContent = `
28
+ /* accessify text-size: ${percent}% */
29
+ body { font-size: 1rem !important; }
30
+ `;
31
+ }
32
+ function clamp(value) {
33
+ return Math.min(MAX_SIZE, Math.max(MIN_SIZE, Math.round(value / STEP) * STEP));
34
+ }
35
+ function activate() {
36
+ originalFontSize = document.documentElement.style.fontSize || "";
37
+ const saved = localStorage.getItem(STORAGE_KEY);
38
+ currentSize = saved ? clamp(parseInt(saved, 10)) : 150;
39
+ applySize(currentSize);
40
+ }
41
+ function deactivate() {
42
+ currentSize = 100;
43
+ applySize(100);
44
+ localStorage.removeItem(STORAGE_KEY);
45
+ }
46
+ return {
47
+ id: "text-size",
48
+ name: () => "Text Size",
49
+ description: "Adjust text size from 100% to 200%",
50
+ icon: "text-size",
51
+ category: "visual",
52
+ activate,
53
+ deactivate,
54
+ getState: () => ({
55
+ id: "text-size",
56
+ enabled: currentSize !== 100,
57
+ value: currentSize
58
+ }),
59
+ setState: (size) => {
60
+ currentSize = clamp(size);
61
+ applySize(currentSize);
62
+ localStorage.setItem(STORAGE_KEY, String(currentSize));
63
+ }
64
+ };
65
+ }
66
+ export {
67
+ createTextSizeModule as default
68
+ };
69
+ //# sourceMappingURL=text-size-B-uv436p.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-size-B-uv436p.js","sources":["../src/features/text-size.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\nexport default function createTextSizeModule(): FeatureModule {\n let currentSize = 100;\n let originalFontSize = '';\n const STYLE_ID = 'accessify-text-size';\n const STORAGE_KEY = 'accessify-text-size';\n const MIN_SIZE = 100;\n const MAX_SIZE = 200;\n const STEP = 10;\n\n function applySize(percent: number) {\n let styleEl = document.getElementById(STYLE_ID);\n if (percent === 100) {\n styleEl?.remove();\n if (originalFontSize) {\n document.documentElement.style.fontSize = originalFontSize;\n } else {\n document.documentElement.style.removeProperty('font-size');\n }\n return;\n }\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n const scale = percent / 100;\n document.documentElement.style.fontSize = `${scale * 100}%`;\n styleEl.textContent = `\n /* accessify text-size: ${percent}% */\n body { font-size: 1rem !important; }\n `;\n }\n\n function clamp(value: number): number {\n return Math.min(MAX_SIZE, Math.max(MIN_SIZE, Math.round(value / STEP) * STEP));\n }\n\n function activate() {\n originalFontSize = document.documentElement.style.fontSize || '';\n const saved = localStorage.getItem(STORAGE_KEY);\n currentSize = saved ? clamp(parseInt(saved, 10)) : 150;\n applySize(currentSize);\n }\n\n function deactivate() {\n currentSize = 100;\n applySize(100);\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'text-size',\n name: () => 'Text Size',\n description: 'Adjust text size from 100% to 200%',\n icon: 'text-size',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({\n id: 'text-size',\n enabled: currentSize !== 100,\n value: currentSize,\n }),\n setState: (size: number) => {\n currentSize = clamp(size);\n applySize(currentSize);\n localStorage.setItem(STORAGE_KEY, String(currentSize));\n },\n };\n}\n"],"names":[],"mappings":"AAEA,SAAwB,uBAAsC;AAC5D,MAAI,cAAc;AAClB,MAAI,mBAAmB;AACvB,QAAM,WAAW;AACjB,QAAM,cAAc;AACpB,QAAM,WAAW;AACjB,QAAM,WAAW;AACjB,QAAM,OAAO;AAEb,WAAS,UAAU,SAAiB;AAClC,QAAI,UAAU,SAAS,eAAe,QAAQ;AAC9C,QAAI,YAAY,KAAK;AACnB,eAAS,OAAA;AACT,UAAI,kBAAkB;AACpB,iBAAS,gBAAgB,MAAM,WAAW;AAAA,MAC5C,OAAO;AACL,iBAAS,gBAAgB,MAAM,eAAe,WAAW;AAAA,MAC3D;AACA;AAAA,IACF;AACA,QAAI,CAAC,SAAS;AACZ,gBAAU,SAAS,cAAc,OAAO;AACxC,cAAQ,KAAK;AACb,eAAS,KAAK,YAAY,OAAO;AAAA,IACnC;AACA,UAAM,QAAQ,UAAU;AACxB,aAAS,gBAAgB,MAAM,WAAW,GAAG,QAAQ,GAAG;AACxD,YAAQ,cAAc;AAAA,gCACM,OAAO;AAAA;AAAA;AAAA,EAGrC;AAEA,WAAS,MAAM,OAAuB;AACpC,WAAO,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,KAAK,MAAM,QAAQ,IAAI,IAAI,IAAI,CAAC;AAAA,EAC/E;AAEA,WAAS,WAAW;AAClB,uBAAmB,SAAS,gBAAgB,MAAM,YAAY;AAC9D,UAAM,QAAQ,aAAa,QAAQ,WAAW;AAC9C,kBAAc,QAAQ,MAAM,SAAS,OAAO,EAAE,CAAC,IAAI;AACnD,cAAU,WAAW;AAAA,EACvB;AAEA,WAAS,aAAa;AACpB,kBAAc;AACd,cAAU,GAAG;AACb,iBAAa,WAAW,WAAW;AAAA,EACrC;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM,MAAM;AAAA,IACZ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,UAAU,OAAqB;AAAA,MAC7B,IAAI;AAAA,MACJ,SAAS,gBAAgB;AAAA,MACzB,OAAO;AAAA,IAAA;AAAA,IAET,UAAU,CAAC,SAAiB;AAC1B,oBAAc,MAAM,IAAI;AACxB,gBAAU,WAAW;AACrB,mBAAa,QAAQ,aAAa,OAAO,WAAW,CAAC;AAAA,IACvD;AAAA,EAAA;AAEJ;"}