diff --git a/client/src/App.jsx b/client/src/App.jsx index b3645c2..37cb06d 100755 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,17 +1,78 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import ViolationForm from './components/ViolationForm'; import Dashboard from './components/Dashboard'; import ReadmeModal from './components/ReadmeModal'; import ToastProvider from './components/ToastProvider'; +const REPO_URL = 'https://git.alwisp.com/jason/cpas'; +const PROJECT_START = new Date('2026-03-06T11:33:32-06:00'); + +function elapsed(from) { + const totalSec = Math.floor((Date.now() - from.getTime()) / 1000); + const d = Math.floor(totalSec / 86400); + const h = Math.floor((totalSec % 86400) / 3600); + const m = Math.floor((totalSec % 3600) / 60); + const s = totalSec % 60; + return `${d}d ${String(h).padStart(2,'0')}h ${String(m).padStart(2,'0')}m ${String(s).padStart(2,'0')}s`; +} + +function DevTicker() { + const [tick, setTick] = useState(() => elapsed(PROJECT_START)); + useEffect(() => { + const id = setInterval(() => setTick(elapsed(PROJECT_START)), 1000); + return () => clearInterval(id); + }, []); + return ( + + + {tick} + + ); +} + +function GiteaIcon() { + return ( + + ); +} + +function AppFooter() { + const year = new Date().getFullYear(); + return ( + <> + + + > + ); +} + const tabs = [ { id: 'dashboard', label: '📊 Dashboard' }, { id: 'violation', label: '+ New Violation' }, ]; const s = { - app: { minHeight: '100vh', background: '#050608', fontFamily: "'Segoe UI', Arial, sans-serif", color: '#f8f9fa' }, - nav: { background: '#000000', padding: '0 40px', display: 'flex', alignItems: 'center', gap: 0, borderBottom: '1px solid #333' }, + app: { minHeight: '100vh', background: '#050608', fontFamily: "'Segoe UI', Arial, sans-serif", color: '#f8f9fa', display: 'flex', flexDirection: 'column' }, + nav: { background: '#000000', padding: '0 40px', display: 'flex', alignItems: 'center', gap: 0, borderBottom: '1px solid #333' }, logoWrap: { display: 'flex', alignItems: 'center', marginRight: '32px', padding: '14px 0' }, logoImg: { height: '28px', marginRight: '10px' }, logoText: { color: '#f8f9fa', fontWeight: 800, fontSize: '18px', letterSpacing: '0.5px' }, @@ -22,7 +83,6 @@ const s = { cursor: 'pointer', fontWeight: active ? 700 : 400, fontSize: '14px', background: 'none', border: 'none', }), - // Docs button sits flush-right in the nav docsBtn: { marginLeft: 'auto', background: 'none', @@ -38,9 +98,34 @@ const s = { alignItems: 'center', gap: '6px', }, + main: { flex: 1 }, card: { maxWidth: '1100px', margin: '30px auto', background: '#111217', borderRadius: '10px', boxShadow: '0 2px 16px rgba(0,0,0,0.6)', border: '1px solid #222' }, }; +const sf = { + footer: { + borderTop: '1px solid #1a1b22', + padding: '12px 40px', + display: 'flex', + alignItems: 'center', + gap: '12px', + fontSize: '11px', + color: 'rgba(248,249,250,0.35)', + background: '#000', + flexShrink: 0, + }, + copy: { color: 'rgba(248,249,250,0.35)' }, + sep: { color: 'rgba(248,249,250,0.15)' }, + link: { + color: 'rgba(248,249,250,0.35)', + textDecoration: 'none', + display: 'inline-flex', + alignItems: 'center', + gap: '4px', + transition: 'color 0.15s', + }, +}; + export default function App() { const [tab, setTab] = useState('dashboard'); const [showReadme, setShowReadme] = useState(false); @@ -65,10 +150,14 @@ export default function App() { -