@dashadmin/dash-utils 1.3.73 → 1.3.74-srcfree.2
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/dist/components/LazyAppLoader.d.ts +17 -0
- package/dist/components/MinimalLayout.d.ts +6 -0
- package/dist/components/RouterComponent.d.ts +22 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/contexts/IPCMessageBrokerContext.d.ts +42 -0
- package/dist/hooks/useCapacitorAppStateRefresh.d.ts +2 -0
- package/dist/hooks/useCapacitorKeyboard.d.ts +19 -0
- package/dist/hooks/useDeviceStorageSync.d.ts +4 -0
- package/dist/hooks/useDraggable.d.ts +24 -0
- package/dist/hooks/useMenuStateInit.d.ts +10 -0
- package/dist/hooks/useMobileDetection.d.ts +20 -0
- package/dist/hooks/useNotifications.d.ts +51 -0
- package/dist/hooks/useQuickSearch.d.ts +6 -0
- package/dist/hooks/useWindowSize.d.ts +6 -0
- package/dist/index.d.ts +30 -0
- package/dist/utils/authProviderUtils.d.ts +37 -0
- package/dist/utils/dashBootstrapApp.d.ts +9 -0
- package/dist/utils/dashDtorage.d.ts +8 -0
- package/dist/utils/dashIPCService.d.ts +93 -0
- package/dist/utils/dataProviderUtils.d.ts +44 -0
- package/dist/utils/electronStoreSync.d.ts +3 -0
- package/dist/utils/envUtils.d.ts +1 -0
- package/dist/utils/environmentBodyClasses.d.ts +11 -0
- package/dist/utils/isDev.d.ts +5 -0
- package/dist/utils/notificationPermission.d.ts +5 -0
- package/dist/utils/platformDetection.d.ts +13 -0
- package/dist/utils/priceFormatter.d.ts +2 -0
- package/dist/utils/resourceLoader.d.ts +8 -0
- package/dist/utils/speechService.d.ts +7 -0
- package/dist/utils/storedTheme.d.ts +11 -0
- package/dist/utils/updateDomCssVariables.d.ts +6 -0
- package/dist/utils/validation.d.ts +12 -0
- package/package.json +13 -10
- package/src/components/LazyAppLoader.tsx +0 -143
- package/src/components/MinimalLayout.tsx +0 -22
- package/src/components/RouterComponent.tsx +0 -169
- package/src/components/index.ts +0 -16
- package/src/contexts/IPCMessageBrokerContext.tsx +0 -303
- package/src/hooks/useCapacitorAppStateRefresh.ts +0 -34
- package/src/hooks/useCapacitorKeyboard.ts +0 -213
- package/src/hooks/useDeviceStorageSync.ts +0 -70
- package/src/hooks/useDraggable.ts +0 -133
- package/src/hooks/useMenuStateInit.ts +0 -85
- package/src/hooks/useMobileDetection.ts +0 -165
- package/src/hooks/useNotifications.ts +0 -220
- package/src/hooks/useQuickSearch.ts +0 -42
- package/src/hooks/useWindowSize.tsx +0 -36
- package/src/index.ts +0 -202
- package/src/utils/authProviderUtils.ts +0 -170
- package/src/utils/dashBootstrapApp.ts +0 -104
- package/src/utils/dashDtorage.tsx +0 -51
- package/src/utils/dashDtorage.tsx.old +0 -78
- package/src/utils/dashIPCService.ts +0 -204
- package/src/utils/dataProviderUtils.ts +0 -221
- package/src/utils/electronStoreSync.ts +0 -34
- package/src/utils/envUtils.tsx +0 -27
- package/src/utils/environmentBodyClasses.ts +0 -72
- package/src/utils/isDev.ts +0 -65
- package/src/utils/notificationPermission.ts +0 -57
- package/src/utils/platformDetection.ts +0 -98
- package/src/utils/priceFormatter.ts +0 -36
- package/src/utils/resourceLoader.ts +0 -107
- package/src/utils/speechService.ts +0 -112
- package/src/utils/storedTheme.ts +0 -60
- package/src/utils/updateDomCssVariables.tsx +0 -181
- package/src/utils/validation.ts +0 -147
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface KeyboardState {
|
|
4
|
-
isKeyboardOpen: boolean;
|
|
5
|
-
keyboardHeight: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface UseCapacitorKeyboardOptions {
|
|
9
|
-
/** Disable accessory bar for cleaner UI */
|
|
10
|
-
disableAccessoryBar?: boolean;
|
|
11
|
-
/** Resize mode: 'body', 'ionic', 'native', 'none' */
|
|
12
|
-
resizeMode?: 'body' | 'ionic' | 'native' | 'none';
|
|
13
|
-
/** Enable debug logging */
|
|
14
|
-
debug?: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Check if Capacitor Keyboard plugin is available
|
|
19
|
-
*/
|
|
20
|
-
export const isCapacitorKeyboardAvailable = (): boolean => {
|
|
21
|
-
const hasCapacitor = !!(window as any)?.Capacitor?.Plugins?.Keyboard;
|
|
22
|
-
const hasCapacitorKeyboard = !!(window as any)?.CapacitorKeyboard;
|
|
23
|
-
return hasCapacitor || hasCapacitorKeyboard;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get Capacitor Keyboard instance from window
|
|
28
|
-
*/
|
|
29
|
-
export const getCapacitorKeyboard = () => {
|
|
30
|
-
return (window as any)?.Capacitor?.Plugins?.Keyboard || (window as any)?.CapacitorKeyboard;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Hook for Capacitor keyboard detection and management
|
|
35
|
-
* Handles both Capacitor native keyboard and fallback viewport-based detection
|
|
36
|
-
*
|
|
37
|
-
* @param options - Configuration options
|
|
38
|
-
* @returns Keyboard state and utility functions
|
|
39
|
-
*/
|
|
40
|
-
export const useCapacitorKeyboard = (options: UseCapacitorKeyboardOptions = {}) => {
|
|
41
|
-
const {
|
|
42
|
-
disableAccessoryBar = true,
|
|
43
|
-
resizeMode = 'body',
|
|
44
|
-
debug = false
|
|
45
|
-
} = options;
|
|
46
|
-
|
|
47
|
-
const [keyboardState, setKeyboardState] = useState<KeyboardState>({
|
|
48
|
-
isKeyboardOpen: false,
|
|
49
|
-
keyboardHeight: 0,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const log = useCallback((message: string, data?: any) => {
|
|
53
|
-
if (debug) {
|
|
54
|
-
console.log(`[useCapacitorKeyboard] ${message}`, data || '');
|
|
55
|
-
}
|
|
56
|
-
}, [debug]);
|
|
57
|
-
|
|
58
|
-
// Hide keyboard programmatically
|
|
59
|
-
const hideKeyboard = useCallback(async () => {
|
|
60
|
-
if (isCapacitorKeyboardAvailable()) {
|
|
61
|
-
const Keyboard = getCapacitorKeyboard();
|
|
62
|
-
if (Keyboard?.hide) {
|
|
63
|
-
try {
|
|
64
|
-
log('Hiding keyboard...');
|
|
65
|
-
await Keyboard.hide();
|
|
66
|
-
} catch (error) {
|
|
67
|
-
log('Error hiding keyboard:', error);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}, [log]);
|
|
72
|
-
|
|
73
|
-
// Show keyboard programmatically
|
|
74
|
-
const showKeyboard = useCallback(async () => {
|
|
75
|
-
if (isCapacitorKeyboardAvailable()) {
|
|
76
|
-
const Keyboard = getCapacitorKeyboard();
|
|
77
|
-
if (Keyboard?.show) {
|
|
78
|
-
try {
|
|
79
|
-
log('Showing keyboard...');
|
|
80
|
-
await Keyboard.show();
|
|
81
|
-
} catch (error) {
|
|
82
|
-
log('Error showing keyboard:', error);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}, [log]);
|
|
87
|
-
|
|
88
|
-
// Configure Capacitor Keyboard
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
const configureKeyboard = async () => {
|
|
91
|
-
if (isCapacitorKeyboardAvailable()) {
|
|
92
|
-
const Keyboard = getCapacitorKeyboard();
|
|
93
|
-
if (Keyboard) {
|
|
94
|
-
try {
|
|
95
|
-
log('Configuring Capacitor Keyboard...');
|
|
96
|
-
|
|
97
|
-
if (Keyboard.setAccessoryBarVisible) {
|
|
98
|
-
await Keyboard.setAccessoryBarVisible({ isVisible: !disableAccessoryBar });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (Keyboard.setResizeMode) {
|
|
102
|
-
await Keyboard.setResizeMode({ mode: resizeMode });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
log('Capacitor Keyboard configured successfully');
|
|
106
|
-
} catch (error) {
|
|
107
|
-
log('Error configuring Capacitor Keyboard:', error);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
configureKeyboard();
|
|
114
|
-
}, [disableAccessoryBar, resizeMode, log]);
|
|
115
|
-
|
|
116
|
-
// Setup keyboard listeners
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
if (isCapacitorKeyboardAvailable()) {
|
|
119
|
-
const Keyboard = getCapacitorKeyboard();
|
|
120
|
-
|
|
121
|
-
if (Keyboard) {
|
|
122
|
-
log('Using Capacitor Keyboard API');
|
|
123
|
-
|
|
124
|
-
const handleKeyboardWillShow = (info: any) => {
|
|
125
|
-
log('Keyboard will show', { height: info.keyboardHeight });
|
|
126
|
-
setKeyboardState({
|
|
127
|
-
isKeyboardOpen: true,
|
|
128
|
-
keyboardHeight: info.keyboardHeight,
|
|
129
|
-
});
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const handleKeyboardDidShow = (info: any) => {
|
|
133
|
-
setKeyboardState({
|
|
134
|
-
isKeyboardOpen: true,
|
|
135
|
-
keyboardHeight: info.keyboardHeight,
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const handleKeyboardWillHide = () => {
|
|
140
|
-
log('Keyboard will hide');
|
|
141
|
-
setKeyboardState({
|
|
142
|
-
isKeyboardOpen: false,
|
|
143
|
-
keyboardHeight: 0,
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const handleKeyboardDidHide = () => {
|
|
148
|
-
setKeyboardState({
|
|
149
|
-
isKeyboardOpen: false,
|
|
150
|
-
keyboardHeight: 0,
|
|
151
|
-
});
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
Keyboard.addListener('keyboardWillShow', handleKeyboardWillShow);
|
|
155
|
-
Keyboard.addListener('keyboardDidShow', handleKeyboardDidShow);
|
|
156
|
-
Keyboard.addListener('keyboardWillHide', handleKeyboardWillHide);
|
|
157
|
-
Keyboard.addListener('keyboardDidHide', handleKeyboardDidHide);
|
|
158
|
-
|
|
159
|
-
return () => {
|
|
160
|
-
Keyboard.removeAllListeners?.();
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Fallback: viewport-based detection for web
|
|
166
|
-
log('Using fallback viewport-based keyboard detection');
|
|
167
|
-
|
|
168
|
-
let previousViewportHeight = window.visualViewport?.height || window.innerHeight;
|
|
169
|
-
|
|
170
|
-
const handleResize = () => {
|
|
171
|
-
const viewportHeight = window.visualViewport?.height || window.innerHeight;
|
|
172
|
-
const screenHeight = window.screen.height;
|
|
173
|
-
|
|
174
|
-
// If viewport is significantly smaller than screen, keyboard is likely open
|
|
175
|
-
const keyboardThreshold = screenHeight * 0.75;
|
|
176
|
-
const keyboardOpen = viewportHeight < keyboardThreshold;
|
|
177
|
-
|
|
178
|
-
if (keyboardOpen !== keyboardState.isKeyboardOpen) {
|
|
179
|
-
const estimatedKeyboardHeight = keyboardOpen ? screenHeight - viewportHeight : 0;
|
|
180
|
-
log(keyboardOpen ? 'Keyboard opened (fallback)' : 'Keyboard closed (fallback)', {
|
|
181
|
-
height: estimatedKeyboardHeight
|
|
182
|
-
});
|
|
183
|
-
setKeyboardState({
|
|
184
|
-
isKeyboardOpen: keyboardOpen,
|
|
185
|
-
keyboardHeight: estimatedKeyboardHeight,
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
previousViewportHeight = viewportHeight;
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
window.addEventListener('resize', handleResize);
|
|
193
|
-
if (window.visualViewport) {
|
|
194
|
-
window.visualViewport.addEventListener('resize', handleResize);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return () => {
|
|
198
|
-
window.removeEventListener('resize', handleResize);
|
|
199
|
-
if (window.visualViewport) {
|
|
200
|
-
window.visualViewport.removeEventListener('resize', handleResize);
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}, [log, keyboardState.isKeyboardOpen]);
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
...keyboardState,
|
|
207
|
-
hideKeyboard,
|
|
208
|
-
showKeyboard,
|
|
209
|
-
isCapacitorAvailable: isCapacitorKeyboardAvailable(),
|
|
210
|
-
};
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
export default useCapacitorKeyboard;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Hook to sync device storage (Electron store) with localStorage
|
|
5
|
-
* Useful for Electron apps to maintain state persistence
|
|
6
|
-
*/
|
|
7
|
-
export const useDeviceStorageSync = () => {
|
|
8
|
-
useEffect(() => {
|
|
9
|
-
const syncDeviceStoreToLocalStorage = async () => {
|
|
10
|
-
const electronStore = (window as any).electronStore;
|
|
11
|
-
if (electronStore && electronStore.getAll) {
|
|
12
|
-
// Sync logic can be implemented here if needed
|
|
13
|
-
// Currently placeholder for future implementation
|
|
14
|
-
console.log('[useDeviceStorageSync] Electron store detected');
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
syncDeviceStoreToLocalStorage();
|
|
18
|
-
}, []);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Sync all data from Electron store to localStorage
|
|
23
|
-
* Call this on app initialization
|
|
24
|
-
*/
|
|
25
|
-
export const syncDeviceStoreToLocalStorage = async (): Promise<void> => {
|
|
26
|
-
const electronStore = (window as any).electronStore;
|
|
27
|
-
if (electronStore && electronStore.getAll) {
|
|
28
|
-
try {
|
|
29
|
-
const allData = await electronStore.getAll();
|
|
30
|
-
if (allData && typeof allData === 'object') {
|
|
31
|
-
for (const [key, value] of Object.entries(allData)) {
|
|
32
|
-
window.localStorage.setItem(key, JSON.stringify(value));
|
|
33
|
-
}
|
|
34
|
-
console.log('[syncDeviceStoreToLocalStorage] Synced electron-store to localStorage');
|
|
35
|
-
}
|
|
36
|
-
} catch (err) {
|
|
37
|
-
console.error('[syncDeviceStoreToLocalStorage] Failed to sync:', err);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Sync all data from localStorage to Electron store
|
|
44
|
-
* Call this after auth changes or important state updates
|
|
45
|
-
*/
|
|
46
|
-
export const syncLocalStorageToDeviceStore = async (): Promise<void> => {
|
|
47
|
-
const electronStore = (window as any).electronStore;
|
|
48
|
-
if (electronStore && electronStore.set) {
|
|
49
|
-
try {
|
|
50
|
-
for (let i = 0; i < window.localStorage.length; i++) {
|
|
51
|
-
const key = window.localStorage.key(i);
|
|
52
|
-
if (key) {
|
|
53
|
-
const value = window.localStorage.getItem(key);
|
|
54
|
-
if (value !== null) {
|
|
55
|
-
try {
|
|
56
|
-
await electronStore.set(key, JSON.parse(value));
|
|
57
|
-
} catch {
|
|
58
|
-
await electronStore.set(key, value);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
console.log('[syncLocalStorageToDeviceStore] Synced localStorage to electron-store');
|
|
64
|
-
} catch (err) {
|
|
65
|
-
console.error('[syncLocalStorageToDeviceStore] Failed to sync:', err);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export default useDeviceStorageSync;
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface DraggablePosition {
|
|
4
|
-
x: number;
|
|
5
|
-
y: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface UseDraggableOptions {
|
|
9
|
-
/** Initial position */
|
|
10
|
-
initialPosition?: DraggablePosition;
|
|
11
|
-
/** Minimum X position (default: 0) */
|
|
12
|
-
minX?: number;
|
|
13
|
-
/** Minimum Y position (default: 0) */
|
|
14
|
-
minY?: number;
|
|
15
|
-
/** Maximum X position (default: window.innerWidth - elementWidth) */
|
|
16
|
-
maxX?: number;
|
|
17
|
-
/** Maximum Y position (default: window.innerHeight - elementHeight) */
|
|
18
|
-
maxY?: number;
|
|
19
|
-
/** Element width for boundary calculation */
|
|
20
|
-
elementWidth?: number;
|
|
21
|
-
/** Element height for boundary calculation */
|
|
22
|
-
elementHeight?: number;
|
|
23
|
-
/** Callback when position changes */
|
|
24
|
-
onPositionChange?: (position: DraggablePosition) => void;
|
|
25
|
-
/** Callback when drag starts */
|
|
26
|
-
onDragStart?: () => void;
|
|
27
|
-
/** Callback when drag ends */
|
|
28
|
-
onDragEnd?: () => void;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface UseDraggableReturn {
|
|
32
|
-
position: DraggablePosition;
|
|
33
|
-
isDragging: boolean;
|
|
34
|
-
handleMouseDown: (e: React.MouseEvent) => void;
|
|
35
|
-
setPosition: (position: DraggablePosition) => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Hook for making elements draggable
|
|
40
|
-
* Handles mouse events and position calculations
|
|
41
|
-
*/
|
|
42
|
-
export const useDraggable = (options: UseDraggableOptions = {}): UseDraggableReturn => {
|
|
43
|
-
const {
|
|
44
|
-
initialPosition = { x: 0, y: 0 },
|
|
45
|
-
minX = 0,
|
|
46
|
-
minY = 0,
|
|
47
|
-
maxX,
|
|
48
|
-
maxY,
|
|
49
|
-
elementWidth = 400,
|
|
50
|
-
elementHeight = 200,
|
|
51
|
-
onPositionChange,
|
|
52
|
-
onDragStart,
|
|
53
|
-
onDragEnd,
|
|
54
|
-
} = options;
|
|
55
|
-
|
|
56
|
-
const [position, setPosition] = useState<DraggablePosition>(initialPosition);
|
|
57
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
58
|
-
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
|
59
|
-
|
|
60
|
-
// Calculate boundaries
|
|
61
|
-
const getMaxX = useCallback(() => {
|
|
62
|
-
if (maxX !== undefined) return maxX;
|
|
63
|
-
return typeof window !== 'undefined' ? window.innerWidth - elementWidth : 1000;
|
|
64
|
-
}, [maxX, elementWidth]);
|
|
65
|
-
|
|
66
|
-
const getMaxY = useCallback(() => {
|
|
67
|
-
if (maxY !== undefined) return maxY;
|
|
68
|
-
return typeof window !== 'undefined' ? window.innerHeight - elementHeight : 800;
|
|
69
|
-
}, [maxY, elementHeight]);
|
|
70
|
-
|
|
71
|
-
// Handle mouse down - start dragging
|
|
72
|
-
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
73
|
-
// Only start drag if clicking on an element with .drag-handle class
|
|
74
|
-
if ((e.target as HTMLElement).closest('.drag-handle')) {
|
|
75
|
-
e.preventDefault();
|
|
76
|
-
setIsDragging(true);
|
|
77
|
-
setDragOffset({
|
|
78
|
-
x: e.clientX - position.x,
|
|
79
|
-
y: e.clientY - position.y,
|
|
80
|
-
});
|
|
81
|
-
onDragStart?.();
|
|
82
|
-
}
|
|
83
|
-
}, [position, onDragStart]);
|
|
84
|
-
|
|
85
|
-
// Handle mouse move
|
|
86
|
-
const handleMouseMove = useCallback((e: MouseEvent) => {
|
|
87
|
-
if (isDragging) {
|
|
88
|
-
e.preventDefault();
|
|
89
|
-
const newX = Math.max(minX, Math.min(getMaxX(), e.clientX - dragOffset.x));
|
|
90
|
-
const newY = Math.max(minY, Math.min(getMaxY(), e.clientY - dragOffset.y));
|
|
91
|
-
const newPosition = { x: newX, y: newY };
|
|
92
|
-
setPosition(newPosition);
|
|
93
|
-
onPositionChange?.(newPosition);
|
|
94
|
-
}
|
|
95
|
-
}, [isDragging, dragOffset, minX, minY, getMaxX, getMaxY, onPositionChange]);
|
|
96
|
-
|
|
97
|
-
// Handle mouse up - stop dragging
|
|
98
|
-
const handleMouseUp = useCallback(() => {
|
|
99
|
-
if (isDragging) {
|
|
100
|
-
setIsDragging(false);
|
|
101
|
-
onDragEnd?.();
|
|
102
|
-
}
|
|
103
|
-
}, [isDragging, onDragEnd]);
|
|
104
|
-
|
|
105
|
-
// Add/remove event listeners
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
if (isDragging) {
|
|
108
|
-
document.addEventListener('mousemove', handleMouseMove);
|
|
109
|
-
document.addEventListener('mouseup', handleMouseUp);
|
|
110
|
-
document.body.style.userSelect = 'none';
|
|
111
|
-
|
|
112
|
-
return () => {
|
|
113
|
-
document.removeEventListener('mousemove', handleMouseMove);
|
|
114
|
-
document.removeEventListener('mouseup', handleMouseUp);
|
|
115
|
-
document.body.style.userSelect = '';
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}, [isDragging, handleMouseMove, handleMouseUp]);
|
|
119
|
-
|
|
120
|
-
// Update position when initialPosition changes
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
setPosition(initialPosition);
|
|
123
|
-
}, [initialPosition.x, initialPosition.y]);
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
position,
|
|
127
|
-
isDragging,
|
|
128
|
-
handleMouseDown,
|
|
129
|
-
setPosition,
|
|
130
|
-
};
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
export default useDraggable;
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Menu State Initialization Hook
|
|
3
|
-
*
|
|
4
|
-
* Hook to initialize menu/navigation state from localStorage
|
|
5
|
-
* and sync it with Redux store.
|
|
6
|
-
*/
|
|
7
|
-
import { useEffect } from 'react';
|
|
8
|
-
import { useDispatch } from 'react-redux';
|
|
9
|
-
import { dashStorage } from '../utils/dashDtorage';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Options for the useMenuStateInit hook
|
|
13
|
-
*/
|
|
14
|
-
export interface UseMenuStateInitOptions {
|
|
15
|
-
/** Storage key for nav expanded state */
|
|
16
|
-
navExpandedKey?: string;
|
|
17
|
-
/** Storage key for nav size */
|
|
18
|
-
navSizeKey?: string;
|
|
19
|
-
/** Redux action creator for setting nav expanded */
|
|
20
|
-
setNavExpandedAction?: (isExpanded: boolean) => any;
|
|
21
|
-
/** Redux action creator for setting nav size */
|
|
22
|
-
setNavSizeAction?: (size: string) => any;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Default options
|
|
27
|
-
*/
|
|
28
|
-
const defaultOptions: UseMenuStateInitOptions = {
|
|
29
|
-
navExpandedKey: 'dashNavExpanded',
|
|
30
|
-
navSizeKey: 'dashNavSize',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Hook to initialize menu state from localStorage
|
|
35
|
-
* Reads persisted navigation state and dispatches Redux actions
|
|
36
|
-
*/
|
|
37
|
-
export const useMenuStateInit = (options: UseMenuStateInitOptions = {}) => {
|
|
38
|
-
const dispatch = useDispatch();
|
|
39
|
-
const {
|
|
40
|
-
navExpandedKey = defaultOptions.navExpandedKey!,
|
|
41
|
-
setNavExpandedAction
|
|
42
|
-
} = options;
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
if (!setNavExpandedAction) return;
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const savedNavState = dashStorage.getItem(navExpandedKey);
|
|
49
|
-
if (savedNavState !== null) {
|
|
50
|
-
const isExpanded = savedNavState === 'true';
|
|
51
|
-
dispatch(setNavExpandedAction(isExpanded));
|
|
52
|
-
}
|
|
53
|
-
} catch (e) {
|
|
54
|
-
console.error('Error accessing localStorage:', e);
|
|
55
|
-
}
|
|
56
|
-
}, [dispatch, navExpandedKey, setNavExpandedAction]);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Initialize menu state without Redux (returns state)
|
|
61
|
-
* Useful for initial state setup
|
|
62
|
-
*/
|
|
63
|
-
export const getInitialMenuState = (navExpandedKey: string = 'dashNavExpanded') => {
|
|
64
|
-
try {
|
|
65
|
-
const savedNavState = dashStorage.getItem(navExpandedKey);
|
|
66
|
-
return savedNavState !== null ? savedNavState === 'true' : true;
|
|
67
|
-
} catch (e) {
|
|
68
|
-
console.error('Error accessing localStorage:', e);
|
|
69
|
-
return true;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get initial nav size from localStorage
|
|
75
|
-
*/
|
|
76
|
-
export const getInitialNavSize = (navSizeKey: string = 'dashNavSize') => {
|
|
77
|
-
try {
|
|
78
|
-
return dashStorage.getItem(navSizeKey) || 'small';
|
|
79
|
-
} catch (e) {
|
|
80
|
-
console.error('Error accessing localStorage:', e);
|
|
81
|
-
return 'small';
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export default useMenuStateInit;
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useCallback } from 'react';
|
|
2
|
-
|
|
3
|
-
export interface MobileDetectionState {
|
|
4
|
-
isMobile: boolean;
|
|
5
|
-
isAndroid: boolean;
|
|
6
|
-
isIOS: boolean;
|
|
7
|
-
isWebView: boolean;
|
|
8
|
-
screenWidth: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface UseMobileDetectionOptions {
|
|
12
|
-
/** Screen width threshold to consider as mobile (default: 700) */
|
|
13
|
-
mobileBreakpoint?: number;
|
|
14
|
-
/** Enable debug logging */
|
|
15
|
-
debug?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Check if the current environment is a mobile device
|
|
20
|
-
* Based on body classes and screen width
|
|
21
|
-
*/
|
|
22
|
-
export const checkMobileDevice = (mobileBreakpoint: number = 700): boolean => {
|
|
23
|
-
// Check body classes for mobile devices
|
|
24
|
-
const bodyClasses = document.body.className;
|
|
25
|
-
const hasMobileClass = bodyClasses.includes('webview') ||
|
|
26
|
-
bodyClasses.includes('android') ||
|
|
27
|
-
bodyClasses.includes('ios') ||
|
|
28
|
-
bodyClasses.includes('mobile');
|
|
29
|
-
|
|
30
|
-
// Check screen width
|
|
31
|
-
const screenWidth = window.innerWidth;
|
|
32
|
-
const isSmallScreen = screenWidth < mobileBreakpoint;
|
|
33
|
-
|
|
34
|
-
// Consider mobile if either condition is true
|
|
35
|
-
return hasMobileClass || isSmallScreen;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Check if running in a WebView
|
|
40
|
-
*/
|
|
41
|
-
export const isWebView = (): boolean => {
|
|
42
|
-
const userAgent = navigator.userAgent.toLowerCase();
|
|
43
|
-
return (/(webview|wv)/.test(userAgent) ||
|
|
44
|
-
/android.*(wv|.net)/.test(userAgent) || /iphone|ipod|ipad.*applewebkit(?!.*safari)/i.test(userAgent));
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Check if running on Android
|
|
49
|
-
*/
|
|
50
|
-
export const isAndroid = (): boolean => {
|
|
51
|
-
return /android/i.test(navigator.userAgent.toLowerCase());
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Check if running on iOS
|
|
56
|
-
*/
|
|
57
|
-
export const isIOS = (): boolean => {
|
|
58
|
-
return /iphone|ipad|ipod/i.test(navigator.userAgent.toLowerCase());
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Check if running on Windows
|
|
63
|
-
*/
|
|
64
|
-
export const isWindows = (): boolean => {
|
|
65
|
-
try {
|
|
66
|
-
// Check Node.js process (for Electron)
|
|
67
|
-
const nodeProcess = (globalThis as any).process;
|
|
68
|
-
if (nodeProcess?.platform === 'win32') return true;
|
|
69
|
-
|
|
70
|
-
return navigator.userAgent.toLowerCase().includes('windows');
|
|
71
|
-
} catch (error) {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Check if running on macOS
|
|
78
|
-
*/
|
|
79
|
-
export const isMacOS = (): boolean => {
|
|
80
|
-
try {
|
|
81
|
-
// Check Node.js process (for Electron)
|
|
82
|
-
const nodeProcess = (globalThis as any).process;
|
|
83
|
-
if (nodeProcess?.platform === 'darwin') return true;
|
|
84
|
-
|
|
85
|
-
return /macintosh|mac os x/i.test(navigator.userAgent.toLowerCase());
|
|
86
|
-
} catch (error) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Check if running on Linux
|
|
93
|
-
*/
|
|
94
|
-
export const isLinux = (): boolean => {
|
|
95
|
-
try {
|
|
96
|
-
// Check Node.js process (for Electron)
|
|
97
|
-
const nodeProcess = (globalThis as any).process;
|
|
98
|
-
if (nodeProcess?.platform === 'linux') return true;
|
|
99
|
-
|
|
100
|
-
return /linux/i.test(navigator.userAgent.toLowerCase());
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Hook for detecting mobile devices and platform information
|
|
108
|
-
*
|
|
109
|
-
* @param options - Configuration options
|
|
110
|
-
* @returns Mobile detection state
|
|
111
|
-
*/
|
|
112
|
-
export const useMobileDetection = (options: UseMobileDetectionOptions = {}) => {
|
|
113
|
-
const { mobileBreakpoint = 700, debug = false } = options;
|
|
114
|
-
|
|
115
|
-
const [state, setState] = useState<MobileDetectionState>(() => ({
|
|
116
|
-
isMobile: checkMobileDevice(mobileBreakpoint),
|
|
117
|
-
isAndroid: isAndroid(),
|
|
118
|
-
isIOS: isIOS(),
|
|
119
|
-
isWebView: isWebView(),
|
|
120
|
-
screenWidth: window.innerWidth,
|
|
121
|
-
}));
|
|
122
|
-
|
|
123
|
-
const log = useCallback((message: string, data?: any) => {
|
|
124
|
-
if (debug) {
|
|
125
|
-
console.log(`[useMobileDetection] ${message}`, data || '');
|
|
126
|
-
}
|
|
127
|
-
}, [debug]);
|
|
128
|
-
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
const handleResize = () => {
|
|
131
|
-
const newState: MobileDetectionState = {
|
|
132
|
-
isMobile: checkMobileDevice(mobileBreakpoint),
|
|
133
|
-
isAndroid: isAndroid(),
|
|
134
|
-
isIOS: isIOS(),
|
|
135
|
-
isWebView: isWebView(),
|
|
136
|
-
screenWidth: window.innerWidth,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// Only update if something changed
|
|
140
|
-
if (newState.isMobile !== state.isMobile || newState.screenWidth !== state.screenWidth) {
|
|
141
|
-
log('Mobile detection state changed', newState);
|
|
142
|
-
setState(newState);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
window.addEventListener('resize', handleResize);
|
|
147
|
-
|
|
148
|
-
// Also listen to orientation changes
|
|
149
|
-
window.addEventListener('orientationchange', handleResize);
|
|
150
|
-
|
|
151
|
-
return () => {
|
|
152
|
-
window.removeEventListener('resize', handleResize);
|
|
153
|
-
window.removeEventListener('orientationchange', handleResize);
|
|
154
|
-
};
|
|
155
|
-
}, [mobileBreakpoint, state.isMobile, state.screenWidth, log]);
|
|
156
|
-
|
|
157
|
-
// Initial detection logging
|
|
158
|
-
useEffect(() => {
|
|
159
|
-
log('Initial mobile detection', state);
|
|
160
|
-
}, []);
|
|
161
|
-
|
|
162
|
-
return state;
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
export default useMobileDetection;
|