Skip to content

Commit 19294ad

Browse files
committed
Refactor and migration of TFMS, other changes
1 parent 0e69b5e commit 19294ad

23 files changed

Lines changed: 6321 additions & 263 deletions

‎README.md‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
Unified front-end shell for Houston ARTCC controller utilities.
44

5-
Current tools are registered in a single data file and rendered as searchable cards:
6-
- TFMS Viewer
5+
Current tools are registered in a single data file and rendered as launch cards:
6+
- TFMS
77
- Alias Guide (migrated internal route)
88
- ADAR Routes
99
- Route Validator
@@ -24,7 +24,7 @@ Then open [http://localhost:3000](http://localhost:3000).
2424

2525
- `data/tools.json`: tool registry (add/edit tools here)
2626
- `app/page.js`: homepage entry
27-
- `components/toolkit-home.js`: searchable tool grid UI
27+
- `components/toolkit-home.js`: tool launcher grid UI
2828
- `app/tools/[id]/page.js`: per-tool detail pages
2929
- `app/tools/alias-guide/page.js`: migrated Alias Guide tool
3030
- `components/alias-guide-page.js`: refactored Alias UI (sidebar nav, search, cards)
@@ -111,6 +111,13 @@ Route Validator renders from `data/zhu-routing-rules.json` and compares filed ro
111111
- If live traffic fetch fails, static samples are used automatically.
112112
- D-ATIS remains live unless that feed fails.
113113

114+
## TFMS Notes
115+
116+
- TFMS currently shows:
117+
- Specialty Summary
118+
- Online Positions (enroute + TRACON status)
119+
- Split Summary is intentionally hidden for now and can be re-enabled later.
120+
114121
### Route Validator Statuses
115122

116123
Current status labels:
@@ -159,7 +166,7 @@ npm run build
159166

160167
## Theme Modes
161168

162-
The app now supports `Light`, `Dark`, and `System` mode via a global top-right selector.
169+
The app supports `Light`, `Dark`, and `System` mode via `Auto / ☀ / ☾` controls placed in tool/page headers.
163170
Preference is saved in `localStorage` (`theme-mode`).
164171

165172
## GitHub Pages Deployment

‎app/globals.css‎

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
@import "tailwindcss";
22

33
:root {
4-
--background: #f8fafc;
5-
--foreground: #0f172a;
6-
--surface: #ffffff;
7-
--surface-soft: #f1f5f9;
8-
--surface-border: #cbd5e1;
9-
--muted: #475569;
10-
--accent: #0369a1;
11-
--accent-strong: #075985;
4+
--background: #eff4fa;
5+
--foreground: #152335;
6+
--surface: #f8fbff;
7+
--surface-soft: #eaf0f7;
8+
--surface-border: #bfcbdb;
9+
--muted: #4b5f78;
10+
--accent: #0b6da8;
11+
--accent-strong: #0a5f93;
1212
--on-accent: #ffffff;
1313
--card-shadow: 0 8px 22px rgba(15, 23, 42, 0.06);
1414
}
@@ -45,8 +45,8 @@ body {
4545
inset: 0;
4646
pointer-events: none;
4747
background:
48-
radial-gradient(circle at 10% -6%, rgba(14, 165, 233, 0.06), transparent 42%),
49-
radial-gradient(circle at 90% -10%, rgba(56, 189, 248, 0.05), transparent 40%);
48+
radial-gradient(circle at 10% -6%, rgba(14, 165, 233, 0.045), transparent 42%),
49+
radial-gradient(circle at 90% -10%, rgba(56, 189, 248, 0.04), transparent 40%);
5050
}
5151

5252
:root[data-theme="dark"] .ambient-bg {
@@ -66,36 +66,36 @@ body {
6666
}
6767

6868
.theme-switcher {
69-
position: fixed;
70-
top: 0.9rem;
71-
right: 0.9rem;
72-
z-index: 60;
7369
display: flex;
7470
align-items: center;
75-
gap: 0.45rem;
76-
background: color-mix(in srgb, var(--surface) 92%, transparent);
77-
border: 1px solid var(--surface-border);
78-
border-radius: 0.7rem;
79-
padding: 0.35rem 0.45rem;
80-
box-shadow: var(--card-shadow);
71+
gap: 0.2rem;
72+
border-radius: 0.65rem;
73+
padding: 0.1rem;
8174
}
8275

83-
.theme-label {
76+
.theme-mode-button {
77+
border: 1px solid var(--surface-border);
78+
border-radius: 0.55rem;
79+
background: transparent;
80+
color: var(--muted);
8481
font-size: 0.72rem;
8582
font-weight: 700;
86-
letter-spacing: 0.12em;
87-
text-transform: uppercase;
88-
color: var(--muted);
83+
letter-spacing: 0.06em;
84+
line-height: 1;
85+
padding: 0.33rem 0.6rem;
86+
transition: background-color 130ms ease, border-color 130ms ease, color 130ms ease;
8987
}
9088

91-
.theme-select {
92-
border: 1px solid var(--surface-border);
93-
border-radius: 0.5rem;
94-
background: var(--surface);
89+
.theme-mode-button:hover {
9590
color: var(--foreground);
96-
font-size: 0.78rem;
97-
font-weight: 600;
98-
padding: 0.2rem 0.35rem;
91+
background: var(--surface-soft);
92+
border-color: color-mix(in srgb, var(--accent) 45%, transparent);
93+
}
94+
95+
.theme-mode-button-active {
96+
color: var(--foreground);
97+
border-color: color-mix(in srgb, var(--accent) 45%, transparent);
98+
background: color-mix(in srgb, var(--accent) 14%, transparent);
9999
}
100100

101101
.hero-panel {
@@ -124,6 +124,26 @@ body {
124124
padding: 1rem;
125125
}
126126

127+
.tool-launcher-card {
128+
transition:
129+
box-shadow 160ms ease,
130+
border-color 160ms ease,
131+
background-color 160ms ease;
132+
}
133+
134+
.tool-launcher-card:hover {
135+
transform: none;
136+
border-color: color-mix(in srgb, var(--accent) 45%, var(--surface-border));
137+
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 38%, transparent);
138+
background: color-mix(in srgb, var(--surface) 92%, var(--surface-soft));
139+
}
140+
141+
.tool-launcher-card .button-primary:hover,
142+
.tool-launcher-card .button-secondary:hover {
143+
transform: none;
144+
filter: none;
145+
}
146+
127147
.badge {
128148
border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
129149
border-radius: 9999px;
@@ -342,6 +362,10 @@ body {
342362
animation: feed-pulse 2.8s ease-in-out infinite;
343363
}
344364

365+
.feed-indicator-static {
366+
animation: none;
367+
}
368+
345369
.feed-indicator-green {
346370
background: #22c55e;
347371
color: #22c55e;
@@ -357,6 +381,18 @@ body {
357381
color: #ef4444;
358382
}
359383

384+
.feed-indicator-gray {
385+
background: #94a3b8;
386+
color: #94a3b8;
387+
box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.35);
388+
}
389+
390+
:root[data-theme="light"] .feed-indicator-gray {
391+
background: #475569;
392+
color: #475569;
393+
box-shadow: 0 0 0 1px rgba(100, 116, 139, 0.45);
394+
}
395+
360396
@keyframes feed-pulse {
361397
0%,
362398
100% {

‎app/layout.js‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Rajdhani, Source_Sans_3 } from "next/font/google";
2-
import ThemeSwitcher from "@/components/theme-switcher";
32
import "./globals.css";
43

54
const headingFont = Rajdhani({
@@ -35,7 +34,6 @@ export default function RootLayout({ children }) {
3534
<html lang="en" suppressHydrationWarning>
3635
<body className={`${headingFont.variable} ${bodyFont.variable} antialiased`}>
3736
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
38-
<ThemeSwitcher />
3937
{children}
4038
</body>
4139
</html>

‎app/page.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import ToolkitHome from "@/components/toolkit-home";
2-
import { getToolCategories, getTools } from "@/lib/tools";
2+
import { getTools } from "@/lib/tools";
33

44
export default function Home() {
55
const tools = getTools();
6-
const categories = getToolCategories();
76

8-
return <ToolkitHome tools={tools} categories={categories} />;
7+
return <ToolkitHome tools={tools} />;
98
}

‎app/tools/[id]/page.js‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Link from "next/link";
22
import { notFound } from "next/navigation";
3+
import ThemeSwitcher from "@/components/theme-switcher";
34
import { getToolById, getTools } from "@/lib/tools";
45

56
export function generateStaticParams() {
@@ -34,9 +35,17 @@ export default function ToolDetailsPage({ params }) {
3435
<div className="ambient-bg" />
3536
<div className="mx-auto max-w-4xl">
3637
<article className="panel">
37-
<p className="text-accent mb-2 text-sm font-semibold uppercase tracking-[0.24em]">
38-
{tool.category}
39-
</p>
38+
<div className="mb-2 flex flex-wrap items-start justify-between gap-3">
39+
<p className="text-accent text-sm font-semibold uppercase tracking-[0.24em]">
40+
{tool.category}
41+
</p>
42+
<div className="flex flex-col items-end gap-2">
43+
<ThemeSwitcher />
44+
<Link className="button-secondary text-sm" href="/">
45+
Back to Toolkit
46+
</Link>
47+
</div>
48+
</div>
4049
<h1 className="font-heading text-main text-5xl font-bold tracking-wide md:text-6xl">
4150
{tool.name}
4251
</h1>
@@ -81,9 +90,6 @@ export default function ToolDetailsPage({ params }) {
8190
>
8291
View Source Repository
8392
</a>
84-
<Link className="button-secondary" href="/">
85-
Back to Toolkit
86-
</Link>
8793
</div>
8894
</article>
8995
</div>

‎app/tools/tfms/page.js‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import TfmsViewerPage from "@/components/tfms-viewer-page";
2+
import "./styles.css";
3+
4+
export const metadata = {
5+
title: "TFMS | ZHU Controller Toolkit",
6+
description:
7+
"Live ZHU traffic flow summaries with specialty and split projections from VATSIM data.",
8+
};
9+
10+
export default function TfmsToolPage() {
11+
return <TfmsViewerPage />;
12+
}

0 commit comments

Comments
 (0)