nyte 1.0.1 → 1.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.
- package/dist/client/entry.client.d.ts +1 -1
- package/dist/client/entry.client.js +65 -176
- package/package.json +1 -1
- package/src/client/entry.client.tsx +77 -206
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function DevIndicator(): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DevIndicator = DevIndicator;
|
|
36
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
37
38
|
/*
|
|
38
39
|
* This file is part of the Nyte.js Project.
|
|
@@ -214,184 +215,72 @@ function App({ componentMap, routes, initialComponentPath, initialParams, layout
|
|
|
214
215
|
// Adiciona o indicador de dev se não for produção
|
|
215
216
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [content, process.env.NODE_ENV !== 'production' && (0, jsx_runtime_1.jsx)(DevIndicator, {})] }));
|
|
216
217
|
}
|
|
217
|
-
// --- Constantes de Configuração ---
|
|
218
|
-
const DEV_INDICATOR_SIZE = 48;
|
|
219
|
-
const DEV_INDICATOR_CORNERS = [
|
|
220
|
-
{ top: 16, left: 16 }, // 0: topo-esquerda
|
|
221
|
-
{ top: 16, right: 16 }, // 1: topo-direita
|
|
222
|
-
{ bottom: 16, left: 16 }, // 2: baixo-esquerda
|
|
223
|
-
{ bottom: 16, right: 16 }, // 3: baixo-direita
|
|
224
|
-
];
|
|
225
218
|
function DevIndicator() {
|
|
226
|
-
const [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
// Posição visual do indicador durante o arraste
|
|
230
|
-
const [position, setPosition] = (0, react_1.useState)({ top: 0, left: 0 });
|
|
231
|
-
const indicatorRef = (0, react_1.useRef)(null);
|
|
232
|
-
const dragStartRef = (0, react_1.useRef)(null);
|
|
233
|
-
// Escuta eventos de hot reload para mostrar estado de build
|
|
234
|
-
(0, react_1.useEffect)(() => {
|
|
235
|
-
if (typeof window === 'undefined')
|
|
236
|
-
return;
|
|
237
|
-
const handleHotReloadMessage = (event) => {
|
|
238
|
-
try {
|
|
239
|
-
const message = JSON.parse(event.data);
|
|
240
|
-
// Quando detecta mudança em arquivo, ativa loading
|
|
241
|
-
if (message.type === 'frontend-reload' ||
|
|
242
|
-
message.type === 'backend-api-reload' ||
|
|
243
|
-
message.type === 'src-reload') {
|
|
244
|
-
setIsBuilding(true);
|
|
245
|
-
}
|
|
246
|
-
// Quando o build termina ou servidor fica pronto, desativa loading
|
|
247
|
-
if (message.type === 'server-ready' || message.type === 'build-complete') {
|
|
248
|
-
setIsBuilding(false);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
catch (e) {
|
|
252
|
-
// Ignora mensagens que não são JSON
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
// Intercepta mensagens WebSocket
|
|
256
|
-
const originalWebSocket = window.WebSocket;
|
|
257
|
-
window.WebSocket = class extends originalWebSocket {
|
|
258
|
-
constructor(url, protocols) {
|
|
259
|
-
super(url, protocols);
|
|
260
|
-
this.addEventListener('message', (event) => {
|
|
261
|
-
if (url.toString().includes('hweb-hotreload')) {
|
|
262
|
-
handleHotReloadMessage(event);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
return () => {
|
|
268
|
-
window.WebSocket = originalWebSocket;
|
|
269
|
-
};
|
|
270
|
-
}, []);
|
|
271
|
-
// --- Estilos Dinâmicos ---
|
|
272
|
-
const getIndicatorStyle = () => {
|
|
273
|
-
const baseStyle = {
|
|
274
|
-
position: 'fixed',
|
|
275
|
-
zIndex: 9999,
|
|
276
|
-
width: DEV_INDICATOR_SIZE,
|
|
277
|
-
height: DEV_INDICATOR_SIZE,
|
|
278
|
-
borderRadius: '50%',
|
|
279
|
-
background: isBuilding
|
|
280
|
-
? 'linear-gradient(135deg, #f093fb, #f5576c)' // Gradiente Rosa/Vermelho quando building
|
|
281
|
-
: 'linear-gradient(135deg, #8e2de2, #4a00e0)', // Gradiente Roxo normal
|
|
282
|
-
color: 'white',
|
|
283
|
-
fontWeight: 'bold',
|
|
284
|
-
fontSize: 28,
|
|
285
|
-
boxShadow: isBuilding
|
|
286
|
-
? '0 4px 25px rgba(245, 87, 108, 0.6)' // Shadow mais forte quando building
|
|
287
|
-
: '0 4px 15px rgba(0,0,0,0.2)',
|
|
288
|
-
display: 'flex',
|
|
289
|
-
alignItems: 'center',
|
|
290
|
-
justifyContent: 'center',
|
|
291
|
-
cursor: isDragging ? 'grabbing' : 'grab',
|
|
292
|
-
userSelect: 'none',
|
|
293
|
-
transition: isDragging ? 'none' : 'all 0.3s ease-out',
|
|
294
|
-
animation: isBuilding ? 'hweb-pulse 1.5s ease-in-out infinite' : 'none',
|
|
295
|
-
};
|
|
296
|
-
if (isDragging) {
|
|
297
|
-
return {
|
|
298
|
-
...baseStyle,
|
|
299
|
-
top: position.top,
|
|
300
|
-
left: position.left,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
return { ...baseStyle, ...DEV_INDICATOR_CORNERS[corner] };
|
|
304
|
-
};
|
|
305
|
-
const getMenuPositionStyle = () => {
|
|
306
|
-
// Posiciona o menu dependendo do canto
|
|
307
|
-
switch (corner) {
|
|
308
|
-
case 0: return { top: '110%', left: '0' }; // Top-Left
|
|
309
|
-
case 1: return { top: '110%', right: '0' }; // Top-Right
|
|
310
|
-
case 2: return { bottom: '110%', left: '0' }; // Bottom-Left
|
|
311
|
-
case 3: return { bottom: '110%', right: '0' }; // Bottom-Right
|
|
312
|
-
default: return {};
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
// --- Lógica de Eventos ---
|
|
316
|
-
const handleMouseDown = (e) => {
|
|
317
|
-
e.preventDefault();
|
|
318
|
-
dragStartRef.current = { x: e.clientX, y: e.clientY, moved: false };
|
|
319
|
-
if (indicatorRef.current) {
|
|
320
|
-
const rect = indicatorRef.current.getBoundingClientRect();
|
|
321
|
-
setPosition({ top: rect.top, left: rect.left });
|
|
322
|
-
}
|
|
323
|
-
setIsDragging(true);
|
|
324
|
-
};
|
|
325
|
-
const handleMouseMove = (0, react_1.useCallback)((e) => {
|
|
326
|
-
if (!isDragging || !dragStartRef.current)
|
|
327
|
-
return;
|
|
328
|
-
const deltaX = e.clientX - dragStartRef.current.x;
|
|
329
|
-
const deltaY = e.clientY - dragStartRef.current.y;
|
|
330
|
-
// Diferencia clique de arrastar (threshold de 5px)
|
|
331
|
-
if (!dragStartRef.current.moved && Math.hypot(deltaX, deltaY) > 5) {
|
|
332
|
-
dragStartRef.current.moved = true;
|
|
333
|
-
}
|
|
334
|
-
if (dragStartRef.current.moved) {
|
|
335
|
-
setPosition(prevPos => ({
|
|
336
|
-
top: prevPos.top + deltaY,
|
|
337
|
-
left: prevPos.left + deltaX,
|
|
338
|
-
}));
|
|
339
|
-
// Atualiza a referência para o próximo movimento
|
|
340
|
-
dragStartRef.current.x = e.clientX;
|
|
341
|
-
dragStartRef.current.y = e.clientY;
|
|
342
|
-
}
|
|
343
|
-
}, [isDragging]);
|
|
344
|
-
const handleMouseUp = (0, react_1.useCallback)((e) => {
|
|
345
|
-
if (!isDragging)
|
|
346
|
-
return;
|
|
347
|
-
setIsDragging(false);
|
|
348
|
-
// Se moveu, calcula o canto mais próximo
|
|
349
|
-
if (dragStartRef.current?.moved) {
|
|
350
|
-
const { clientX, clientY } = e;
|
|
351
|
-
const w = window.innerWidth;
|
|
352
|
-
const h = window.innerHeight;
|
|
353
|
-
const dists = [
|
|
354
|
-
Math.hypot(clientX, clientY), // TL
|
|
355
|
-
Math.hypot(w - clientX, clientY), // TR
|
|
356
|
-
Math.hypot(clientX, h - clientY), // BL
|
|
357
|
-
Math.hypot(w - clientX, h - clientY), // BR
|
|
358
|
-
];
|
|
359
|
-
setCorner(dists.indexOf(Math.min(...dists)));
|
|
360
|
-
}
|
|
361
|
-
dragStartRef.current = null;
|
|
362
|
-
}, [isDragging]);
|
|
363
|
-
// Adiciona e remove listeners globais
|
|
364
|
-
(0, react_1.useEffect)(() => {
|
|
365
|
-
if (isDragging) {
|
|
366
|
-
window.addEventListener('mousemove', handleMouseMove);
|
|
367
|
-
window.addEventListener('mouseup', handleMouseUp);
|
|
368
|
-
}
|
|
369
|
-
return () => {
|
|
370
|
-
window.removeEventListener('mousemove', handleMouseMove);
|
|
371
|
-
window.removeEventListener('mouseup', handleMouseUp);
|
|
372
|
-
};
|
|
373
|
-
}, [isDragging, handleMouseMove, handleMouseUp]);
|
|
219
|
+
const [isVisible, setIsVisible] = (0, react_1.useState)(true);
|
|
220
|
+
if (!isVisible)
|
|
221
|
+
return null;
|
|
374
222
|
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("style", { children: `
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
223
|
+
@keyframes nyte-pulse {
|
|
224
|
+
0% { opacity: 0.4; }
|
|
225
|
+
50% { opacity: 1; }
|
|
226
|
+
100% { opacity: 0.4; }
|
|
227
|
+
}
|
|
228
|
+
.nyte-dev-badge {
|
|
229
|
+
position: fixed;
|
|
230
|
+
bottom: 20px;
|
|
231
|
+
right: 20px;
|
|
232
|
+
z-index: 999999;
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 12px;
|
|
236
|
+
padding: 8px 14px;
|
|
237
|
+
background: rgba(15, 15, 20, 0.8);
|
|
238
|
+
backdrop-filter: blur(12px);
|
|
239
|
+
-webkit-backdrop-filter: blur(12px);
|
|
240
|
+
|
|
241
|
+
border-radius: 10px;
|
|
242
|
+
color: #fff;
|
|
243
|
+
font-family: 'Inter', ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
244
|
+
font-size: 12px;
|
|
245
|
+
font-weight: 600;
|
|
246
|
+
letter-spacing: 0.05em;
|
|
247
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
248
|
+
transition: all 0.2s ease;
|
|
249
|
+
cursor: default;
|
|
250
|
+
user-select: none;
|
|
251
|
+
}
|
|
252
|
+
.nyte-dev-badge:hover {
|
|
253
|
+
border-color: rgba(142, 45, 226, 0.5);
|
|
254
|
+
transform: translateY(-2px);
|
|
255
|
+
}
|
|
256
|
+
.nyte-status-dot {
|
|
257
|
+
width: 8px;
|
|
258
|
+
height: 8px;
|
|
259
|
+
background: #10b981; /* Verde esmeralda */
|
|
260
|
+
border-radius: 50%;
|
|
261
|
+
box-shadow: 0 0 10px #10b981;
|
|
262
|
+
animation: nyte-pulse 2s infinite ease-in-out;
|
|
263
|
+
}
|
|
264
|
+
.nyte-label {
|
|
265
|
+
color: rgba(255, 255, 255, 0.5);
|
|
266
|
+
text-transform: uppercase;
|
|
267
|
+
font-size: 10px;
|
|
268
|
+
}
|
|
269
|
+
.nyte-logo {
|
|
270
|
+
background: linear-gradient(135deg, #00a3a3, #808080);
|
|
271
|
+
-webkit-background-clip: text;
|
|
272
|
+
-webkit-text-fill-color: transparent;
|
|
273
|
+
font-weight: 800;
|
|
274
|
+
}
|
|
275
|
+
` }), (0, jsx_runtime_1.jsxs)("div", { className: "nyte-dev-badge", children: [(0, jsx_runtime_1.jsx)("div", { className: "nyte-status-dot" }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("span", { className: "nyte-logo", children: "NYTE.JS" }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setIsVisible(false), style: {
|
|
276
|
+
background: 'none',
|
|
277
|
+
border: 'none',
|
|
278
|
+
color: 'rgba(255,255,255,0.3)',
|
|
279
|
+
cursor: 'pointer',
|
|
280
|
+
fontSize: '14px',
|
|
281
|
+
padding: '0 0 0 4px',
|
|
282
|
+
marginLeft: '4px'
|
|
283
|
+
}, title: "Fechar", children: "\u00D7" })] })] }));
|
|
395
284
|
}
|
|
396
285
|
// --- Inicialização do Cliente (CSR - Client-Side Rendering) ---
|
|
397
286
|
function deobfuscateData(obfuscated) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nyte",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Nyte.js is a high-level framework for building web applications with ease and speed. It provides a robust set of tools and features to streamline development and enhance productivity.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -223,221 +223,92 @@ function App({ componentMap, routes, initialComponentPath, initialParams, layout
|
|
|
223
223
|
|
|
224
224
|
|
|
225
225
|
|
|
226
|
-
// --- Constantes de Configuração ---
|
|
227
|
-
const DEV_INDICATOR_SIZE = 48;
|
|
228
|
-
const DEV_INDICATOR_CORNERS = [
|
|
229
|
-
{ top: 16, left: 16 }, // 0: topo-esquerda
|
|
230
|
-
{ top: 16, right: 16 }, // 1: topo-direita
|
|
231
|
-
{ bottom: 16, left: 16 }, // 2: baixo-esquerda
|
|
232
|
-
{ bottom: 16, right: 16 },// 3: baixo-direita
|
|
233
|
-
];
|
|
234
|
-
|
|
235
|
-
function DevIndicator() {
|
|
236
|
-
const [corner, setCorner] = useState(3); // Canto atual (0-3)
|
|
237
|
-
const [isDragging, setIsDragging] = useState(false); // Estado de arrastar
|
|
238
|
-
const [isBuilding, setIsBuilding] = useState(false); // Estado de build
|
|
239
|
-
|
|
240
|
-
// Posição visual do indicador durante o arraste
|
|
241
|
-
const [position, setPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 });
|
|
242
|
-
|
|
243
|
-
const indicatorRef = useRef<HTMLDivElement>(null);
|
|
244
|
-
const dragStartRef = useRef<{ x: number; y: number; moved: boolean } | null>(null);
|
|
245
|
-
|
|
246
|
-
// Escuta eventos de hot reload para mostrar estado de build
|
|
247
|
-
useEffect(() => {
|
|
248
|
-
if (typeof window === 'undefined') return;
|
|
249
|
-
|
|
250
|
-
const handleHotReloadMessage = (event: MessageEvent) => {
|
|
251
|
-
try {
|
|
252
|
-
const message = JSON.parse(event.data);
|
|
253
|
-
|
|
254
|
-
// Quando detecta mudança em arquivo, ativa loading
|
|
255
|
-
if (message.type === 'frontend-reload' ||
|
|
256
|
-
message.type === 'backend-api-reload' ||
|
|
257
|
-
message.type === 'src-reload') {
|
|
258
|
-
setIsBuilding(true);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Quando o build termina ou servidor fica pronto, desativa loading
|
|
262
|
-
if (message.type === 'server-ready' || message.type === 'build-complete') {
|
|
263
|
-
setIsBuilding(false);
|
|
264
|
-
}
|
|
265
|
-
} catch (e) {
|
|
266
|
-
// Ignora mensagens que não são JSON
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
// Intercepta mensagens WebSocket
|
|
271
|
-
const originalWebSocket = window.WebSocket;
|
|
272
|
-
window.WebSocket = class extends originalWebSocket {
|
|
273
|
-
constructor(url: string | URL, protocols?: string | string[]) {
|
|
274
|
-
super(url, protocols);
|
|
275
|
-
|
|
276
|
-
this.addEventListener('message', (event) => {
|
|
277
|
-
if (url.toString().includes('hweb-hotreload')) {
|
|
278
|
-
handleHotReloadMessage(event);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
} as any;
|
|
283
|
-
|
|
284
|
-
return () => {
|
|
285
|
-
window.WebSocket = originalWebSocket;
|
|
286
|
-
};
|
|
287
|
-
}, []);
|
|
288
|
-
|
|
289
|
-
// --- Estilos Dinâmicos ---
|
|
290
|
-
const getIndicatorStyle = (): React.CSSProperties => {
|
|
291
|
-
const baseStyle: React.CSSProperties = {
|
|
292
|
-
position: 'fixed',
|
|
293
|
-
zIndex: 9999,
|
|
294
|
-
width: DEV_INDICATOR_SIZE,
|
|
295
|
-
height: DEV_INDICATOR_SIZE,
|
|
296
|
-
borderRadius: '50%',
|
|
297
|
-
background: isBuilding
|
|
298
|
-
? 'linear-gradient(135deg, #f093fb, #f5576c)' // Gradiente Rosa/Vermelho quando building
|
|
299
|
-
: 'linear-gradient(135deg, #8e2de2, #4a00e0)', // Gradiente Roxo normal
|
|
300
|
-
color: 'white',
|
|
301
|
-
fontWeight: 'bold',
|
|
302
|
-
fontSize: 28,
|
|
303
|
-
boxShadow: isBuilding
|
|
304
|
-
? '0 4px 25px rgba(245, 87, 108, 0.6)' // Shadow mais forte quando building
|
|
305
|
-
: '0 4px 15px rgba(0,0,0,0.2)',
|
|
306
|
-
display: 'flex',
|
|
307
|
-
alignItems: 'center',
|
|
308
|
-
justifyContent: 'center',
|
|
309
|
-
cursor: isDragging ? 'grabbing' : 'grab',
|
|
310
|
-
userSelect: 'none',
|
|
311
|
-
transition: isDragging ? 'none' : 'all 0.3s ease-out',
|
|
312
|
-
animation: isBuilding ? 'hweb-pulse 1.5s ease-in-out infinite' : 'none',
|
|
313
|
-
};
|
|
314
226
|
|
|
315
|
-
if (isDragging) {
|
|
316
|
-
return {
|
|
317
|
-
...baseStyle,
|
|
318
|
-
top: position.top,
|
|
319
|
-
left: position.left,
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return { ...baseStyle, ...DEV_INDICATOR_CORNERS[corner] };
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const getMenuPositionStyle = (): React.CSSProperties => {
|
|
327
|
-
// Posiciona o menu dependendo do canto
|
|
328
|
-
switch (corner) {
|
|
329
|
-
case 0: return { top: '110%', left: '0' }; // Top-Left
|
|
330
|
-
case 1: return { top: '110%', right: '0' }; // Top-Right
|
|
331
|
-
case 2: return { bottom: '110%', left: '0' }; // Bottom-Left
|
|
332
|
-
case 3: return { bottom: '110%', right: '0' }; // Bottom-Right
|
|
333
|
-
default: return {};
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
|
|
337
|
-
// --- Lógica de Eventos ---
|
|
338
|
-
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
339
|
-
e.preventDefault();
|
|
340
|
-
dragStartRef.current = { x: e.clientX, y: e.clientY, moved: false };
|
|
341
|
-
if (indicatorRef.current) {
|
|
342
|
-
const rect = indicatorRef.current.getBoundingClientRect();
|
|
343
|
-
setPosition({ top: rect.top, left: rect.left });
|
|
344
|
-
}
|
|
345
|
-
setIsDragging(true);
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
const handleMouseMove = useCallback((e: MouseEvent) => {
|
|
349
|
-
if (!isDragging || !dragStartRef.current) return;
|
|
350
227
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
// Diferencia clique de arrastar (threshold de 5px)
|
|
355
|
-
if (!dragStartRef.current.moved && Math.hypot(deltaX, deltaY) > 5) {
|
|
356
|
-
dragStartRef.current.moved = true;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (dragStartRef.current.moved) {
|
|
360
|
-
setPosition(prevPos => ({
|
|
361
|
-
top: prevPos.top + deltaY,
|
|
362
|
-
left: prevPos.left + deltaX,
|
|
363
|
-
}));
|
|
364
|
-
// Atualiza a referência para o próximo movimento
|
|
365
|
-
dragStartRef.current.x = e.clientX;
|
|
366
|
-
dragStartRef.current.y = e.clientY;
|
|
367
|
-
}
|
|
368
|
-
}, [isDragging]);
|
|
369
|
-
|
|
370
|
-
const handleMouseUp = useCallback((e: MouseEvent) => {
|
|
371
|
-
if (!isDragging) return;
|
|
372
|
-
setIsDragging(false);
|
|
373
|
-
|
|
374
|
-
// Se moveu, calcula o canto mais próximo
|
|
375
|
-
if (dragStartRef.current?.moved) {
|
|
376
|
-
const { clientX, clientY } = e;
|
|
377
|
-
const w = window.innerWidth;
|
|
378
|
-
const h = window.innerHeight;
|
|
379
|
-
|
|
380
|
-
const dists = [
|
|
381
|
-
Math.hypot(clientX, clientY), // TL
|
|
382
|
-
Math.hypot(w - clientX, clientY), // TR
|
|
383
|
-
Math.hypot(clientX, h - clientY), // BL
|
|
384
|
-
Math.hypot(w - clientX, h - clientY), // BR
|
|
385
|
-
];
|
|
386
|
-
setCorner(dists.indexOf(Math.min(...dists)));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
dragStartRef.current = null;
|
|
390
|
-
}, [isDragging]);
|
|
391
|
-
|
|
392
|
-
// Adiciona e remove listeners globais
|
|
393
|
-
useEffect(() => {
|
|
394
|
-
if (isDragging) {
|
|
395
|
-
window.addEventListener('mousemove', handleMouseMove);
|
|
396
|
-
window.addEventListener('mouseup', handleMouseUp);
|
|
397
|
-
}
|
|
398
|
-
return () => {
|
|
399
|
-
window.removeEventListener('mousemove', handleMouseMove);
|
|
400
|
-
window.removeEventListener('mouseup', handleMouseUp);
|
|
401
|
-
};
|
|
402
|
-
}, [isDragging, handleMouseMove, handleMouseUp]);
|
|
228
|
+
export function DevIndicator() {
|
|
229
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
403
230
|
|
|
231
|
+
if (!isVisible) return null;
|
|
404
232
|
|
|
405
233
|
return (
|
|
406
234
|
<>
|
|
407
235
|
<style>
|
|
408
236
|
{`
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
237
|
+
@keyframes nyte-pulse {
|
|
238
|
+
0% { opacity: 0.4; }
|
|
239
|
+
50% { opacity: 1; }
|
|
240
|
+
100% { opacity: 0.4; }
|
|
241
|
+
}
|
|
242
|
+
.nyte-dev-badge {
|
|
243
|
+
position: fixed;
|
|
244
|
+
bottom: 20px;
|
|
245
|
+
right: 20px;
|
|
246
|
+
z-index: 999999;
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
gap: 12px;
|
|
250
|
+
padding: 8px 14px;
|
|
251
|
+
background: rgba(15, 15, 20, 0.8);
|
|
252
|
+
backdrop-filter: blur(12px);
|
|
253
|
+
-webkit-backdrop-filter: blur(12px);
|
|
254
|
+
|
|
255
|
+
border-radius: 10px;
|
|
256
|
+
color: #fff;
|
|
257
|
+
font-family: 'Inter', ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
258
|
+
font-size: 12px;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
letter-spacing: 0.05em;
|
|
261
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
|
262
|
+
transition: all 0.2s ease;
|
|
263
|
+
cursor: default;
|
|
264
|
+
user-select: none;
|
|
265
|
+
}
|
|
266
|
+
.nyte-dev-badge:hover {
|
|
267
|
+
border-color: rgba(142, 45, 226, 0.5);
|
|
268
|
+
transform: translateY(-2px);
|
|
269
|
+
}
|
|
270
|
+
.nyte-status-dot {
|
|
271
|
+
width: 8px;
|
|
272
|
+
height: 8px;
|
|
273
|
+
background: #10b981; /* Verde esmeralda */
|
|
274
|
+
border-radius: 50%;
|
|
275
|
+
box-shadow: 0 0 10px #10b981;
|
|
276
|
+
animation: nyte-pulse 2s infinite ease-in-out;
|
|
277
|
+
}
|
|
278
|
+
.nyte-label {
|
|
279
|
+
color: rgba(255, 255, 255, 0.5);
|
|
280
|
+
text-transform: uppercase;
|
|
281
|
+
font-size: 10px;
|
|
282
|
+
}
|
|
283
|
+
.nyte-logo {
|
|
284
|
+
background: linear-gradient(135deg, #00a3a3, #808080);
|
|
285
|
+
-webkit-background-clip: text;
|
|
286
|
+
-webkit-text-fill-color: transparent;
|
|
287
|
+
font-weight: 800;
|
|
288
|
+
}
|
|
289
|
+
`}
|
|
429
290
|
</style>
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
291
|
+
|
|
292
|
+
<div className="nyte-dev-badge">
|
|
293
|
+
<div className="nyte-status-dot" />
|
|
294
|
+
<div>
|
|
295
|
+
<span className="nyte-logo">NYTE.JS</span>
|
|
296
|
+
</div>
|
|
297
|
+
<button
|
|
298
|
+
onClick={() => setIsVisible(false)}
|
|
299
|
+
style={{
|
|
300
|
+
background: 'none',
|
|
301
|
+
border: 'none',
|
|
302
|
+
color: 'rgba(255,255,255,0.3)',
|
|
303
|
+
cursor: 'pointer',
|
|
304
|
+
fontSize: '14px',
|
|
305
|
+
padding: '0 0 0 4px',
|
|
306
|
+
marginLeft: '4px'
|
|
307
|
+
}}
|
|
308
|
+
title="Fechar"
|
|
309
|
+
>
|
|
310
|
+
×
|
|
311
|
+
</button>
|
|
441
312
|
</div>
|
|
442
313
|
</>
|
|
443
314
|
);
|