create-fluxstack 1.7.5 → 1.8.3
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/.dockerignore +82 -0
- package/.env.example +19 -0
- package/Dockerfile +70 -0
- package/README.md +6 -3
- package/app/client/SIMPLIFICATION.md +140 -0
- package/app/client/frontend-only.ts +1 -1
- package/app/client/src/App.tsx +148 -283
- package/app/client/src/index.css +5 -20
- package/app/client/src/lib/eden-api.ts +53 -220
- package/app/client/src/main.tsx +2 -3
- package/app/server/app.ts +20 -5
- package/app/server/backend-only.ts +15 -12
- package/app/server/controllers/users.controller.ts +57 -31
- package/app/server/index.ts +86 -96
- package/app/server/live/register-components.ts +18 -7
- package/app/server/routes/env-test.ts +110 -0
- package/app/server/routes/index.ts +1 -8
- package/app/server/routes/users.routes.ts +192 -91
- package/config/app.config.ts +2 -54
- package/config/client.config.ts +95 -0
- package/config/fluxstack.config.ts +2 -2
- package/config/index.ts +57 -22
- package/config/monitoring.config.ts +114 -0
- package/config/plugins.config.ts +80 -0
- package/config/runtime.config.ts +0 -17
- package/config/server.config.ts +50 -30
- package/core/build/bundler.ts +17 -16
- package/core/build/flux-plugins-generator.ts +34 -23
- package/core/build/index.ts +32 -31
- package/core/build/live-components-generator.ts +44 -30
- package/core/build/optimizer.ts +37 -17
- package/core/cli/command-registry.ts +4 -14
- package/core/cli/commands/plugin-deps.ts +8 -8
- package/core/cli/generators/component.ts +3 -3
- package/core/cli/generators/controller.ts +4 -4
- package/core/cli/generators/index.ts +8 -8
- package/core/cli/generators/interactive.ts +4 -4
- package/core/cli/generators/plugin.ts +3 -3
- package/core/cli/generators/prompts.ts +1 -1
- package/core/cli/generators/route.ts +27 -11
- package/core/cli/generators/service.ts +5 -5
- package/core/cli/generators/template-engine.ts +1 -1
- package/core/cli/generators/types.ts +1 -1
- package/core/cli/index.ts +158 -189
- package/core/cli/plugin-discovery.ts +3 -3
- package/core/client/hooks/index.ts +2 -2
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +1 -1
- package/core/client/hooks/useChunkedUpload.ts +1 -1
- package/core/client/hooks/useHybridLiveComponent.ts +1 -1
- package/core/client/hooks/useWebSocket.ts +1 -1
- package/core/config/env.ts +5 -1
- package/core/config/runtime-config.ts +12 -10
- package/core/config/schema.ts +33 -2
- package/core/framework/server.ts +30 -14
- package/core/framework/types.ts +2 -2
- package/core/index.ts +31 -23
- package/core/live/ComponentRegistry.ts +1 -1
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +65 -161
- package/core/plugins/built-in/static/index.ts +75 -277
- package/core/plugins/built-in/swagger/index.ts +301 -231
- package/core/plugins/built-in/vite/index.ts +342 -377
- package/core/plugins/config.ts +2 -2
- package/core/plugins/dependency-manager.ts +2 -2
- package/core/plugins/discovery.ts +1 -1
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/manager.ts +19 -4
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +25 -21
- package/core/plugins/types.ts +147 -5
- package/core/server/backend-entry.ts +51 -0
- package/core/server/framework.ts +2 -2
- package/core/server/live/ComponentRegistry.ts +9 -26
- package/core/server/live/FileUploadManager.ts +1 -1
- package/core/server/live/auto-generated-components.ts +26 -0
- package/core/server/live/websocket-plugin.ts +211 -19
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +4 -4
- package/core/server/plugins/database.ts +1 -2
- package/core/server/plugins/static-files-plugin.ts +259 -231
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +4 -4
- package/core/server/standalone.ts +16 -1
- package/core/testing/index.ts +1 -1
- package/core/testing/setup.ts +1 -1
- package/core/types/plugin.ts +6 -0
- package/core/utils/build-logger.ts +324 -0
- package/core/utils/config-schema.ts +2 -6
- package/core/utils/helpers.ts +14 -9
- package/core/utils/logger/startup-banner.ts +7 -33
- package/core/utils/regenerate-files.ts +69 -0
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +68 -25
- package/fluxstack.config.ts +138 -252
- package/package.json +3 -18
- package/plugins/crypto-auth/index.ts +52 -47
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
- package/vitest.config.ts +17 -26
- package/app/client/src/App.css +0 -883
- package/app/client/src/components/ErrorBoundary.tsx +0 -107
- package/app/client/src/components/ErrorDisplay.css +0 -365
- package/app/client/src/components/ErrorDisplay.tsx +0 -258
- package/app/client/src/components/FluxStackConfig.tsx +0 -1321
- package/app/client/src/components/HybridLiveCounter.tsx +0 -140
- package/app/client/src/components/LiveClock.tsx +0 -286
- package/app/client/src/components/MainLayout.tsx +0 -388
- package/app/client/src/components/SidebarNavigation.tsx +0 -391
- package/app/client/src/components/StateDemo.tsx +0 -178
- package/app/client/src/components/SystemMonitor.tsx +0 -1044
- package/app/client/src/components/UserProfile.tsx +0 -809
- package/app/client/src/hooks/useAuth.ts +0 -39
- package/app/client/src/hooks/useNotifications.ts +0 -56
- package/app/client/src/lib/errors.ts +0 -340
- package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
- package/app/client/src/lib/index.ts +0 -45
- package/app/client/src/pages/ApiDocs.tsx +0 -182
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/client/src/pages/Demo.tsx +0 -174
- package/app/client/src/pages/HybridLive.tsx +0 -263
- package/app/client/src/pages/Overview.tsx +0 -155
- package/app/client/src/store/README.md +0 -43
- package/app/client/src/store/index.ts +0 -16
- package/app/client/src/store/slices/uiSlice.ts +0 -151
- package/app/client/src/store/slices/userSlice.ts +0 -161
- package/app/client/src/test/README.md +0 -257
- package/app/client/src/test/setup.ts +0 -70
- package/app/client/src/test/types.ts +0 -12
- package/app/server/live/CounterComponent.ts +0 -191
- package/app/server/live/FluxStackConfig.ts +0 -534
- package/app/server/live/SidebarNavigation.ts +0 -157
- package/app/server/live/SystemMonitor.ts +0 -595
- package/app/server/live/SystemMonitorIntegration.ts +0 -151
- package/app/server/live/UserProfileComponent.ts +0 -141
- package/app/server/middleware/auth.ts +0 -136
- package/app/server/middleware/errorHandling.ts +0 -252
- package/app/server/middleware/index.ts +0 -10
- package/app/server/middleware/rateLimit.ts +0 -193
- package/app/server/middleware/requestLogging.ts +0 -215
- package/app/server/middleware/validation.ts +0 -270
- package/app/server/routes/config.ts +0 -145
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/app/server/routes/upload.ts +0 -92
- package/app/server/services/NotificationService.ts +0 -302
- package/app/server/services/UserService.ts +0 -222
- package/app/server/services/index.ts +0 -46
- package/app/server/types/index.ts +0 -1
- package/config/build.config.ts +0 -24
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
// 🔥 Simple Hybrid Live Counter - Server-Driven with Zustand
|
|
2
|
-
|
|
3
|
-
import { useHybridLiveComponent } from '@/core/client'
|
|
4
|
-
|
|
5
|
-
interface CounterState {
|
|
6
|
-
count: number
|
|
7
|
-
title: string
|
|
8
|
-
step: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface HybridLiveCounterProps {
|
|
12
|
-
initialCount?: number
|
|
13
|
-
title?: string
|
|
14
|
-
step?: number
|
|
15
|
-
room?: string
|
|
16
|
-
userId?: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function HybridLiveCounter({
|
|
20
|
-
initialCount = 0,
|
|
21
|
-
title = 'Simple Live Counter',
|
|
22
|
-
step = 1,
|
|
23
|
-
room,
|
|
24
|
-
userId
|
|
25
|
-
}: HybridLiveCounterProps = {}) {
|
|
26
|
-
// Frontend provides initial state - server takes control after mount
|
|
27
|
-
const initialState: CounterState = {
|
|
28
|
-
count: initialCount,
|
|
29
|
-
title,
|
|
30
|
-
step
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const {
|
|
34
|
-
state,
|
|
35
|
-
loading,
|
|
36
|
-
error,
|
|
37
|
-
connected,
|
|
38
|
-
call,
|
|
39
|
-
callAndWait
|
|
40
|
-
} = useHybridLiveComponent<CounterState>('Counter', initialState, {
|
|
41
|
-
debug: true,
|
|
42
|
-
autoMount: true,
|
|
43
|
-
room,
|
|
44
|
-
userId
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const handleIncrement = () => call('increment', state.step)
|
|
48
|
-
const handleDecrement = () => call('decrement', state.step)
|
|
49
|
-
const handleReset = () => call('reset')
|
|
50
|
-
|
|
51
|
-
const handleGetStats = async () => {
|
|
52
|
-
try {
|
|
53
|
-
const response = await callAndWait('getStats')
|
|
54
|
-
const stats = response.stats
|
|
55
|
-
alert(`📊 Current: ${stats.current} | Min: ${stats.min} | Max: ${stats.max} | Avg: ${stats.average.toFixed(1)}`)
|
|
56
|
-
} catch (err) {
|
|
57
|
-
alert(`❌ Error: ${err instanceof Error ? err.message : 'Failed to get stats'}`)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg border">
|
|
63
|
-
{/* Header */}
|
|
64
|
-
<div className="text-center mb-6">
|
|
65
|
-
<h1 className="text-2xl font-bold text-gray-800 mb-2">{state.title}</h1>
|
|
66
|
-
<div className="flex justify-center gap-2 text-sm">
|
|
67
|
-
<span className={`px-2 py-1 rounded text-xs ${
|
|
68
|
-
connected ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
|
|
69
|
-
}`}>
|
|
70
|
-
{connected ? '🟢 Connected' : '🔴 Disconnected'}
|
|
71
|
-
</span>
|
|
72
|
-
<span className="px-2 py-1 rounded text-xs bg-blue-100 text-blue-700">
|
|
73
|
-
🎯 Server-Driven
|
|
74
|
-
</span>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
{/* Error Display */}
|
|
79
|
-
{error && (
|
|
80
|
-
<div className="mb-4 p-3 bg-red-100 border border-red-300 text-red-700 rounded text-sm">
|
|
81
|
-
❌ {error}
|
|
82
|
-
</div>
|
|
83
|
-
)}
|
|
84
|
-
|
|
85
|
-
{/* Counter Display */}
|
|
86
|
-
<div className="text-center mb-6">
|
|
87
|
-
<div className="text-5xl font-bold text-blue-600 mb-2">
|
|
88
|
-
{state.count}
|
|
89
|
-
</div>
|
|
90
|
-
<div className="text-sm text-gray-500">
|
|
91
|
-
Step: {state.step}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
{/* Control Buttons */}
|
|
96
|
-
<div className="grid grid-cols-2 gap-3 mb-4">
|
|
97
|
-
<button
|
|
98
|
-
onClick={handleDecrement}
|
|
99
|
-
disabled={loading || !connected}
|
|
100
|
-
className="px-4 py-2 bg-red-500 hover:bg-red-600 disabled:bg-gray-300 text-white font-bold rounded transition-colors"
|
|
101
|
-
>
|
|
102
|
-
- {state.step}
|
|
103
|
-
</button>
|
|
104
|
-
<button
|
|
105
|
-
onClick={handleIncrement}
|
|
106
|
-
disabled={loading || !connected}
|
|
107
|
-
className="px-4 py-2 bg-green-500 hover:bg-green-600 disabled:bg-gray-300 text-white font-bold rounded transition-colors"
|
|
108
|
-
>
|
|
109
|
-
+ {state.step}
|
|
110
|
-
</button>
|
|
111
|
-
</div>
|
|
112
|
-
|
|
113
|
-
{/* Action Buttons */}
|
|
114
|
-
<div className="grid grid-cols-2 gap-3">
|
|
115
|
-
<button
|
|
116
|
-
onClick={handleReset}
|
|
117
|
-
disabled={loading || !connected}
|
|
118
|
-
className="px-3 py-2 bg-gray-500 hover:bg-gray-600 disabled:bg-gray-300 text-white text-sm rounded transition-colors"
|
|
119
|
-
>
|
|
120
|
-
🔄 Reset
|
|
121
|
-
</button>
|
|
122
|
-
<button
|
|
123
|
-
onClick={handleGetStats}
|
|
124
|
-
disabled={loading || !connected}
|
|
125
|
-
className="px-3 py-2 bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white text-sm rounded transition-colors"
|
|
126
|
-
>
|
|
127
|
-
📊 Stats
|
|
128
|
-
</button>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
{/* Loading Indicator */}
|
|
132
|
-
{loading && (
|
|
133
|
-
<div className="mt-4 text-center">
|
|
134
|
-
<div className="inline-block animate-spin rounded-full h-4 w-4 border-2 border-blue-600 border-t-transparent"></div>
|
|
135
|
-
<span className="ml-2 text-sm text-gray-600">Loading...</span>
|
|
136
|
-
</div>
|
|
137
|
-
)}
|
|
138
|
-
</div>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
// 🔥 LiveClock - Real-time Clock Client Component
|
|
2
|
-
import React, { useState } from 'react';
|
|
3
|
-
import { useHybridLiveComponent } from '@/core/client';
|
|
4
|
-
import {
|
|
5
|
-
FaClock,
|
|
6
|
-
FaCog,
|
|
7
|
-
FaSync,
|
|
8
|
-
FaServer,
|
|
9
|
-
FaCalendarAlt,
|
|
10
|
-
FaStopwatch,
|
|
11
|
-
FaGlobe,
|
|
12
|
-
FaEye,
|
|
13
|
-
FaEyeSlash
|
|
14
|
-
} from 'react-icons/fa';
|
|
15
|
-
|
|
16
|
-
interface LiveClockState {
|
|
17
|
-
currentTime: string;
|
|
18
|
-
timeZone: string;
|
|
19
|
-
format: '12h' | '24h';
|
|
20
|
-
showSeconds: boolean;
|
|
21
|
-
showDate: boolean;
|
|
22
|
-
lastSync: Date;
|
|
23
|
-
serverUptime: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const initialState: LiveClockState = {
|
|
27
|
-
currentTime: "Loading...",
|
|
28
|
-
timeZone: "America/Sao_Paulo",
|
|
29
|
-
format: "24h",
|
|
30
|
-
showSeconds: true,
|
|
31
|
-
showDate: true,
|
|
32
|
-
lastSync: new Date(),
|
|
33
|
-
serverUptime: 0,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export function LiveClock() {
|
|
37
|
-
const { state, call, connected, loading, status } = useHybridLiveComponent<LiveClockState>('LiveClock', initialState, {
|
|
38
|
-
debug: true
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const [showSettings, setShowSettings] = useState(false);
|
|
42
|
-
|
|
43
|
-
if (!connected || status !== 'synced') {
|
|
44
|
-
const getStatusMessage = () => {
|
|
45
|
-
switch (status) {
|
|
46
|
-
case 'connecting':
|
|
47
|
-
return '🔄 Conectando ao relógio do servidor...';
|
|
48
|
-
case 'reconnecting':
|
|
49
|
-
return '🔄 Reconectando relógio...';
|
|
50
|
-
case 'mounting':
|
|
51
|
-
return '🚀 Sincronizando horário...';
|
|
52
|
-
case 'loading':
|
|
53
|
-
return '⏳ Carregando relógio...';
|
|
54
|
-
case 'error':
|
|
55
|
-
return '❌ Erro na sincronização';
|
|
56
|
-
default:
|
|
57
|
-
return '🔄 Preparando relógio...';
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div className="flex items-center justify-center p-8 border-2 border-dashed border-gray-300 rounded-lg bg-gradient-to-br from-blue-50 to-indigo-100">
|
|
63
|
-
<div className="text-center">
|
|
64
|
-
<FaClock size={48} className="mx-auto mb-4 text-blue-500 animate-pulse" />
|
|
65
|
-
<p className="text-gray-700 font-medium">{getStatusMessage()}</p>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const getCurrentDate = () => {
|
|
72
|
-
return new Date().toLocaleDateString('pt-BR', {
|
|
73
|
-
weekday: 'long',
|
|
74
|
-
year: 'numeric',
|
|
75
|
-
month: 'long',
|
|
76
|
-
day: 'numeric'
|
|
77
|
-
});
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const formatUptime = (seconds: number) => {
|
|
81
|
-
const hours = Math.floor(seconds / 3600);
|
|
82
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
83
|
-
const secs = seconds % 60;
|
|
84
|
-
|
|
85
|
-
if (hours > 0) {
|
|
86
|
-
return `${hours}h ${minutes}m ${secs}s`;
|
|
87
|
-
} else if (minutes > 0) {
|
|
88
|
-
return `${minutes}m ${secs}s`;
|
|
89
|
-
} else {
|
|
90
|
-
return `${secs}s`;
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const handleFormatToggle = async () => {
|
|
95
|
-
const newFormat = state.format === '24h' ? '12h' : '24h';
|
|
96
|
-
try {
|
|
97
|
-
await call('setTimeFormat', { format: newFormat });
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error('Error changing format:', error);
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const handleToggleSeconds = async () => {
|
|
104
|
-
try {
|
|
105
|
-
await call('toggleSeconds');
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error('Error toggling seconds:', error);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const handleToggleDate = async () => {
|
|
112
|
-
try {
|
|
113
|
-
await call('toggleDate');
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('Error toggling date:', error);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const handleSyncTime = async () => {
|
|
120
|
-
try {
|
|
121
|
-
await call('syncTime');
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Error syncing time:', error);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const handleGetServerInfo = async () => {
|
|
128
|
-
try {
|
|
129
|
-
const result = await call('getServerInfo');
|
|
130
|
-
console.log('Server info:', result);
|
|
131
|
-
|
|
132
|
-
if (result && result.info) {
|
|
133
|
-
alert(`Server Info:\nTime: ${result.info.localTime}\nUptime: ${result.info.uptimeFormatted}\nTimezone: ${result.info.timezone}`);
|
|
134
|
-
} else {
|
|
135
|
-
console.error('Invalid server info response:', result);
|
|
136
|
-
alert('Erro: Resposta inválida do servidor');
|
|
137
|
-
}
|
|
138
|
-
} catch (error) {
|
|
139
|
-
console.error('Error getting server info:', error);
|
|
140
|
-
alert(`Erro ao obter info do servidor: ${error instanceof Error ? error.message : 'Erro desconhecido'}`);
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
return (
|
|
145
|
-
<div className="bg-gradient-to-br from-slate-50 to-blue-50 border border-gray-200 rounded-xl shadow-lg p-6 m-4 relative overflow-hidden">
|
|
146
|
-
{/* Background decoration */}
|
|
147
|
-
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-blue-200 to-indigo-300 rounded-full opacity-20 -translate-y-16 translate-x-16"></div>
|
|
148
|
-
|
|
149
|
-
{/* Header */}
|
|
150
|
-
<div className="flex items-center justify-between mb-6 relative z-10">
|
|
151
|
-
<div className="flex items-center gap-3">
|
|
152
|
-
<FaClock size={28} className="text-blue-600" />
|
|
153
|
-
<h2 className="text-2xl font-bold text-gray-800">Live Clock</h2>
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
<div className="flex items-center gap-2">
|
|
157
|
-
<span className={`px-3 py-1 rounded-full text-xs font-medium flex items-center gap-1 ${
|
|
158
|
-
connected ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
|
159
|
-
}`}>
|
|
160
|
-
{connected ? '🟢 Sincronizado' : '🔴 Desconectado'}
|
|
161
|
-
</span>
|
|
162
|
-
|
|
163
|
-
<button
|
|
164
|
-
onClick={() => setShowSettings(!showSettings)}
|
|
165
|
-
className="p-2 rounded-lg bg-gray-100 hover:bg-gray-200 transition-colors"
|
|
166
|
-
>
|
|
167
|
-
<FaCog className="text-gray-600" />
|
|
168
|
-
</button>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
{/* Main Clock Display */}
|
|
173
|
-
<div className="text-center mb-6 relative z-10">
|
|
174
|
-
<div className="bg-white rounded-2xl p-8 shadow-inner border-2 border-gray-100">
|
|
175
|
-
<div className="text-6xl font-mono font-bold text-gray-800 mb-2 tracking-wider">
|
|
176
|
-
{state.currentTime}
|
|
177
|
-
</div>
|
|
178
|
-
|
|
179
|
-
{state.showDate && (
|
|
180
|
-
<div className="text-lg text-gray-600 mb-2 flex items-center justify-center gap-2">
|
|
181
|
-
<FaCalendarAlt className="text-blue-500" />
|
|
182
|
-
{getCurrentDate()}
|
|
183
|
-
</div>
|
|
184
|
-
)}
|
|
185
|
-
|
|
186
|
-
<div className="flex items-center justify-center gap-4 text-sm text-gray-500">
|
|
187
|
-
<div className="flex items-center gap-1">
|
|
188
|
-
<FaGlobe />
|
|
189
|
-
<span>{state.timeZone}</span>
|
|
190
|
-
</div>
|
|
191
|
-
<div className="flex items-center gap-1">
|
|
192
|
-
<FaStopwatch />
|
|
193
|
-
<span>Uptime: {formatUptime(state.serverUptime)}</span>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
</div>
|
|
198
|
-
|
|
199
|
-
{/* Settings Panel */}
|
|
200
|
-
{showSettings && (
|
|
201
|
-
<div className="bg-white rounded-xl p-4 mb-4 border shadow-sm relative z-10">
|
|
202
|
-
<h3 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
|
|
203
|
-
<FaCog />
|
|
204
|
-
Configurações
|
|
205
|
-
</h3>
|
|
206
|
-
|
|
207
|
-
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
|
208
|
-
<button
|
|
209
|
-
onClick={handleFormatToggle}
|
|
210
|
-
disabled={loading}
|
|
211
|
-
className="px-3 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center justify-center gap-1"
|
|
212
|
-
>
|
|
213
|
-
<FaClock />
|
|
214
|
-
{state.format === '24h' ? '12h' : '24h'}
|
|
215
|
-
</button>
|
|
216
|
-
|
|
217
|
-
<button
|
|
218
|
-
onClick={handleToggleSeconds}
|
|
219
|
-
disabled={loading}
|
|
220
|
-
className="px-3 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center justify-center gap-1"
|
|
221
|
-
>
|
|
222
|
-
{state.showSeconds ? <FaEyeSlash /> : <FaEye />}
|
|
223
|
-
Segundos
|
|
224
|
-
</button>
|
|
225
|
-
|
|
226
|
-
<button
|
|
227
|
-
onClick={handleToggleDate}
|
|
228
|
-
disabled={loading}
|
|
229
|
-
className="px-3 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center justify-center gap-1"
|
|
230
|
-
>
|
|
231
|
-
<FaCalendarAlt />
|
|
232
|
-
Data
|
|
233
|
-
</button>
|
|
234
|
-
|
|
235
|
-
<button
|
|
236
|
-
onClick={handleSyncTime}
|
|
237
|
-
disabled={loading}
|
|
238
|
-
className="px-3 py-2 bg-orange-500 text-white rounded-lg hover:bg-orange-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center justify-center gap-1"
|
|
239
|
-
>
|
|
240
|
-
<FaSync />
|
|
241
|
-
Sync
|
|
242
|
-
</button>
|
|
243
|
-
</div>
|
|
244
|
-
</div>
|
|
245
|
-
)}
|
|
246
|
-
|
|
247
|
-
{/* Action Buttons */}
|
|
248
|
-
<div className="flex gap-3 flex-wrap relative z-10">
|
|
249
|
-
<button
|
|
250
|
-
onClick={handleGetServerInfo}
|
|
251
|
-
disabled={loading}
|
|
252
|
-
className="px-4 py-2 bg-indigo-500 text-white rounded-lg hover:bg-indigo-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center gap-2"
|
|
253
|
-
>
|
|
254
|
-
<FaServer />
|
|
255
|
-
Info do Servidor
|
|
256
|
-
</button>
|
|
257
|
-
|
|
258
|
-
<button
|
|
259
|
-
onClick={handleSyncTime}
|
|
260
|
-
disabled={loading}
|
|
261
|
-
className="px-4 py-2 bg-emerald-500 text-white rounded-lg hover:bg-emerald-600 disabled:opacity-50 disabled:cursor-not-allowed text-sm flex items-center gap-2"
|
|
262
|
-
>
|
|
263
|
-
<FaSync />
|
|
264
|
-
Sincronizar Agora
|
|
265
|
-
</button>
|
|
266
|
-
</div>
|
|
267
|
-
|
|
268
|
-
{/* Status Footer */}
|
|
269
|
-
<div className="mt-4 text-xs text-gray-500 text-center relative z-10">
|
|
270
|
-
Última sincronização: {new Date(state.lastSync).toLocaleTimeString()} •
|
|
271
|
-
Formato: {state.format} •
|
|
272
|
-
Servidor rodando há {formatUptime(state.serverUptime)}
|
|
273
|
-
</div>
|
|
274
|
-
|
|
275
|
-
{/* Loading Overlay */}
|
|
276
|
-
{loading && (
|
|
277
|
-
<div className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center rounded-xl z-20">
|
|
278
|
-
<div className="flex items-center gap-2">
|
|
279
|
-
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500"></div>
|
|
280
|
-
<span className="text-gray-700 font-medium">Sincronizando...</span>
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
)}
|
|
284
|
-
</div>
|
|
285
|
-
);
|
|
286
|
-
}
|