diff --git a/frontend/index.html b/frontend/index.html index 7cfb423..0a76d12 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,9 +2,9 @@ - + - frontned + Hit Servers Manager
diff --git a/frontend/public/favicon.png b/frontend/public/favicon.png new file mode 100644 index 0000000..4a9105c Binary files /dev/null and b/frontend/public/favicon.png differ diff --git a/frontend/src/App.css b/frontend/src/App.css index bd6213e..ab13784 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,3 +1,31 @@ @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@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; + } +} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3d73571..1f15119 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,18 +5,19 @@ import { Dashboard } from './pages/Dashboard'; import { ProtectedRoute } from './routes/ProtectedRoute'; function App() { - return ( - - - - - - } /> - } /> - - +
+ + + + + + } /> + } /> + + +
); } diff --git a/frontend/src/components/Header.tsx b/frontend/src/components/Header.tsx index 9af1ab6..355990c 100644 --- a/frontend/src/components/Header.tsx +++ b/frontend/src/components/Header.tsx @@ -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", }; diff --git a/frontend/src/components/ServerCardMetrics.tsx b/frontend/src/components/ServerCardMetrics.tsx index aa980cd..9c271a9 100644 --- a/frontend/src/components/ServerCardMetrics.tsx +++ b/frontend/src/components/ServerCardMetrics.tsx @@ -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", }; diff --git a/frontend/src/components/ServersFilterBar.tsx b/frontend/src/components/ServersFilterBar.tsx index 06d81b6..cad9618 100644 --- a/frontend/src/components/ServersFilterBar.tsx +++ b/frontend/src/components/ServersFilterBar.tsx @@ -15,6 +15,8 @@ interface Props { serverTypeOptions?: ServersType[]; applicationOptions?: Applications[]; databaseOptions?: DatabaseType[]; + hideSensitive: boolean; + onToggleSensitive: () => void; } const withAllOption = (options?: T[]): Array => { @@ -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} /> +
+ +
); }; @@ -100,10 +109,12 @@ const Select = ({ 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", }; diff --git a/frontend/src/components/ServersTable.tsx b/frontend/src/components/ServersTable.tsx index 9844099..51d59e8 100644 --- a/frontend/src/components/ServersTable.tsx +++ b/frontend/src/components/ServersTable.tsx @@ -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 (
- - {loading &&
Carregando servidores...
} + {isInitialLoad &&
Carregando servidores...
} {error &&
{error}
} {!loading && !error && servers.length === 0 && (
Nenhum servidor encontrado.
)} - {!loading && !error && hasResults && ( - <> + {hasResults && ( +
+ {showOverlay && ( +
+ Atualizando lista... +
+ )}
- + @@ -69,14 +67,14 @@ export const ServersTable = ({ {servers.map((server) => ( @@ -130,29 +128,34 @@ export const ServersTable = ({ - + )} +
); }; 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", }; diff --git a/frontend/src/components/common/Modal.tsx b/frontend/src/components/common/Modal.tsx index f41e470..14012f7 100644 --- a/frontend/src/components/common/Modal.tsx +++ b/frontend/src/components/common/Modal.tsx @@ -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", }; diff --git a/frontend/src/components/header/BulkImportModal.tsx b/frontend/src/components/header/BulkImportModal.tsx index 6b09733..0d50b0c 100644 --- a/frontend/src/components/header/BulkImportModal.tsx +++ b/frontend/src/components/header/BulkImportModal.tsx @@ -34,7 +34,7 @@ export const BulkImportModal = ({
Nome IP Porta
{server.name} {formatSensitiveValue(server.ip)} {formatSensitiveValue(server.port)} {formatSensitiveValue(server.user)} - + {hideSensitive ? "••••" : server.password}