feat(ui): adicionar suporte avançado de tema
- define tokens CSS/Tailwind com variantes claras e escuras - adapta layout, filtros, modais e tabela aos novos estilos - adiciona favicon otimizado e controles de dados sensíveismaster
parent
c665aa18ea
commit
3104f83170
|
|
@ -2,9 +2,9 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" sizes="96x96" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>frontned</title>
|
||||
<title>Hit Servers Manager</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
|
|
@ -1,3 +1,31 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--color-bg: 250 250 249;
|
||||
--color-card: 244 244 242;
|
||||
--color-card-border: 229 231 235;
|
||||
--color-text: 26 26 26;
|
||||
--color-text-secondary: 107 114 128;
|
||||
--color-hover: 208 74 15;
|
||||
--color-accent: 233 90 27;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--color-bg: 2 6 23;
|
||||
--color-card: 15 23 42;
|
||||
--color-card-border: 51 65 85;
|
||||
--color-text: 241 245 249;
|
||||
--color-text-secondary: 148 163 184;
|
||||
--color-hover: 249 115 22;
|
||||
--color-accent: 233 90 27;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
body {
|
||||
@apply bg-bg text-text antialiased transition-colors duration-200;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,18 +5,19 @@ import { Dashboard } from './pages/Dashboard';
|
|||
import { ProtectedRoute } from './routes/ProtectedRoute';
|
||||
|
||||
function App() {
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={
|
||||
<ProtectedRoute>
|
||||
<Dashboard />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<div className="min-h-screen bg-bg text-text transition-colors duration-200 dark:bg-slate-950 dark:text-slate-100">
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={
|
||||
<ProtectedRoute>
|
||||
<Dashboard />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,5 +254,5 @@ export const Header = ({
|
|||
};
|
||||
|
||||
const Styles = {
|
||||
wrapper: "flex items-center justify-between rounded-xl border border-cardBorder bg-card px-6 py-4 shadow-sm",
|
||||
wrapper: "flex items-center justify-between rounded-xl border border-cardBorder bg-card px-6 py-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:shadow-slate-900/50",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -74,11 +74,11 @@ export const ServerCardMetrics = () => {
|
|||
|
||||
const Styles = {
|
||||
grid: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
|
||||
card: "flex items-center gap-4 rounded-xl border border-cardBorder bg-gradient-to-br from-white/90 to-card p-5 shadow-sm",
|
||||
iconWrapper: "flex h-14 w-14 items-center justify-center rounded-lg border border-accent/20 bg-accent/10 text-accent",
|
||||
card: "flex items-center gap-4 rounded-xl border border-cardBorder bg-gradient-to-br from-white/90 to-card p-5 shadow-sm dark:border-slate-800 dark:from-slate-900 dark:to-slate-950 dark:shadow-slate-900/40",
|
||||
iconWrapper: "flex h-14 w-14 items-center justify-center rounded-lg border border-accent/20 bg-accent/10 text-accent dark:border-slate-800 dark:bg-slate-800/60",
|
||||
textGroup: "flex flex-col",
|
||||
label: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
||||
value: "text-3xl font-semibold text-text leading-tight",
|
||||
placeholder: "p-4 rounded-lg border border-cardBorder bg-card text-text-secondary text-sm",
|
||||
error: "p-4 rounded-lg border border-red-200 bg-red-50 text-red-600 text-sm",
|
||||
label: "text-xs font-medium uppercase tracking-wide text-text-secondary dark:text-slate-400",
|
||||
value: "text-3xl font-semibold leading-tight text-text dark:text-white",
|
||||
placeholder: "rounded-lg border border-cardBorder bg-card p-4 text-sm text-text-secondary dark:border-slate-800 dark:bg-slate-900 dark:text-slate-400",
|
||||
error: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-600 dark:border-red-400/30 dark:bg-red-950/40 dark:text-red-300",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ interface Props {
|
|||
serverTypeOptions?: ServersType[];
|
||||
applicationOptions?: Applications[];
|
||||
databaseOptions?: DatabaseType[];
|
||||
hideSensitive: boolean;
|
||||
onToggleSensitive: () => void;
|
||||
}
|
||||
|
||||
const withAllOption = <T extends string>(options?: T[]): Array<T | OptionAll> => {
|
||||
|
|
@ -37,6 +39,8 @@ export const ServersFilterBar = ({
|
|||
serverTypeOptions,
|
||||
applicationOptions,
|
||||
databaseOptions,
|
||||
hideSensitive,
|
||||
onToggleSensitive,
|
||||
}: Props) => {
|
||||
const typeOptions = withAllOption(serverTypeOptions);
|
||||
const applicationOptionsList = withAllOption(applicationOptions);
|
||||
|
|
@ -73,6 +77,11 @@ export const ServersFilterBar = ({
|
|||
onChange={(event) => onDbTypeChange(event.target.value as DatabaseType | OptionAll)}
|
||||
options={databaseOptionsList}
|
||||
/>
|
||||
<div className={Styles.toggleWrapper}>
|
||||
<button type="button" className={Styles.toggleButton} onClick={onToggleSensitive}>
|
||||
{hideSensitive ? "Mostrar dados confidenciais" : "Ocultar dados confidenciais"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -100,10 +109,12 @@ const Select = <T extends string>({ label, value, onChange, options }: SelectPro
|
|||
};
|
||||
|
||||
const Styles = {
|
||||
wrapper: "flex flex-wrap gap-4 rounded-lg border border-cardBorder bg-white/70 p-4 shadow-sm",
|
||||
wrapper: "flex flex-wrap items-end gap-4 rounded-lg border border-cardBorder bg-white/70 p-4 shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:shadow-slate-900/40",
|
||||
searchGroup: "flex-1 min-w-[220px]",
|
||||
selectGroup: "flex min-w-[150px] flex-col gap-1",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary",
|
||||
input: "w-full rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent",
|
||||
select: "w-full rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent capitalize",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary dark:text-slate-400",
|
||||
input: "w-full rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
select: "w-full rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent capitalize dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
toggleWrapper: "flex min-w-[200px] items-center justify-end",
|
||||
toggleButton: "rounded-md border border-cardBorder px-4 py-2 text-xs font-semibold uppercase tracking-wide text-text-secondary hover:bg-bg dark:border-slate-700 dark:text-slate-300 dark:hover:bg-slate-800",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useState } from "react";
|
||||
import type { Server } from "../types/Server";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -9,6 +8,7 @@ interface Props {
|
|||
pageSize: number;
|
||||
totalPages: number;
|
||||
totalItems: number;
|
||||
hideSensitive: boolean;
|
||||
onPageChange: (page: number) => void;
|
||||
onPageSizeChange: (size: number) => void;
|
||||
}
|
||||
|
|
@ -23,38 +23,36 @@ export const ServersTable = ({
|
|||
pageSize,
|
||||
totalPages,
|
||||
totalItems,
|
||||
hideSensitive,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
}: Props) => {
|
||||
const [hideSensitive, setHideSensitive] = useState(false);
|
||||
const showingFrom = totalItems === 0 ? 0 : page * pageSize + 1;
|
||||
const showingTo = totalItems === 0 ? 0 : Math.min((page + 1) * pageSize, totalItems);
|
||||
const hasResults = servers.length > 0;
|
||||
const isInitialLoad = loading && !hasResults;
|
||||
const showOverlay = loading && hasResults;
|
||||
|
||||
const formatSensitiveValue = (value: string | number) => (hideSensitive ? "••••" : value);
|
||||
|
||||
return (
|
||||
<div className={Styles.card}>
|
||||
<button
|
||||
type="button"
|
||||
className={Styles.hideButton}
|
||||
onClick={() => setHideSensitive((prev) => !prev)}
|
||||
disabled={loading || (!hasResults && !error)}
|
||||
aria-pressed={hideSensitive}
|
||||
>
|
||||
{hideSensitive ? "Mostrar dados sensíveis" : "Ocultar dados sensíveis"}
|
||||
</button>
|
||||
{loading && <div className={Styles.status}>Carregando servidores...</div>}
|
||||
{isInitialLoad && <div className={Styles.status}>Carregando servidores...</div>}
|
||||
{error && <div className={Styles.error}>{error}</div>}
|
||||
{!loading && !error && servers.length === 0 && (
|
||||
<div className={Styles.status}>Nenhum servidor encontrado.</div>
|
||||
)}
|
||||
{!loading && !error && hasResults && (
|
||||
<>
|
||||
{hasResults && (
|
||||
<div className="relative space-y-4">
|
||||
{showOverlay && (
|
||||
<div className={Styles.loadingOverlay}>
|
||||
<span>Atualizando lista...</span>
|
||||
</div>
|
||||
)}
|
||||
<div className={Styles.tableWrapper}>
|
||||
<table className={Styles.table}>
|
||||
<thead className={Styles.tableHead}>
|
||||
<tr className="text-left">
|
||||
<tr className={Styles.tableHeadRow}>
|
||||
<th className={Styles.tableHeadCell}>Nome</th>
|
||||
<th className={Styles.tableHeadCell}>IP</th>
|
||||
<th className={Styles.tableHeadCell}>Porta</th>
|
||||
|
|
@ -69,14 +67,14 @@ export const ServersTable = ({
|
|||
{servers.map((server) => (
|
||||
<tr
|
||||
key={server.id}
|
||||
className="hover:bg-gray-50 transition-colors even:bg-gray-50/50"
|
||||
className={Styles.tableRow}
|
||||
>
|
||||
<td className={Styles.rowCell}>{server.name}</td>
|
||||
<td className={Styles.rowCell}>{formatSensitiveValue(server.ip)}</td>
|
||||
<td className={Styles.rowCell}>{formatSensitiveValue(server.port)}</td>
|
||||
<td className={Styles.rowCell}>{formatSensitiveValue(server.user)}</td>
|
||||
<td className={Styles.rowCell}>
|
||||
<code className="text-xs bg-gray-100 px-2 py-1 rounded">
|
||||
<code className={Styles.password}>
|
||||
{hideSensitive ? "••••" : server.password}
|
||||
</code>
|
||||
</td>
|
||||
|
|
@ -130,29 +128,34 @@ export const ServersTable = ({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
<div className={Styles.footerSpacer} aria-hidden />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Styles = {
|
||||
card: "relative bg-card border border-cardBorder shadow-sm rounded-lg overflow-hidden",
|
||||
status: "p-4 text-text-secondary text-sm",
|
||||
error: "p-4 text-red-600 text-sm",
|
||||
tableWrapper: "overflow-x-auto rounded-lg shadow-sm border border-cardBorder",
|
||||
table: "min-w-full divide-y divide-cardBorder table-auto",
|
||||
tableHead: "bg-gray-50 sticky top-0",
|
||||
tableHeadCell: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-text-secondary",
|
||||
tableBody: "bg-white divide-y divide-cardBorder",
|
||||
rowCell: "px-4 py-3 text-sm text-text",
|
||||
pagination: "flex flex-col gap-2 border-t border-cardBorder bg-white px-4 py-3 sm:flex-row sm:items-center sm:justify-between",
|
||||
pageInfo: "text-sm text-text-secondary",
|
||||
card: "overflow-hidden rounded-lg border border-cardBorder bg-card shadow-sm dark:border-slate-800 dark:bg-slate-900 dark:shadow-slate-900/40",
|
||||
status: "p-4 text-sm text-text-secondary dark:text-slate-400",
|
||||
error: "p-4 text-sm text-red-600 dark:text-red-400",
|
||||
tableWrapper: "overflow-x-auto rounded-lg border border-cardBorder shadow-sm dark:border-slate-800 dark:bg-slate-950/40",
|
||||
table: "min-w-full table-auto divide-y divide-cardBorder dark:divide-slate-800",
|
||||
tableHead: "sticky top-0 bg-gray-50 dark:bg-slate-800",
|
||||
tableHeadRow: "text-left text-text dark:text-slate-200",
|
||||
tableHeadCell: "px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-text-secondary dark:text-slate-300",
|
||||
tableBody: "divide-y divide-cardBorder bg-white dark:divide-slate-800 dark:bg-slate-900",
|
||||
tableRow: "transition-colors even:bg-gray-50/50 hover:bg-gray-50 dark:even:bg-slate-900 dark:hover:bg-slate-800",
|
||||
rowCell: "px-4 py-3 text-sm text-text dark:text-slate-100",
|
||||
password: "rounded bg-gray-100 px-2 py-1 text-xs dark:bg-slate-800 dark:text-slate-100",
|
||||
pagination: "flex flex-col gap-2 border-t border-cardBorder bg-white px-4 py-3 dark:border-slate-800 dark:bg-slate-900 sm:flex-row sm:items-center sm:justify-between",
|
||||
pageInfo: "text-sm text-text-secondary dark:text-slate-400",
|
||||
paginationControls: "flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4",
|
||||
pageSizeLabel: "text-sm text-text flex items-center gap-2",
|
||||
pageSizeSelect: "rounded-md border border-cardBorder bg-white px-2 py-1 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent",
|
||||
pageSizeLabel: "text-sm text-text dark:text-slate-100 flex items-center gap-2",
|
||||
pageSizeSelect: "rounded-md border border-cardBorder bg-white px-2 py-1 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
pageButtons: "flex items-center gap-3",
|
||||
pageButton: "rounded-md border border-cardBorder px-3 py-1.5 text-sm font-medium text-text hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent",
|
||||
pageIndicator: "text-sm text-text-secondary",
|
||||
hideButton: "absolute right-3 top-3 rounded-md border border-cardBorder px-3 py-1.5 text-xs font-semibold uppercase tracking-wide text-text-secondary hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent bg-white shadow-sm",
|
||||
pageButton: "rounded-md border border-cardBorder px-3 py-1.5 text-sm font-medium text-text transition-colors hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-800",
|
||||
pageIndicator: "text-sm text-text-secondary dark:text-slate-400",
|
||||
footerSpacer: "h-4",
|
||||
loadingOverlay: "absolute inset-0 z-10 flex items-center justify-center rounded-lg bg-white/70 text-sm font-medium text-text backdrop-blur-sm dark:bg-slate-900/80 dark:text-slate-100",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -64,11 +64,11 @@ export const Modal = ({ isOpen, title, onClose, children, description, bodyClass
|
|||
};
|
||||
|
||||
const Styles = {
|
||||
overlay: "fixed inset-0 z-40 flex items-center justify-center bg-black/40 backdrop-blur-sm px-4 !mt-0",
|
||||
dialog: "w-full max-w-2xl rounded-2xl border border-cardBorder bg-card p-6 shadow-xl transform transition-all duration-200 animate-fade-up",
|
||||
header: "flex items-start justify-between gap-4 pb-4 border-b border-cardBorder",
|
||||
title: "text-lg font-semibold text-text",
|
||||
closeButton: "text-2xl leading-none text-text-secondary hover:text-text",
|
||||
description: "pt-3 text-sm text-text-secondary",
|
||||
overlay: "fixed inset-0 z-40 flex items-center justify-center bg-black/40 px-4 backdrop-blur-sm !mt-0 dark:bg-black/60",
|
||||
dialog: "w-full max-w-2xl transform animate-fade-up rounded-2xl border border-cardBorder bg-card p-6 shadow-xl transition-all duration-200 dark:border-slate-800 dark:bg-slate-900 dark:shadow-slate-900/70",
|
||||
header: "flex items-start justify-between gap-4 border-b border-cardBorder pb-4 dark:border-slate-800",
|
||||
title: "text-lg font-semibold text-text dark:text-white",
|
||||
closeButton: "text-2xl leading-none text-text-secondary hover:text-text dark:text-slate-400 dark:hover:text-white",
|
||||
description: "pt-3 text-sm text-text-secondary dark:text-slate-400",
|
||||
body: "pt-4",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const BulkImportModal = ({
|
|||
<Modal isOpen={isOpen} title="Cadastro em massa" onClose={onClose} bodyClassName={Styles.modalBody}>
|
||||
<div className={Styles.uploadCard}>
|
||||
<label htmlFor="bulk-file" className={Styles.dropLabel}>
|
||||
<span className="text-base font-medium text-text">Selecionar arquivo CSV</span>
|
||||
<span className="text-base font-medium text-text dark:text-white">Selecionar arquivo CSV</span>
|
||||
<span className="text-xs text-text-secondary">
|
||||
Arraste e solte ou clique para procurar
|
||||
</span>
|
||||
|
|
@ -115,19 +115,19 @@ const Stat = ({
|
|||
|
||||
const Styles = {
|
||||
modalBody: "space-y-5",
|
||||
uploadCard: "rounded-xl border border-dashed border-cardBorder bg-white/70 p-6 shadow-inner space-y-4",
|
||||
dropLabel: "flex flex-col gap-1 text-center",
|
||||
dropzone: "flex flex-col items-center justify-center rounded-lg border border-cardBorder bg-bg px-4 py-6 text-center cursor-pointer hover:border-accent hover:bg-white transition-colors",
|
||||
helperText: "text-xs text-text-secondary",
|
||||
uploadCard: "space-y-4 rounded-xl border border-dashed border-cardBorder bg-white/70 p-6 shadow-inner dark:border-slate-800 dark:bg-slate-900/70",
|
||||
dropLabel: "flex flex-col gap-1 text-center text-text dark:text-white",
|
||||
dropzone: "flex cursor-pointer flex-col items-center justify-center rounded-lg border border-cardBorder bg-bg px-4 py-6 text-center transition-colors hover:border-accent hover:bg-white dark:border-slate-700 dark:bg-slate-900 dark:hover:bg-slate-800",
|
||||
helperText: "text-xs text-text-secondary dark:text-slate-400",
|
||||
actionsRow: "flex flex-wrap items-center gap-3",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70",
|
||||
errorText: "text-sm text-red-600",
|
||||
resultCard: "rounded-xl border border-cardBorder bg-white/90 p-5 space-y-4",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-800",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200",
|
||||
errorText: "text-sm text-red-600 dark:text-red-400",
|
||||
resultCard: "space-y-4 rounded-xl border border-cardBorder bg-white/90 p-5 dark:border-slate-800 dark:bg-slate-900/80",
|
||||
statsGrid: "flex flex-wrap gap-4",
|
||||
failureList: "list-disc pl-5 space-y-1 text-sm text-text-secondary max-h-40 overflow-auto",
|
||||
failureList: "max-h-40 list-disc space-y-1 overflow-auto pl-5 text-sm text-text-secondary dark:text-slate-400",
|
||||
statBase: "flex flex-col rounded-lg border px-4 py-3 text-sm",
|
||||
statDefault: "border-cardBorder bg-white text-text",
|
||||
statAccent: "border-accent/40 bg-accent/10 text-accent",
|
||||
statDanger: "border-red-200 bg-red-50 text-red-600",
|
||||
statDefault: "border-cardBorder bg-white text-text dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
statAccent: "border-accent/40 bg-accent/10 text-accent dark:border-accent/20 dark:bg-accent/20 dark:text-white",
|
||||
statDanger: "border-red-200 bg-red-50 text-red-600 dark:border-red-400/40 dark:bg-red-500/10 dark:text-red-300",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ export const HeaderActions = ({
|
|||
|
||||
const Styles = {
|
||||
actions: "flex items-center gap-3",
|
||||
menuTrigger: "rounded-lg border border-cardBorder bg-white/70 px-4 py-2 text-sm font-medium text-text flex items-center gap-2 hover:bg-white transition-colors",
|
||||
dropdown: "absolute right-0 mt-2 w-48 rounded-lg border border-cardBorder bg-white py-2 shadow-lg z-10",
|
||||
dropdownItem: "w-full px-4 py-2 text-left text-sm text-text-secondary hover:bg-bg hover:text-text transition-colors",
|
||||
logoutButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-hover",
|
||||
menuTrigger: "flex items-center gap-2 rounded-lg border border-cardBorder bg-white/70 px-4 py-2 text-sm font-medium text-text transition-colors hover:bg-white dark:border-slate-700 dark:bg-slate-800/80 dark:text-slate-100 dark:hover:bg-slate-800",
|
||||
dropdown: "absolute right-0 z-10 mt-2 w-48 rounded-lg border border-cardBorder bg-white py-2 shadow-lg dark:border-slate-700 dark:bg-slate-900 dark:shadow-black/40",
|
||||
dropdownItem: "w-full px-4 py-2 text-left text-sm text-text-secondary transition-colors hover:bg-bg hover:text-text dark:text-slate-300 dark:hover:bg-slate-800 dark:hover:text-white",
|
||||
logoutButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-hover dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ export const HeaderBrand = () => {
|
|||
const Styles = {
|
||||
brand: "flex items-center gap-3",
|
||||
logo: "h-10 w-10 object-contain",
|
||||
title: "text-base font-semibold text-text",
|
||||
subtitle: "text-xs uppercase tracking-wide text-text-secondary",
|
||||
title: "text-base font-semibold text-text dark:text-white",
|
||||
subtitle: "text-xs uppercase tracking-wide text-text-secondary dark:text-slate-400",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -65,14 +65,14 @@ export const ProfileModal = ({
|
|||
|
||||
const Styles = {
|
||||
modalBody: "space-y-4",
|
||||
helperText: "text-sm text-text-secondary",
|
||||
errorMessage: "text-sm text-red-600",
|
||||
helperText: "text-sm text-text-secondary dark:text-slate-400",
|
||||
errorMessage: "text-sm text-red-600 dark:text-red-400",
|
||||
form: "space-y-4",
|
||||
formGrid: "grid gap-4 md:grid-cols-2",
|
||||
field: "flex flex-col gap-2",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary",
|
||||
input: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent disabled:opacity-70",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary dark:text-slate-400",
|
||||
input: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent disabled:opacity-70 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
modalActions: "flex justify-end gap-3 pt-2",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg disabled:opacity-50",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-800",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -95,10 +95,10 @@ const Styles = {
|
|||
form: "space-y-4",
|
||||
formGrid: "grid gap-4 md:grid-cols-2",
|
||||
field: "flex flex-col gap-2",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary",
|
||||
input: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent",
|
||||
select: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent capitalize",
|
||||
label: "text-xs font-semibold uppercase tracking-wide text-text-secondary dark:text-slate-400",
|
||||
input: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
select: "rounded-lg border border-cardBorder bg-white px-3 py-2 text-sm text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent capitalize dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
modalActions: "flex justify-end gap-3 pt-2",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg disabled:opacity-50",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70",
|
||||
secondaryButton: "rounded-md border border-cardBorder px-4 py-2 text-sm font-medium text-text hover:bg-bg disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-800",
|
||||
primaryButton: "rounded-md bg-accent px-4 py-2 text-sm font-semibold text-white hover:bg-hover disabled:opacity-70 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export const Dashboard = () => {
|
|||
const [pageSize, setPageSize] = useState<number>(10);
|
||||
const [totalPages, setTotalPages] = useState<number>(0);
|
||||
const [totalItems, setTotalItems] = useState<number>(0);
|
||||
const [hideSensitive, setHideSensitive] = useState<boolean>(true);
|
||||
const [serverTypeOptions, setServerTypeOptions] = useState<string[]>([]);
|
||||
const [applicationOptions, setApplicationOptions] = useState<string[]>([]);
|
||||
const [databaseOptions, setDatabaseOptions] = useState<string[]>([]);
|
||||
|
|
@ -150,12 +151,16 @@ export const Dashboard = () => {
|
|||
setPageSize(nextSize);
|
||||
};
|
||||
|
||||
const handleToggleSensitive = () => {
|
||||
setHideSensitive((prev) => !prev);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTypeOptions();
|
||||
}, [fetchTypeOptions]);
|
||||
|
||||
return (
|
||||
<Layout className="h-screen py-10">
|
||||
<Layout className="h-full py-10">
|
||||
<div className="space-y-6">
|
||||
<Header
|
||||
currentUser={currentUser}
|
||||
|
|
@ -176,6 +181,8 @@ export const Dashboard = () => {
|
|||
onTypeChange={handleTypeChange}
|
||||
onApplicationChange={handleApplicationChange}
|
||||
onDbTypeChange={handleDbTypeChange}
|
||||
hideSensitive={hideSensitive}
|
||||
onToggleSensitive={handleToggleSensitive}
|
||||
serverTypeOptions={serverTypeOptions}
|
||||
applicationOptions={applicationOptions}
|
||||
databaseOptions={databaseOptions}
|
||||
|
|
@ -188,6 +195,7 @@ export const Dashboard = () => {
|
|||
pageSize={pageSize}
|
||||
totalPages={totalPages}
|
||||
totalItems={totalItems}
|
||||
hideSensitive={hideSensitive}
|
||||
onPageChange={handlePageChange}
|
||||
onPageSizeChange={handlePageSizeChange}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ export const Login = () => {
|
|||
|
||||
return (
|
||||
<Layout className={Styles.layout}>
|
||||
<img src="/logo.webp " alt="Logo" className="w-36 h-36 mx-auto mb-4" />
|
||||
<img src="/logo.webp" alt="Logo" className="mx-auto mb-4 h-36 w-36" />
|
||||
<div className={Styles.card}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div>
|
||||
<label htmlFor="email" className="block mb-2 text-md font-medium text-text">Email:</label>
|
||||
<label htmlFor="email" className={Styles.label}>Email:</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
|
|
@ -65,7 +65,7 @@ export const Login = () => {
|
|||
onChange={handleChange}/>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<label htmlFor="password" className="block mb-2 text-md font-medium text-text">Password:</label>
|
||||
<label htmlFor="password" className={Styles.label}>Password:</label>
|
||||
<input
|
||||
type={showPassword ? "text" : "password"}
|
||||
id="password"
|
||||
|
|
@ -84,7 +84,7 @@ export const Login = () => {
|
|||
{showPassword ? <Eye size={18} /> : <EyeOff size={18} />}
|
||||
</button>
|
||||
</div>
|
||||
{error && <p className="text-red-500 text-sm mt-2">{error}</p>}
|
||||
{error && <p className="mt-2 text-sm text-red-500 dark:text-red-400">{error}</p>}
|
||||
<button type="submit" disabled={loading} className={Styles.button}>
|
||||
{loading ? "Autenticando..." : "Login"}
|
||||
</button>
|
||||
|
|
@ -95,9 +95,10 @@ export const Login = () => {
|
|||
};
|
||||
|
||||
const Styles = {
|
||||
layout: "h-screen flex flex-col gap-4 justify-center animate-fade-up",
|
||||
card: "w-96 p-8 shadow-lg rounded-lg border border-cardBorder bg-card",
|
||||
input: "bg-gray-50 border border-cardBorder text-text text-md rounded-lg outline-none block w-full p-2.5",
|
||||
iconButton: "absolute right-3 top-1/2 text-text p-1 focus:outline-none",
|
||||
button: "w-full bg-accent p-2 rounded-md mt-4 text-white font-bold text-lg hover:bg-hover transition duration-150",
|
||||
layout: "flex h-screen animate-fade-up flex-col justify-center gap-4 px-4",
|
||||
card: "w-full max-w-md rounded-lg border border-cardBorder bg-card p-8 shadow-lg dark:border-slate-800 dark:bg-slate-900 dark:shadow-slate-900/60",
|
||||
label: "mb-2 block text-md font-medium text-text dark:text-slate-100",
|
||||
input: "block w-full rounded-lg border border-cardBorder bg-gray-50 p-2.5 text-md text-text outline-none focus:border-accent focus:ring-1 focus:ring-accent dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100",
|
||||
iconButton: "absolute right-3 top-9 p-1 text-text focus:outline-none dark:text-slate-200",
|
||||
button: "mt-4 w-full rounded-md bg-accent p-2 text-lg font-bold text-white transition duration-150 hover:bg-hover dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,15 @@
|
|||
const withOpacity = (variable) => {
|
||||
return ({ opacityValue } = {}) => {
|
||||
if (opacityValue !== undefined) {
|
||||
return `rgb(var(${variable}) / ${opacityValue})`;
|
||||
}
|
||||
return `rgb(var(${variable}))`;
|
||||
};
|
||||
};
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
darkMode: "class",
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
|
|
@ -7,13 +17,13 @@ export default {
|
|||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
bg: '#FAFAF9',
|
||||
card: '#F4F4F2',
|
||||
cardBorder: '#E5E7EB',
|
||||
text: '#1A1A1A',
|
||||
'text-secondary': '#6B7280',
|
||||
hover: '#D04A0F',
|
||||
accent: '#E95A1B',
|
||||
bg: withOpacity("--color-bg"),
|
||||
card: withOpacity("--color-card"),
|
||||
cardBorder: withOpacity("--color-card-border"),
|
||||
text: withOpacity("--color-text"),
|
||||
"text-secondary": withOpacity("--color-text-secondary"),
|
||||
hover: withOpacity("--color-hover"),
|
||||
accent: withOpacity("--color-accent"),
|
||||
},
|
||||
keyframes: {
|
||||
'fade-up': {
|
||||
|
|
|
|||
Loading…
Reference in New Issue