diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 91cccc2..4e6db50 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -1,23 +1,3 @@ -### T-19 · Move `DashboardFilterProvider` — page-scoped provider in wrong directory - -**Where found:** `frontend/src/providers/DashboardFilterProvider.tsx` — instantiated only inside `DashboardPage.tsx` - -**Why this is needed:** The `providers/` directory implies app-wide providers (alongside `AuthProvider`, `ThemeProvider`, `TimezoneProvider`). `DashboardFilterProvider` wraps only `DashboardPageContent` and is not used anywhere else. Its placement implies reuse that doesn't exist, misleading future contributors about its scope. - -**Goal:** Co-located with its only consumer. - -**What to do:** -1. Move `DashboardFilterProvider.tsx` to `frontend/src/pages/` (alongside `DashboardPage.tsx`) or to `frontend/src/pages/dashboard/` if the page is split into a subdirectory. -2. Update imports in `DashboardPage.tsx` and any tests. - -**Possible traps and issues:** Only `DashboardPage.tsx` imports it — confirm with grep before moving. - -**Docs changes needed:** `Docs/Web-Development.md` — document what belongs in `providers/` (app-wide) vs co-located. - -**Doc references:** `Docs/Web-Development.md` - ---- - ### T-20 · Replace inline `style={{}}` objects with `makeStyles` classes **Where found:** `frontend/src/pages/map/MapBansTable.tsx` (multiple), `pages/JailDetailPage.tsx`, `pages/HistoryPage.tsx`, `pages/history/IpDetailView.tsx`, `components/WorldMap.tsx`, `components/TopCountriesPieChart.tsx`, `components/TopCountriesBarChart.tsx` diff --git a/Docs/Web-Development.md b/Docs/Web-Development.md index 625ae9f..691ece9 100644 --- a/Docs/Web-Development.md +++ b/Docs/Web-Development.md @@ -257,6 +257,7 @@ export const darkTheme: Theme = createDarkTheme(brandColors); - Co-locate styles in the same file as the component they belong to, defined above the component function. - Use `mergeClasses` when combining multiple style sets conditionally. - Reference Fluent **design tokens** (`tokens.colorBrandBackground`, `tokens.fontSizeBase300`, etc.) instead of hard-coded values — this ensures consistency and automatic theme support. +- **Inline styles are only allowed for genuinely dynamic values** (e.g., tooltip position calculated from mouse position, or height derived from data count). All static layout properties (`display`, `gap`, `margin`, `padding`, colour) must go in `makeStyles`. ```tsx import { makeStyles, tokens, mergeClasses } from "@fluentui/react-components"; diff --git a/frontend/src/pages/HistoryPage.tsx b/frontend/src/pages/HistoryPage.tsx index 926e54b..c9aa70c 100644 --- a/frontend/src/pages/HistoryPage.tsx +++ b/frontend/src/pages/HistoryPage.tsx @@ -116,6 +116,9 @@ const useStyles = makeStyles({ fontFamily: "Consolas, 'Courier New', monospace", fontSize: "0.85rem", }, + summaryText: { + color: tokens.colorNeutralForeground3, + }, }); // --------------------------------------------------------------------------- @@ -292,7 +295,7 @@ export function HistoryPage(): React.JSX.Element { {/* Summary */} {/* ---------------------------------------------------------------- */} {!loading && !error && ( - + {String(total)} record{total !== 1 ? "s" : ""} found · Page {String(currentPage)} of {String(totalPages)} · Rows highlighted in yellow have {String(HIGH_BAN_THRESHOLD)}+ repeat bans diff --git a/frontend/src/pages/JailDetailPage.tsx b/frontend/src/pages/JailDetailPage.tsx index 30013fd..c159366 100644 --- a/frontend/src/pages/JailDetailPage.tsx +++ b/frontend/src/pages/JailDetailPage.tsx @@ -5,7 +5,7 @@ * identified by the `:name` route parameter. */ -import { Button, MessageBar, MessageBarBody, Spinner, Text } from "@fluentui/react-components"; +import { Button, MessageBar, MessageBarBody, Spinner, Text, makeStyles } from "@fluentui/react-components"; import { ArrowLeftRegular } from "@fluentui/react-icons"; import { Link, useParams } from "react-router-dom"; import { useJailData } from "../hooks/useJailData"; @@ -18,7 +18,14 @@ import { BantimeEscalationSection } from "../components/jail/BantimeEscalationSe import { IgnoreListSection } from "../components/jail/IgnoreListSection"; import { useJailDetailPageStyles } from "../components/jail/jailDetailPageStyles"; +const useLinkStyles = makeStyles({ + link: { + textDecoration: "none", + }, +}); + export function JailDetailPage(): React.JSX.Element { + const linkStyles = useLinkStyles(); const styles = useJailDetailPageStyles(); const { name = "" } = useParams<{ name: string }>(); const { jail, ignoreList, ignoreSelf, loading, error, refresh } = useJailData(name); @@ -50,7 +57,7 @@ export function JailDetailPage(): React.JSX.Element { if (error) { return (
- + @@ -67,7 +74,7 @@ export function JailDetailPage(): React.JSX.Element { return (
- + diff --git a/frontend/src/pages/history/IpDetailView.tsx b/frontend/src/pages/history/IpDetailView.tsx index f061f5e..bbc10b2 100644 --- a/frontend/src/pages/history/IpDetailView.tsx +++ b/frontend/src/pages/history/IpDetailView.tsx @@ -67,6 +67,24 @@ const useStyles = makeStyles({ borderRadius: tokens.borderRadiusMedium, border: `1px solid ${tokens.colorNeutralStroke1}`, }, + loadingContainer: { + display: "flex", + justifyContent: "center", + padding: tokens.spacingVerticalXL, + }, + headerControls: { + display: "flex", + alignItems: "center", + gap: tokens.spacingHorizontalM, + }, + dimmedText: { + color: tokens.colorNeutralForeground3, + }, + monoPreformatted: { + fontFamily: "Consolas, 'Courier New', monospace", + whiteSpace: "pre-wrap", + wordBreak: "break-all", + }, }); export function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element { @@ -76,7 +94,7 @@ export function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Eleme if (loading) { return ( -
+
); @@ -101,7 +119,7 @@ export function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Eleme return (
-
+
@@ -176,17 +194,13 @@ export function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Eleme {event.matches.length === 0 ? ( - + ) : ( {event.matches.join("\n")} diff --git a/frontend/src/pages/map/MapBansTable.tsx b/frontend/src/pages/map/MapBansTable.tsx index 86c3259..d8ef8cb 100644 --- a/frontend/src/pages/map/MapBansTable.tsx +++ b/frontend/src/pages/map/MapBansTable.tsx @@ -10,6 +10,7 @@ import { TableRow, Text, Tooltip, + makeStyles, tokens, } from "@fluentui/react-components"; import { ChevronLeftRegular, ChevronRightRegular } from "@fluentui/react-icons"; @@ -27,6 +28,33 @@ interface MapBansTableProps { onPageSizeChange: (pageSize: number) => void; } +const useStyles = makeStyles({ + paginationRow: { + display: "flex", + alignItems: "center", + justifyContent: "space-between", + gap: tokens.spacingHorizontalS, + marginTop: tokens.spacingVerticalS, + }, + paginationLeft: { + display: "flex", + alignItems: "center", + gap: tokens.spacingHorizontalS, + }, + pageSize: { + display: "flex", + alignItems: "center", + gap: tokens.spacingHorizontalS, + }, + paginationButtons: { + display: "flex", + gap: tokens.spacingHorizontalXS, + }, + dimmedText: { + color: tokens.colorNeutralForeground3, + }, +}); + export function MapBansTable({ pageBans, visibleCount, @@ -38,6 +66,7 @@ export function MapBansTable({ onPageChange, onPageSizeChange, }: MapBansTableProps): React.JSX.Element { + const styles = useStyles(); return ( <> @@ -56,7 +85,7 @@ export function MapBansTable({ - + No bans found. @@ -83,7 +112,7 @@ export function MapBansTable({ content="Country could not be resolved — will retry automatically." relationship="description" > - + )} @@ -108,14 +137,14 @@ export function MapBansTable({
{visibleCount > 0 && ( -
-
- +
+
+ Showing {pageBans.length} of {visibleCount} filtered ban{visibleCount !== 1 ? "s" : ""} {" · "}Page {page} of {totalPages} -
- +
+ Page size