aef8791151
- Added Appshell component with responsive navbar and main content area - Integrated ColorSchemeToggle for light/dark mode switching - Created Welcome component with styled title and introductory text - Developed ChatPage for LLM interaction with WebSocket support - Implemented Biblioteca for managing notes with rich text editor - Added LoginPage for user authentication with error handling - Introduced MessageList and MessageBubble components for chat messages - Styled components with CSS modules for consistent design
115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
import { Card, Text, Switch, Group, useMantineTheme, useComputedColorScheme } from '@mantine/core';
|
|
import { Rnd } from 'react-rnd';
|
|
import { useState } from 'react';
|
|
|
|
const GRID_SIZE = 30;
|
|
|
|
function hexToRgba(hex: string, alpha: number): string {
|
|
const sanitized = hex.replace('#', '');
|
|
const bigint = parseInt(sanitized, 16);
|
|
|
|
const r = (bigint >> 16) & 255;
|
|
const g = (bigint >> 8) & 255;
|
|
const b = bigint & 255;
|
|
|
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
}
|
|
|
|
interface CardData {
|
|
id: string;
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
const initialCards: CardData[] = [
|
|
{ id: '1', x: 0, y: 0, width: GRID_SIZE * 2, height: GRID_SIZE * 2 },
|
|
{ id: '2', x: GRID_SIZE * 2, y: 0, width: GRID_SIZE * 3, height: GRID_SIZE * 2 },
|
|
{ id: '3', x: GRID_SIZE * 3, y: 0, width: GRID_SIZE * 3, height: GRID_SIZE * 2 },
|
|
];
|
|
|
|
export const GridDashboard = () => {
|
|
const theme = useMantineTheme();
|
|
const colorScheme = useComputedColorScheme(); // ✅ directamente 'light' o 'dark'
|
|
const isDark = colorScheme === 'dark';
|
|
|
|
// Color de la rejilla adaptado al modo del tema
|
|
const gridBaseColor = isDark ? theme.colors.dark[4] : theme.colors.gray[3];
|
|
const gridColor = hexToRgba(gridBaseColor, 0.25); // Ajusta la opacidad aquí
|
|
|
|
const [cards, setCards] = useState<CardData[]>(initialCards);
|
|
const [showGrid, setShowGrid] = useState(true);
|
|
|
|
const updateCard = (id: string, updates: Partial<CardData>) => {
|
|
setCards((prev) =>
|
|
prev.map((card) => (card.id === id ? { ...card, ...updates } : card))
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Group mb="xs">
|
|
<Switch
|
|
checked={showGrid}
|
|
onChange={(event) => setShowGrid(event.currentTarget.checked)}
|
|
label="Mostrar cuadrícula"
|
|
/>
|
|
</Group>
|
|
|
|
<div
|
|
style={{
|
|
width: '100%',
|
|
height: '700px',
|
|
backgroundSize: `${GRID_SIZE}px ${GRID_SIZE}px`,
|
|
backgroundImage: showGrid
|
|
? `linear-gradient(to right, ${gridColor} 1px, transparent 1px),
|
|
linear-gradient(to bottom, ${gridColor} 1px, transparent 1px)`
|
|
: 'none',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
{cards.map((card) => (
|
|
<Rnd
|
|
key={card.id}
|
|
size={{
|
|
width: Math.round(card.width / GRID_SIZE) * GRID_SIZE,
|
|
height: Math.round(card.height / GRID_SIZE) * GRID_SIZE,
|
|
}}
|
|
position={{ x: card.x, y: card.y }}
|
|
minWidth={GRID_SIZE * 8}
|
|
minHeight={GRID_SIZE * 8}
|
|
bounds="parent"
|
|
grid={[GRID_SIZE, GRID_SIZE]}
|
|
onDragStop={(_, d) =>
|
|
updateCard(card.id, {
|
|
x: Math.round(d.x / GRID_SIZE) * GRID_SIZE,
|
|
y: Math.round(d.y / GRID_SIZE) * GRID_SIZE,
|
|
})
|
|
}
|
|
onResizeStop={(_, __, ref, ___, pos) =>
|
|
updateCard(card.id, {
|
|
width: Math.round(ref.offsetWidth / GRID_SIZE) * GRID_SIZE,
|
|
height: Math.round(ref.offsetHeight / GRID_SIZE) * GRID_SIZE,
|
|
x: Math.round(pos.x / GRID_SIZE) * GRID_SIZE,
|
|
y: Math.round(pos.y / GRID_SIZE) * GRID_SIZE,
|
|
})
|
|
}
|
|
>
|
|
<Card
|
|
shadow="sm"
|
|
padding="md"
|
|
radius="md"
|
|
withBorder
|
|
style={{ height: '100%', userSelect: 'none' }}
|
|
>
|
|
<Text fw={500}>Card {card.id}</Text>
|
|
<Text size="sm">Mueve o redimensiona</Text>
|
|
</Card>
|
|
</Rnd>
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|