-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApp.tsx
More file actions
158 lines (139 loc) · 5.52 KB
/
App.tsx
File metadata and controls
158 lines (139 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import { useState, useEffect, useCallback } from 'react';
import { ClockDisplay } from './components/ClockDisplay';
import { SettingsPanel } from './components/SettingsPanel';
import { BackgroundTheme, ClockConfig, ClockSize, AVAILABLE_FONTS } from './types';
// Default configuration
const DEFAULT_CONFIG: ClockConfig = {
color: '#22c55e', // Default green
size: ClockSize.MEDIUM,
gmtOffset: -new Date().getTimezoneOffset() / 60, // Default to local system time
background: BackgroundTheme.BLACK,
fontFamily: AVAILABLE_FONTS[0].value, // Will pick Roboto Mono
};
export default function App() {
const [config, setConfig] = useState<ClockConfig>(DEFAULT_CONFIG);
const [isViewMode, setIsViewMode] = useState(false);
const [isFullscreenMode, setIsFullscreenMode] = useState(false);
// Handle configuration updates
const updateConfig = (newConfig: Partial<ClockConfig>) => {
setConfig((prev) => ({ ...prev, ...newConfig }));
};
// Function to actually trigger browser fullscreen
const enterFullscreen = useCallback(async () => {
const elem = document.documentElement;
if (elem.requestFullscreen) {
try {
await elem.requestFullscreen();
} catch (err) {
console.error("Error attempting to enable fullscreen:", err);
}
}
}, []);
// Function to exit browser fullscreen
const exitFullscreen = useCallback(async () => {
if (document.fullscreenElement && document.exitFullscreen) {
try {
await document.exitFullscreen();
} catch (err) {
console.error("Error attempting to exit fullscreen:", err);
}
}
}, []);
// Handler for requesting view mode (clicking sizes)
const handleViewModeRequest = (size: ClockSize) => {
setIsViewMode(true);
if (size === ClockSize.FULLSCREEN) {
enterFullscreen();
} else {
// For Small/Medium, we just enter view mode, but ensure we aren't in native fullscreen
if (isFullscreenMode) {
exitFullscreen();
}
}
};
// Listener for browser native fullscreen changes
useEffect(() => {
const handleFullscreenChange = () => {
const isNowFullscreen = !!document.fullscreenElement;
setIsFullscreenMode(isNowFullscreen);
if (!isNowFullscreen && config.size === ClockSize.FULLSCREEN) {
// If we exited native fullscreen and were in Fullscreen size mode,
// we should exit view mode to show settings again.
setIsViewMode(false);
}
};
document.addEventListener('fullscreenchange', handleFullscreenChange);
return () => {
document.removeEventListener('fullscreenchange', handleFullscreenChange);
};
}, [config.size]);
// Listener for Escape key to exit View Mode (for non-native fullscreen states)
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
if (isViewMode) {
setIsViewMode(false);
// Also try to exit native fullscreen if active
if (document.fullscreenElement) {
exitFullscreen();
}
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isViewMode, exitFullscreen]);
// Helper to get background class
const getBackgroundClass = (theme: BackgroundTheme) => {
switch (theme) {
case BackgroundTheme.WHITE:
return 'bg-gray-100';
case BackgroundTheme.NEBULA:
return 'bg-gradient-to-br from-indigo-900 via-purple-900 to-black bg-[length:400%_400%] animate-[gradient_15s_ease_infinite]';
case BackgroundTheme.BLACK:
default:
return 'bg-black';
}
};
return (
<div className={`min-h-screen w-full transition-colors duration-500 relative ${!isViewMode ? 'bg-black p-6 flex flex-col items-center justify-center' : ''}`}>
{/* Settings Mode (Split View) */}
{!isViewMode && (
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-24 w-full max-w-6xl justify-center animate-fade-in z-10">
<div className="order-2 lg:order-1 w-full max-w-md">
<SettingsPanel
config={config}
onConfigChange={updateConfig}
onViewModeRequest={handleViewModeRequest}
/>
</div>
{/* Preview Panel - Always shows a smaller preview that fits the container */}
<div className="order-1 lg:order-2 flex justify-center w-full lg:w-1/2">
<div className={`rounded-3xl border-2 border-white/10 shadow-2xl p-8 flex items-center justify-center aspect-video w-full max-w-lg ${getBackgroundClass(config.background)}`}>
<ClockDisplay
color={config.color}
size={ClockSize.SMALL} // Force small size logic or use autoWidth
gmtOffset={config.gmtOffset}
background={config.background}
fontFamily={config.fontFamily}
autoWidth={true} // Use auto width to fit the preview container
/>
</div>
</div>
</div>
)}
{/* View Mode (Immersive View) */}
{isViewMode && (
<div className={`fixed inset-0 z-50 flex items-center justify-center ${getBackgroundClass(config.background)}`}>
<ClockDisplay
color={config.color}
size={config.size}
gmtOffset={config.gmtOffset}
background={config.background}
fontFamily={config.fontFamily}
/>
</div>
)}
</div>
);
}