@codesinger0/shared-components 1.1.15 → 1.1.17

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.
@@ -1,258 +1,188 @@
1
- // src/components/AccessibilityMenu.jsx
2
1
  import React, { useState, useEffect } from 'react';
3
- import {
4
- Accessibility, ZoomIn, ZoomOut, Contrast, Sun, Moon, Link, Heading,
5
- MousePointer2, X, CircleOff, Glasses, Palette, Square
6
- } from 'lucide-react';
7
2
  import { motion, AnimatePresence } from 'framer-motion';
3
+ import {
4
+ Accessibility,
5
+ ZoomIn,
6
+ ZoomOut,
7
+ Sun,
8
+ Moon,
9
+ Type,
10
+ Eye,
11
+ X
12
+ } from 'lucide-react';
8
13
 
9
- export default function AccessibilityMenu() {
14
+ const AccessibilityMenu = ({
15
+ position = 'bottom-left', // 'bottom-left' or 'bottom-right'
16
+ bottomOffset = '1.5rem',
17
+ sideOffset = '1.5rem',
18
+ size = 'large', // 'small', 'medium', 'large'
19
+ className = '',
20
+ onSettingChange = null, // callback when settings change
21
+ ...props
22
+ }) => {
10
23
  const [isOpen, setIsOpen] = useState(false);
11
- const [activeOptions, setActiveOptions] = useState({});
12
- const [fontSize, setFontSize] = useState(1);
24
+ const [settings, setSettings] = useState({
25
+ fontSize: 100,
26
+ contrast: 'normal',
27
+ darkMode: false,
28
+ underlineLinks: false,
29
+ largerCursor: false
30
+ });
13
31
 
14
- const applyOption = (option, apply) => {
15
- document.documentElement.classList.toggle(`accessibility-${option}`, apply);
16
- };
17
-
18
- const resetAll = () => {
19
- Object.keys(activeOptions).forEach(option => {
20
- if(activeOptions[option]){
21
- applyOption(option, false);
22
- }
23
- });
24
- setActiveOptions({});
25
- setFontSize(1);
26
- document.documentElement.style.setProperty('--font-size-multiplier', 1);
32
+ // Size configurations
33
+ const sizeClasses = {
34
+ small: 'w-12 h-12',
35
+ medium: 'w-14 h-14',
36
+ large: 'w-16 h-16'
27
37
  };
28
38
 
29
- const toggleOption = (option, exclusiveGroup = null) => {
30
- const newActiveOptions = { ...activeOptions };
31
- const currentState = newActiveOptions[option];
39
+ const iconSizes = {
40
+ small: 20,
41
+ medium: 24,
42
+ large: 28
43
+ };
32
44
 
33
- if (exclusiveGroup) {
34
- Object.keys(newActiveOptions).forEach(opt => {
35
- if (opt.startsWith(exclusiveGroup) && opt !== option) {
36
- newActiveOptions[opt] = false;
37
- applyOption(opt, false);
38
- }
39
- });
45
+ // Position styles for button
46
+ const positionStyles = {
47
+ 'bottom-left': {
48
+ bottom: bottomOffset,
49
+ left: sideOffset,
50
+ right: 'auto'
51
+ },
52
+ 'bottom-right': {
53
+ bottom: bottomOffset,
54
+ right: sideOffset,
55
+ left: 'auto'
40
56
  }
57
+ };
41
58
 
42
- newActiveOptions[option] = !currentState;
43
- setActiveOptions(newActiveOptions);
44
- applyOption(option, newActiveOptions[option]);
59
+ // Menu position styles
60
+ const menuPositionStyles = {
61
+ 'bottom-left': {
62
+ bottom: `calc(${bottomOffset} + ${sizeClasses[size] === 'w-12 h-12' ? '4rem' : sizeClasses[size] === 'w-14 h-14' ? '4.5rem' : '5rem'})`,
63
+ left: sideOffset,
64
+ right: 'auto'
65
+ },
66
+ 'bottom-right': {
67
+ bottom: `calc(${bottomOffset} + ${sizeClasses[size] === 'w-12 h-12' ? '4rem' : sizeClasses[size] === 'w-14 h-14' ? '4.5rem' : '5rem'})`,
68
+ right: sideOffset,
69
+ left: 'auto'
70
+ }
45
71
  };
46
-
47
- const changeFontSize = (amount) => {
48
- const newSize = Math.max(0.8, Math.min(1.5, fontSize + amount));
49
- setFontSize(newSize);
50
- document.documentElement.style.setProperty('--font-size-multiplier', newSize);
72
+
73
+ useEffect(() => {
74
+ // Apply font size
75
+ document.documentElement.style.fontSize = `${settings.fontSize}%`;
76
+
77
+ // Apply contrast
78
+ if (settings.contrast === 'high') {
79
+ document.documentElement.style.filter = 'contrast(1.5)';
80
+ } else {
81
+ document.documentElement.style.filter = 'none';
82
+ }
83
+
84
+ // Apply dark mode
85
+ if (settings.darkMode) {
86
+ document.documentElement.classList.add('dark-mode-accessibility');
87
+ } else {
88
+ document.documentElement.classList.remove('dark-mode-accessibility');
89
+ }
90
+
91
+ // Apply link underline
92
+ if (settings.underlineLinks) {
93
+ document.documentElement.classList.add('underline-links');
94
+ } else {
95
+ document.documentElement.classList.remove('underline-links');
96
+ }
97
+
98
+ // Apply larger cursor
99
+ if (settings.largerCursor) {
100
+ document.documentElement.classList.add('large-cursor');
101
+ } else {
102
+ document.documentElement.classList.remove('large-cursor');
103
+ }
104
+
105
+ // Callback
106
+ if (onSettingChange) {
107
+ onSettingChange(settings);
108
+ }
109
+ }, [settings, onSettingChange]);
110
+
111
+ const increaseFontSize = () => {
112
+ setSettings(prev => ({
113
+ ...prev,
114
+ fontSize: Math.min(prev.fontSize + 10, 150)
115
+ }));
51
116
  };
52
117
 
53
- const tools = [
54
- { id: 'increase-font', label: 'הגדלת גופן', icon: ZoomIn, action: () => changeFontSize(0.1) },
55
- { id: 'decrease-font', label: 'הקטנת גופן', icon: ZoomOut, action: () => changeFontSize(-0.1) },
56
- { id: 'readable-font', label: 'גופן קריא', icon: Glasses, action: () => toggleOption('readable-font') },
57
- { id: 'highlight-links', label: 'הדגשת קישורים', icon: Link, action: () => toggleOption('highlight-links') },
58
- { id: 'highlight-headers', label: 'הדגשת כותרות', icon: Heading, action: () => toggleOption('highlight-headers') },
59
- { id: 'contrast-high', label: 'ניגודיות גבוהה', icon: Contrast, action: () => toggleOption('contrast-high', 'contrast-') },
60
- { id: 'contrast-dark', label: 'רקע כהה', icon: Moon, action: () => toggleOption('contrast-dark', 'contrast-') },
61
- { id: 'contrast-light', label: 'רקע בהיר', icon: Sun, action: () => toggleOption('contrast-light', 'contrast-') },
62
- { id: 'invert-colors', label: 'היפוך צבעים', icon: Palette, action: () => toggleOption('invert-colors', 'contrast-') },
63
- { id: 'monochrome', label: 'מונוכרום', icon: CircleOff, action: () => toggleOption('monochrome', 'contrast-') },
64
- { id: 'big-cursor', label: 'סמן גדול', icon: MousePointer2, action: () => toggleOption('big-cursor') },
65
- { id: 'disable-animations', label: 'ביטול אנימציות', icon: Square, action: () => toggleOption('disable-animations') },
66
- ];
118
+ const decreaseFontSize = () => {
119
+ setSettings(prev => ({
120
+ ...prev,
121
+ fontSize: Math.max(prev.fontSize - 10, 80)
122
+ }));
123
+ };
67
124
 
68
- useEffect(() => {
69
- const handleEsc = (event) => {
70
- if (event.key === 'Escape' && isOpen) {
71
- setIsOpen(false);
72
- }
73
- };
74
- window.addEventListener('keydown', handleEsc);
75
- return () => window.removeEventListener('keydown', handleEsc);
76
- }, [isOpen]);
125
+ const resetSettings = () => {
126
+ setSettings({
127
+ fontSize: 100,
128
+ contrast: 'normal',
129
+ darkMode: false,
130
+ underlineLinks: false,
131
+ largerCursor: false
132
+ });
133
+ };
77
134
 
78
- return (
79
- <>
80
- <style>{`
81
- :root { --font-size-multiplier: 1; }
82
-
83
- /* Readable Font */
84
- html.accessibility-readable-font body {
85
- font-family: Arial, sans-serif !important;
86
- }
87
-
88
- /* Highlight Links */
89
- html.accessibility-highlight-links a {
90
- background-color: yellow !important;
91
- color: black !important;
92
- padding: 2px 4px;
93
- border: 1px solid black;
94
- }
95
-
96
- /* Highlight Headers */
97
- html.accessibility-highlight-headers h1,
98
- html.accessibility-highlight-headers h2,
99
- html.accessibility-highlight-headers h3,
100
- html.accessibility-highlight-headers h4 {
101
- background-color: #add8e6 !important;
102
- padding: 4px;
103
- }
104
-
105
- /* High Contrast Mode */
106
- html.accessibility-contrast-high {
107
- filter: contrast(200%) !important;
108
- }
109
- html.accessibility-contrast-high body {
110
- background-color: white !important;
111
- color: black !important;
112
- }
113
- html.accessibility-contrast-high h1,
114
- html.accessibility-contrast-high h2,
115
- html.accessibility-contrast-high h3,
116
- html.accessibility-contrast-high h4,
117
- html.accessibility-contrast-high p,
118
- html.accessibility-contrast-high span,
119
- html.accessibility-contrast-high div {
120
- color: black !important;
121
- }
122
- html.accessibility-contrast-high a {
123
- color: blue !important;
124
- text-decoration: underline !important;
125
- }
126
- html.accessibility-contrast-high button {
127
- background-color: black !important;
128
- color: white !important;
129
- border: 2px solid black !important;
130
- }
131
- html.accessibility-contrast-high input,
132
- html.accessibility-contrast-high textarea {
133
- background-color: white !important;
134
- color: black !important;
135
- border: 2px solid black !important;
136
- }
137
- html.accessibility-contrast-high [class*="bg-green"],
138
- html.accessibility-contrast-high [class*="bg-sky"],
139
- html.accessibility-contrast-high [class*="bg-blue"],
140
- html.accessibility-contrast-high [class*="bg-gradient"] {
141
- background-color: white !important;
142
- color: black !important;
143
- }
144
-
145
- /* Dark Background */
146
- html.accessibility-contrast-dark body {
147
- background-color: #1a1a1a !important;
148
- color: #ffffff !important;
149
- }
150
- html.accessibility-contrast-dark div,
151
- html.accessibility-contrast-dark section,
152
- html.accessibility-contrast-dark p,
153
- html.accessibility-contrast-dark h1,
154
- html.accessibility-contrast-dark h2,
155
- html.accessibility-contrast-dark h3,
156
- html.accessibility-contrast-dark h4,
157
- html.accessibility-contrast-dark span {
158
- color: #ffffff !important;
159
- }
160
- html.accessibility-contrast-dark [class*="bg-white"],
161
- html.accessibility-contrast-dark [class*="bg-gray"],
162
- html.accessibility-contrast-dark [class*="bg-green"],
163
- html.accessibility-contrast-dark [class*="bg-sky"],
164
- html.accessibility-contrast-dark [class*="bg-main"],
165
- html.accessibility-contrast-dark [class*="glass-card"] {
166
- background-color: #2a2a2a !important;
167
- }
168
- html.accessibility-contrast-dark a {
169
- color: #87cefa !important;
170
- }
171
- html.accessibility-contrast-dark button {
172
- background-color: #333 !important;
173
- color: #fff !important;
174
- border: 1px solid #666 !important;
175
- }
176
-
177
- /* Light Background */
178
- html.accessibility-contrast-light body {
179
- background-color: #ffffff !important;
180
- color: #000000 !important;
181
- }
182
- html.accessibility-contrast-light div,
183
- html.accessibility-contrast-light section,
184
- html.accessibility-contrast-light p,
185
- html.accessibility-contrast-light h1,
186
- html.accessibility-contrast-light h2,
187
- html.accessibility-contrast-light h3,
188
- html.accessibility-contrast-light h4,
189
- html.accessibility-contrast-light span {
190
- color: #000000 !important;
191
- }
192
- html.accessibility-contrast-light [class*="bg-"] {
193
- background-color: #f8f8f8 !important;
194
- }
135
+ const toggleContrast = () => {
136
+ setSettings(prev => ({
137
+ ...prev,
138
+ contrast: prev.contrast === 'normal' ? 'high' : 'normal'
139
+ }));
140
+ };
195
141
 
196
- /* Invert Colors */
197
- html.accessibility-invert-colors {
198
- filter: invert(1) !important;
199
- }
200
- html.accessibility-invert-colors img,
201
- html.accessibility-invert-colors video {
202
- filter: invert(1) !important;
203
- }
142
+ const toggleDarkMode = () => {
143
+ setSettings(prev => ({
144
+ ...prev,
145
+ darkMode: !prev.darkMode
146
+ }));
147
+ };
204
148
 
205
- /* Monochrome */
206
- html.accessibility-monochrome {
207
- filter: grayscale(100%) !important;
208
- }
149
+ const toggleUnderlineLinks = () => {
150
+ setSettings(prev => ({
151
+ ...prev,
152
+ underlineLinks: !prev.underlineLinks
153
+ }));
154
+ };
209
155
 
210
- /* Big Cursor */
211
- html.accessibility-big-cursor * {
212
- cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewport='0 0 48 48' style='fill:black;font-size:24px;'><path d='M 10,2 L 10,42 L 18,34 L 25,42 L 30,40 L 22,32 L 32,32 L 10,2 Z'/></svg>") 16 0, auto !important;
213
- }
156
+ const toggleLargerCursor = () => {
157
+ setSettings(prev => ({
158
+ ...prev,
159
+ largerCursor: !prev.largerCursor
160
+ }));
161
+ };
214
162
 
215
- /* Disable Animations */
216
- html.accessibility-disable-animations * {
217
- animation: none !important;
218
- transition: none !important;
219
- }
220
-
221
- /* Font Size Scaling */
222
- body {
223
- font-size: calc(1rem * var(--font-size-multiplier));
224
- }
225
- h1 {
226
- font-size: calc(2.25rem * var(--font-size-multiplier));
227
- }
228
- h2 {
229
- font-size: calc(1.75rem * var(--font-size-multiplier));
230
- }
231
- h3 {
232
- font-size: calc(1.5rem * var(--font-size-multiplier));
233
- }
234
- h4 {
235
- font-size: calc(1.25rem * var(--font-size-multiplier));
236
- }
237
- p, li, span, a, button, div {
238
- font-size: calc(1em * var(--font-size-multiplier));
239
- }
240
- `}</style>
241
-
242
- {/* Floating Accessibility Button */}
243
- <div className="fixed bottom-4 left-4 z-[100]">
244
- <motion.button
245
- onClick={() => setIsOpen(!isOpen)}
246
- className="bg-sky-600 text-white rounded-full p-4 shadow-lg hover:bg-sky-700 transition-colors focus:outline-none focus:ring-2 focus:ring-sky-400"
247
- whileHover={{ scale: 1.1 }}
248
- whileTap={{ scale: 0.9 }}
249
- aria-label="פתח תפריט נגישות"
250
- >
251
- <Accessibility className="w-6 h-6" />
252
- </motion.button>
253
- </div>
163
+ return (
164
+ <>
165
+ {/* Main Button */}
166
+ <motion.button
167
+ onClick={() => setIsOpen(!isOpen)}
168
+ className={`fixed z-50 bg-blue-600 hover:bg-blue-700 text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center ${sizeClasses[size]} ${className}`}
169
+ style={positionStyles[position]}
170
+ initial={{ scale: 0, opacity: 0 }}
171
+ animate={{ scale: 1, opacity: 1 }}
172
+ whileHover={{ scale: 1.1 }}
173
+ whileTap={{ scale: 0.9 }}
174
+ transition={{
175
+ type: "spring",
176
+ stiffness: 300,
177
+ damping: 25
178
+ }}
179
+ aria-label="תפריט נגישות"
180
+ {...props}
181
+ >
182
+ <Accessibility size={iconSizes[size]} />
183
+ </motion.button>
254
184
 
255
- {/* Accessibility Menu Panel */}
185
+ {/* Menu Panel */}
256
186
  <AnimatePresence>
257
187
  {isOpen && (
258
188
  <>
@@ -261,71 +191,284 @@ export default function AccessibilityMenu() {
261
191
  initial={{ opacity: 0 }}
262
192
  animate={{ opacity: 1 }}
263
193
  exit={{ opacity: 0 }}
264
- className="fixed inset-0 bg-black bg-opacity-30 z-[98]"
194
+ className="fixed inset-0 bg-black bg-opacity-20 z-40"
265
195
  onClick={() => setIsOpen(false)}
266
196
  />
267
197
 
268
- {/* Menu Panel */}
198
+ {/* Menu */}
269
199
  <motion.div
270
- initial={{ opacity: 0, y: 50 }}
271
- animate={{ opacity: 1, y: 0 }}
272
- exit={{ opacity: 0, y: 50 }}
273
- className="fixed bottom-20 left-4 z-[99] w-[90vw] max-w-lg"
200
+ initial={{ opacity: 0, scale: 0.8, y: 20 }}
201
+ animate={{ opacity: 1, scale: 1, y: 0 }}
202
+ exit={{ opacity: 0, scale: 0.8, y: 20 }}
203
+ transition={{
204
+ type: "spring",
205
+ stiffness: 300,
206
+ damping: 25
207
+ }}
208
+ className="fixed z-50 bg-white rounded-lg shadow-2xl p-6 w-80"
209
+ style={menuPositionStyles[position]}
274
210
  dir="rtl"
275
211
  >
276
- <div className="bg-white rounded-xl shadow-2xl border-2 border-sky-200 p-4">
277
- {/* Header */}
278
- <div className="flex justify-between items-center mb-4">
279
- <h3 className="font-bold text-lg text-sky-800">תפריט נגישות</h3>
212
+ {/* Header */}
213
+ <div className="flex justify-between items-center mb-4 pb-3 border-b">
214
+ <h3 className="text-lg font-bold text-gray-800">נגישות</h3>
215
+ <button
216
+ onClick={() => setIsOpen(false)}
217
+ className="text-gray-500 hover:text-gray-700 p-1 rounded-full hover:bg-gray-100"
218
+ aria-label="סגור"
219
+ >
220
+ <X size={20} />
221
+ </button>
222
+ </div>
223
+
224
+ {/* Settings */}
225
+ <div className="space-y-4">
226
+ {/* Font Size */}
227
+ <div className="flex items-center justify-between">
228
+ <span className="text-sm font-medium text-gray-700 flex items-center gap-2">
229
+ <Type size={18} />
230
+ גודל טקסט
231
+ </span>
280
232
  <div className="flex gap-2">
281
233
  <button
282
- onClick={resetAll}
283
- className="px-3 py-1 text-sm text-sky-700 hover:bg-sky-50 rounded-md transition-colors"
234
+ onClick={decreaseFontSize}
235
+ className="p-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
236
+ aria-label="הקטן טקסט"
237
+ disabled={settings.fontSize <= 80}
284
238
  >
285
- איפוס
239
+ <ZoomOut size={16} />
286
240
  </button>
241
+ <span className="px-3 py-2 bg-gray-50 rounded-lg text-sm font-medium min-w-[3rem] text-center">
242
+ {settings.fontSize}%
243
+ </span>
287
244
  <button
288
- onClick={() => setIsOpen(false)}
289
- className="p-1 hover:bg-gray-100 rounded-md transition-colors"
290
- aria-label="סגור תפריט נגישות"
245
+ onClick={increaseFontSize}
246
+ className="p-2 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
247
+ aria-label="הגדל טקסט"
248
+ disabled={settings.fontSize >= 150}
291
249
  >
292
- <X className="w-5 h-5" />
250
+ <ZoomIn size={16} />
293
251
  </button>
294
252
  </div>
295
253
  </div>
296
254
 
297
- {/* Font Size Display */}
298
- <div className="mb-4 text-center text-sm text-gray-600">
299
- גודל גופן: {Math.round(fontSize * 100)}%
300
- </div>
255
+ {/* Contrast */}
256
+ <button
257
+ onClick={toggleContrast}
258
+ className={`w-full flex items-center justify-between p-3 rounded-lg transition-colors ${
259
+ settings.contrast === 'high'
260
+ ? 'bg-blue-50 border-2 border-blue-500'
261
+ : 'bg-gray-50 hover:bg-gray-100'
262
+ }`}
263
+ >
264
+ <span className="text-sm font-medium text-gray-700 flex items-center gap-2">
265
+ <Eye size={18} />
266
+ ניגודיות גבוהה
267
+ </span>
268
+ <div className={`w-10 h-6 rounded-full transition-colors ${
269
+ settings.contrast === 'high' ? 'bg-blue-500' : 'bg-gray-300'
270
+ } relative`}>
271
+ <div className={`absolute w-4 h-4 bg-white rounded-full top-1 transition-all ${
272
+ settings.contrast === 'high' ? 'right-1' : 'right-5'
273
+ }`} />
274
+ </div>
275
+ </button>
301
276
 
302
- {/* Tools Grid */}
303
- <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
304
- {tools.map(tool => (
305
- <button
306
- key={tool.id}
307
- onClick={tool.action}
308
- className={`flex flex-col items-center justify-center h-20 text-center gap-1 rounded-lg border-2 transition-all ${
309
- activeOptions[tool.id]
310
- ? 'bg-sky-100 border-sky-500 text-sky-800'
311
- : 'bg-white border-gray-300 hover:border-sky-300 hover:bg-sky-50'
312
- }`}
313
- >
314
- <tool.icon className="w-6 h-6 mb-1" />
315
- <span className="text-xs px-1">{tool.label}</span>
316
- </button>
317
- ))}
318
- </div>
277
+ {/* Dark Mode */}
278
+ <button
279
+ onClick={toggleDarkMode}
280
+ className={`w-full flex items-center justify-between p-3 rounded-lg transition-colors ${
281
+ settings.darkMode
282
+ ? 'bg-blue-50 border-2 border-blue-500'
283
+ : 'bg-gray-50 hover:bg-gray-100'
284
+ }`}
285
+ >
286
+ <span className="text-sm font-medium text-gray-700 flex items-center gap-2">
287
+ {settings.darkMode ? <Moon size={18} /> : <Sun size={18} />}
288
+ מצב כהה
289
+ </span>
290
+ <div className={`w-10 h-6 rounded-full transition-colors ${
291
+ settings.darkMode ? 'bg-blue-500' : 'bg-gray-300'
292
+ } relative`}>
293
+ <div className={`absolute w-4 h-4 bg-white rounded-full top-1 transition-all ${
294
+ settings.darkMode ? 'right-1' : 'right-5'
295
+ }`} />
296
+ </div>
297
+ </button>
319
298
 
320
- {/* Footer Info */}
321
- <div className="mt-4 pt-3 border-t border-gray-200 text-center text-xs text-gray-500">
322
- לחץ ESC לסגירת התפריט
323
- </div>
299
+ {/* Underline Links */}
300
+ <button
301
+ onClick={toggleUnderlineLinks}
302
+ className={`w-full flex items-center justify-between p-3 rounded-lg transition-colors ${
303
+ settings.underlineLinks
304
+ ? 'bg-blue-50 border-2 border-blue-500'
305
+ : 'bg-gray-50 hover:bg-gray-100'
306
+ }`}
307
+ >
308
+ <span className="text-sm font-medium text-gray-700">
309
+ הדגש קישורים
310
+ </span>
311
+ <div className={`w-10 h-6 rounded-full transition-colors ${
312
+ settings.underlineLinks ? 'bg-blue-500' : 'bg-gray-300'
313
+ } relative`}>
314
+ <div className={`absolute w-4 h-4 bg-white rounded-full top-1 transition-all ${
315
+ settings.underlineLinks ? 'right-1' : 'right-5'
316
+ }`} />
317
+ </div>
318
+ </button>
319
+
320
+ {/* Larger Cursor */}
321
+ <button
322
+ onClick={toggleLargerCursor}
323
+ className={`w-full flex items-center justify-between p-3 rounded-lg transition-colors ${
324
+ settings.largerCursor
325
+ ? 'bg-blue-50 border-2 border-blue-500'
326
+ : 'bg-gray-50 hover:bg-gray-100'
327
+ }`}
328
+ >
329
+ <span className="text-sm font-medium text-gray-700">
330
+ סמן גדול
331
+ </span>
332
+ <div className={`w-10 h-6 rounded-full transition-colors ${
333
+ settings.largerCursor ? 'bg-blue-500' : 'bg-gray-300'
334
+ } relative`}>
335
+ <div className={`absolute w-4 h-4 bg-white rounded-full top-1 transition-all ${
336
+ settings.largerCursor ? 'right-1' : 'right-5'
337
+ }`} />
338
+ </div>
339
+ </button>
340
+
341
+ {/* Reset Button */}
342
+ <button
343
+ onClick={resetSettings}
344
+ className="w-full mt-4 p-3 bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium rounded-lg transition-colors"
345
+ >
346
+ איפוס הגדרות
347
+ </button>
324
348
  </div>
325
349
  </motion.div>
326
350
  </>
327
351
  )}
328
352
  </AnimatePresence>
353
+
354
+ {/* Global Styles */}
355
+ <style jsx global>{`
356
+ .dark-mode-accessibility {
357
+ filter: invert(1) hue-rotate(180deg);
358
+ }
359
+
360
+ .dark-mode-accessibility img,
361
+ .dark-mode-accessibility video,
362
+ .dark-mode-accessibility [style*="background-image"] {
363
+ filter: invert(1) hue-rotate(180deg);
364
+ }
365
+
366
+ .underline-links a {
367
+ text-decoration: underline !important;
368
+ }
369
+
370
+ .large-cursor,
371
+ .large-cursor * {
372
+ cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M8 4 L8 24 L14 18 L18 28 L22 26 L18 16 L26 16 Z" fill="black" stroke="white" stroke-width="1"/></svg>') 0 0, auto !important;
373
+ }
374
+
375
+ .large-cursor button,
376
+ .large-cursor a {
377
+ cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M16 4 L12 12 L4 12 L4 16 L12 16 L16 24 L20 24 L20 16 L28 16 L28 12 L20 12 L20 4 Z" fill="black" stroke="white" stroke-width="1"/></svg>') 16 16, pointer !important;
378
+ }
379
+ `}</style>
329
380
  </>
330
381
  );
331
- }
382
+ };
383
+
384
+ // Demo
385
+ const Demo = () => {
386
+ const handleSettingChange = (settings) => {
387
+ console.log('Settings changed:', settings);
388
+ };
389
+
390
+ return (
391
+ <div className="min-h-screen bg-gradient-to-br from-purple-50 to-blue-100 p-8" dir="rtl">
392
+ <div className="max-w-4xl mx-auto">
393
+ <h1 className="text-4xl font-bold text-gray-800 mb-6 text-center">
394
+ Accessibility Menu Demo
395
+ </h1>
396
+
397
+ <div className="bg-white rounded-xl shadow-lg p-8 mb-8">
398
+ <h2 className="text-2xl font-semibold mb-4">תכונות:</h2>
399
+ <ul className="space-y-2 text-gray-700">
400
+ <li>✅ מיקום גמיש (שמאל/ימין למטה)</li>
401
+ <li>✅ שליטה מלאה על המרחקים מהקצוות</li>
402
+ <li>✅ 3 גדלים: small, medium, large</li>
403
+ <li>✅ שינוי גודל טקסט (80% - 150%)</li>
404
+ <li>✅ ניגודיות גבוהה</li>
405
+ <li>✅ מצב כהה</li>
406
+ <li>✅ הדגשת קישורים</li>
407
+ <li>✅ סמן עכבר גדול</li>
408
+ <li>✅ Callback לשינויי הגדרות</li>
409
+ </ul>
410
+ </div>
411
+
412
+ <div className="bg-white rounded-xl shadow-lg p-8 mb-8">
413
+ <h2 className="text-2xl font-semibold mb-4">דוגמאות שימוש:</h2>
414
+
415
+ <div className="space-y-4 text-sm bg-gray-50 p-4 rounded-lg font-mono text-left" dir="ltr">
416
+ <div className="bg-white p-3 rounded border">
417
+ <div className="text-gray-500 mb-2">// Bottom Left (default)</div>
418
+ <code className="text-blue-600">
419
+ {`<AccessibilityMenu
420
+ position="bottom-left"
421
+ bottomOffset="1.5rem"
422
+ sideOffset="1.5rem"
423
+ />`}
424
+ </code>
425
+ </div>
426
+
427
+ <div className="bg-white p-3 rounded border">
428
+ <div className="text-gray-500 mb-2">// Bottom Right with callback</div>
429
+ <code className="text-blue-600">
430
+ {`<AccessibilityMenu
431
+ position="bottom-right"
432
+ size="medium"
433
+ onSettingChange={(settings) => {
434
+ console.log('Settings:', settings);
435
+ }}
436
+ />`}
437
+ </code>
438
+ </div>
439
+ </div>
440
+ </div>
441
+
442
+ <div className="bg-white rounded-xl shadow-lg p-8">
443
+ <h2 className="text-2xl font-semibold mb-4">טקסט לדוגמה</h2>
444
+ <p className="mb-4">
445
+ זהו טקסט לדוגמה שיושפע מהגדרות הנגישות. נסה לשנות את גודל הטקסט, הניגודיות והמצב הכהה כדי לראות את ההשפעה.
446
+ </p>
447
+ <a href="#" className="text-blue-600 hover:underline">זהו קישור לדוגמה</a>
448
+ <div className="mt-4 h-96 flex items-center justify-center text-gray-400">
449
+ <p>גלול למטה כדי לראות את תפריט הנגישות 👇</p>
450
+ </div>
451
+ </div>
452
+ </div>
453
+
454
+ {/* Demo Menus */}
455
+ <AccessibilityMenu
456
+ position="bottom-left"
457
+ bottomOffset="1.5rem"
458
+ sideOffset="1.5rem"
459
+ size="large"
460
+ onSettingChange={handleSettingChange}
461
+ />
462
+
463
+ <AccessibilityMenu
464
+ position="bottom-right"
465
+ bottomOffset="1.5rem"
466
+ sideOffset="1.5rem"
467
+ size="medium"
468
+ onSettingChange={handleSettingChange}
469
+ />
470
+ </div>
471
+ );
472
+ };
473
+
474
+ export default AccessibilityMenu;
@@ -12,6 +12,7 @@ const Hero = ({
12
12
 
13
13
  // Overlay
14
14
  opacity = 70,
15
+ overlayColor = 'white',
15
16
 
16
17
  // Hero text props
17
18
  title,
@@ -60,7 +61,13 @@ const Hero = ({
60
61
  {/* Content Overlay */}
61
62
  <div
62
63
  className="relative z-10 flex items-center justify-center h-full"
63
- style={{ backgroundColor: `rgba(255, 255, 255, ${opacity / 100})` }}
64
+ style={{
65
+ backgroundColor: `rgba(${overlayColor === 'white' ? '255, 255, 255' :
66
+ overlayColor === 'black' ? '0, 0, 0' :
67
+ overlayColor // allow custom rgb values like "128, 128, 128"
68
+ }, ${opacity / 100})`
69
+ }}
70
+
64
71
  >
65
72
  <div className="text-center px-0">
66
73
  <motion.div
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codesinger0/shared-components",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Shared React components for customer projects",
5
5
  "main": "dist/index.js",
6
6
  "files": [