caf005f04b
SPA React 19 + Vite + Mantine v9 en modo oscuro (acento índigo), datos mock para iterar el diseño antes de cablear el gateway. Login con identidad + contraseña (la contraseña desbloqueará la identidad Ed25519 cifrada en el dispositivo). Sidebar: avatar de usuario, buscador (rooms/usuarios/mensajes) y lista de rooms con candado E2E / hash cleartext / badges de no leídos. Panel de chat estilo Element (avatar+nombre+hora+texto) con composer interactivo.
44 lines
1.1 KiB
TypeScript
44 lines
1.1 KiB
TypeScript
import { useState } from "react";
|
|
import { Flex, Box } from "@mantine/core";
|
|
import { Sidebar } from "./Sidebar";
|
|
import { ChatPanel } from "./ChatPanel";
|
|
import { MOCK_ROOMS } from "./mock";
|
|
import type { User } from "./types";
|
|
|
|
export function ChatShell({
|
|
user,
|
|
onLogout,
|
|
}: {
|
|
user: User;
|
|
onLogout: () => void;
|
|
}) {
|
|
const [rooms] = useState(MOCK_ROOMS);
|
|
const [activeId, setActiveId] = useState<string>(rooms[0]?.id ?? "");
|
|
const active = rooms.find((r) => r.id === activeId);
|
|
|
|
return (
|
|
<Flex h="100vh" w="100vw" style={{ overflow: "hidden" }}>
|
|
<Box
|
|
w={320}
|
|
h="100%"
|
|
bg="dark.8"
|
|
style={{
|
|
borderRight: "1px solid var(--mantine-color-dark-4)",
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
<Sidebar
|
|
user={user}
|
|
rooms={rooms}
|
|
activeId={activeId}
|
|
onSelect={setActiveId}
|
|
onLogout={onLogout}
|
|
/>
|
|
</Box>
|
|
<Box flex={1} h="100%" bg="dark.7" style={{ minWidth: 0 }}>
|
|
<ChatPanel room={active} user={user} />
|
|
</Box>
|
|
</Flex>
|
|
);
|
|
}
|