From 7e1164af13d93379a2ce8de9dae6103b16a8bf07 Mon Sep 17 00:00:00 2001 From: jason Date: Sun, 8 Mar 2026 00:21:30 -0600 Subject: [PATCH] feat: add footer with copyright, Gitea repo link, and live dev ticker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - © Jason Stedwell copyright with current year - Gitea icon + link to https://git.alwisp.com/jason/cpas - Running elapsed time ticker since first commit (2026-03-06T11:33:32) ticks every second: Xd HHh MMm SSs format - App layout changed to flex column so footer pins to page bottom - Footer styles isolated in `sf` object for clarity --- client/src/App.jsx | 77 +--------------------------------------------- 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/client/src/App.jsx b/client/src/App.jsx index b3645c2..df8dadf 100755 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,76 +1 @@ -import React, { useState } from 'react'; -import ViolationForm from './components/ViolationForm'; -import Dashboard from './components/Dashboard'; -import ReadmeModal from './components/ReadmeModal'; -import ToastProvider from './components/ToastProvider'; - -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' }, - 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' }, - tab: (active) => ({ - padding: '18px 22px', - color: active ? '#f8f9fa' : 'rgba(248,249,250,0.6)', - borderBottom: active ? '3px solid #d4af37' : '3px solid transparent', - 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', - border: '1px solid #2a2b3a', - color: '#9ca0b8', - borderRadius: '6px', - padding: '6px 14px', - fontSize: '12px', - cursor: 'pointer', - fontWeight: 600, - letterSpacing: '0.3px', - display: 'flex', - alignItems: 'center', - gap: '6px', - }, - card: { maxWidth: '1100px', margin: '30px auto', background: '#111217', borderRadius: '10px', boxShadow: '0 2px 16px rgba(0,0,0,0.6)', border: '1px solid #222' }, -}; - -export default function App() { - const [tab, setTab] = useState('dashboard'); - const [showReadme, setShowReadme] = useState(false); - - return ( - -
- - -
- {tab === 'dashboard' ? : } -
- - {showReadme && setShowReadme(false)} />} -
-
- ); -} +aW1wb3J0IFJlYWN0LCB7IHVzZVN0YXRlLCB1c2VFZmZlY3QgfSBmcm9tICdyZWFjdCc7CmltcG9ydCBWaW9sYXRpb25Gb3JtIGZyb20gJy4vY29tcG9uZW50cy9WaW9sYXRpb25Gb3JtJzsKaW1wb3J0IERhc2hib2FyZCAgICAgZnJvbSAnLi9jb21wb25lbnRzL0Rhc2hib2FyZCc7CmltcG9ydCBSZWFkbWVNb2RhbCAgIGZyb20gJy4vY29tcG9uZW50cy9SZWFkbWVNb2RhbCc7CmltcG9ydCBUb2FzdFByb3ZpZGVyIGZyb20gJy4vY29tcG9uZW50cy9Ub2FzdFByb3ZpZGVyJzsKCmNvbnN0IFJFUE9fVVJMICAgICAgPSAnaHR0cHM6Ly9naXQuYWx3aXNwLmNvbS9qYXNvbi9jcGFzJzsKLy8gRmlyc3QgY29tbWl0IHRpbWVzdGFtcCDigJQgdXNlZCB0byBkcml2ZSB0aGUgZGV2IHRpY2tlcgpjb25zdCBQUk9KRUNUX1NUQVJUID0gbmV3IERhdGUoJzIwMjYtMDMtMDZUMTE6MzM6MzItMDY6MDAnKTsKCmNvbnN0IHRhYnMgPSBbCiAgeyBpZDogJ2Rhc2hib2FyZCcsIGxhYmVsOiAn8J+TiiBEYXNoYm9hcmQnIH0sCiAgeyBpZDogJ3Zpb2xhdGlvbicsIGxhYmVsOiAnKyBOZXcgVmlvbGF0aW9uJyB9LApdOwoKLyog4pSA4pSAIGhlbHBlcnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCmZ1bmN0aW9uIGVsYXBzZWQoZnJvbSkgewogIGNvbnN0IGRpZmYgPSBNYXRoLmZsb29yKChEYXRlLm5vdygpIC0gZnJvbS5nZXRUaW1lKCkpIC8gMTAwMCk7CiAgY29uc3QgZCA9IE1hdGguZmxvb3IoZGlmZiAvIDg2NDAwKTsKICBjb25zdCBoID0gTWF0aC5mbG9vcigoZGlmZiAlIDg2NDAwKSAvIDM2MDApOwogIGNvbnN0IG0gPSBNYXRoLmZsb29yKChkaWZmICUgMzYwMCkgLyA2MCk7CiAgY29uc3QgcyA9IGRpZmYgJSA2MDsKICByZXR1cm4gYCR7ZH1kICR7U3RyaW5nKGgpLnBhZFN0YXJ0KDIsJzAnKX1oICR7U3RyaW5nKG0pLnBhZFN0YXJ0KDIsJzAnKX1tICR7U3RyaW5nKHMpLnBhZFN0YXJ0KDIsJzAnKX1zYDsKfQoKLyog4pSA4pSAIHN1Yi1jb21wb25lbnRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwpmdW5jdGlvbiBEZXZUaWNrZXIoKSB7CiAgY29uc3QgW3RpY2ssIHNldFRpY2tdID0gdXNlU3RhdGUoKCkgPT4gZWxhcHNlZChQUk9KRUNUX1NUQVJUKSk7CiAgdXNlRWZmZWN0KCgpID0+IHsKICAgIGNvbnN0IGlkID0gc2V0SW50ZXJ2YWwoKCkgPT4gc2V0VGljayhlbGFwc2VkKFBST0pFQ1RfU1RBUlQpKSwgMTAwMCk7CiAgICByZXR1cm4gKCkgPT4gY2xlYXJJbnRlcnZhbChpZCk7CiAgfSwgW10pOwogIHJldHVybiAoCiAgICA8c3BhbiBzdHlsZT17c2YudGlja2VyfSB0aXRsZT0iVGltZSBzaW5jZSBmaXJzdCBjb21taXQiPgogICAgICA8c3BhbiBzdHlsZT17c2YudGlja2VyRG90fSAvPgogICAgICB7dGlja30KICAgIDwvc3Bhbj4KICApOwp9CgpmdW5jdGlvbiBHaXRlYUljb24oKSB7CiAgLy8gU2ltcGxlIEdpdGVhLXN0eWxlIGljb24gdXNpbmcgU1ZHIHBhdGgKICByZXR1cm4gKAogICAgPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iY3VycmVudENvbG9yIiBzdHlsZT17eyBkaXNwbGF5OidibG9jaycgfX0+CiAgICAgIDxwYXRoIGQ9Ik0xMiAyQzYuNDc3IDIgMiA2LjQ3NyAyIDEyYzAgNC40MTggMi44NjUgOC4xNjYgNi44MzkgOS40ODkuNS4wOTIuNjgyLS4yMTcuNjgyLS40ODIKICAgICAgICAgICAgICAgMC0uMjM3LS4wMDktLjg2OC0uMDEzLTEuNzAzLTIuNzgyLjYwNS0zLjM2OS0xLjM0LTMuMzY5LTEuMzQtLjQ1NC0xLjE1NC0xLjExLTEuNDYyCiAgICAgICAgICAgICAgIC0xLjExLTEuNDYyLS45MDgtLjYyLjA2OS0uNjA4LjA2OS0uNjA4IDEuMDAzLjA3IDEuNTMxIDEuMDMgMS41MzEgMS4wMy44OTIgMS41MjkKICAgICAgICAgICAgICAgMi4zNDEgMS4wODcgMi45MS44MzIuMDkyLS42NDcuMzUtMS4wODguNjM2LTEuMzM4LTIuMjItLjI1My00LjU1NS0xLjExLTQuNTU1LTQuOTQzCiAgICAgICAgICAgICAgIDAtMS4wOTEuMzktMS45ODQgMS4wMjktMi42ODMtLjEwMy0uMjUzLS40NDYtMS4yNy4wOTgtMi42NDcgMCAwIC44NC0uMjY5IDIuNzUgMS4wMjUKICAgICAgICAgICAgICAgQTkuNTY0IDkuNTY0IDAgMDExMiA2Ljg0NGE5LjU5IDkuNTkgMCAwMTIuNTA0LjMzN2MxLjkwOS0xLjI5NCAyLjc0Ny0xLjAyNSAyLjc0Ny0xLjAyNQogICAgICAgICAgICAgICAuNTQ2IDEuMzc3LjIwMiAyLjM5NC4xIDIuNjQ3LjY0LjY5OSAxLjAyOCAxLjU5MiAxLjAyOCAyLjY4MyAwIDMuODQyLTIuMzM5IDQuNjg3CiAgICAgICAgICAgICAgIC00LjU2NiA0LjkzNS4zNTkuMzA5LjY3OC45MTkuNjc4IDEuODUyIDAgMS4zMzYtLjAxMiAyLjQxNS0uMDEyIDIuNzQzIDAgLjI2Ny4xOC41NzgKICAgICAgICAgICAgICAgLjY4OC40OEMxOS4xMzggMjAuMTYzIDIyIDE2LjQxOCAyMiAxMmMwLTUuNTIzLTQuNDc3LTEwLTEwLTEweiIvPgogICAgPC9zdmc+CiAgKTsKfQoKZnVuY3Rpb24gQXBwRm9vdGVyKCkgewogIHJldHVybiAoCiAgICA8Zm9vdGVyIHN0eWxlPXtzZi5mb290ZXJ9PgogICAgICA8c3BhbiBzdHlsZT17c2YuY29weX0+wqkge25ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKX0gSmFzb24gU3RlZHdlbGw8L3NwYW4+CiAgICAgIDxzcGFuIHN0eWxlPXtzZi5zZXB9PsK3PC9zcGFuPgogICAgICA8RGV2VGlja2VyIC8+CiAgICAgIDxzcGFuIHN0eWxlPXtzZi5zZXB9PsK3PC9zcGFuPgogICAgICA8YSBocmVmPXtSRVBPX1VSTH0gdGFyZ2V0PSJfYmxhbmsiIHJlbD0ibm9vcGVuZXIgbm9yZWZlcnJlciIgc3R5bGU9e3NmLnJlcG9MaW5rfSB0aXRsZT0iVmlldyBzb3VyY2Ugb24gR2l0ZWEiPgogICAgICAgIDxHaXRlYUljb24gLz4KICAgICAgICA8c3Bhbj5jcGFzPC9zcGFuPgogICAgICA8L2E+CiAgICA8L2Zvb3Rlcj4KICApOwp9CgovKiDilIDilIAgc3R5bGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLwpjb25zdCBzID0gewogIGFwcDogICAgICB7IG1pbkhlaWdodDogJzEwMHZoJywgYmFja2dyb3VuZDogJyMwNTA2MDgnLCBmb250RmFtaWx5OiAiJ1NlZ29lIFVJJywgQXJpYWwsIHNhbnMtc2VyaWYiLCBjb2xvcjogJyNmOGY5ZmEnLCBkaXNwbGF5OiAnZmxleCcsIGZsZXhEaXJlY3Rpb246ICdjb2x1bW4nIH0sCiAgbmF2OiAgICAgIHsgYmFja2dyb3VuZDogJyMwMDAwMDAnLCBwYWRkaW5nOiAnMCA0MHB4JywgZGlzcGxheTogJ2ZsZXgnLCBhbGlnbkl0ZW1zOiAnY2VudGVyJywgZ2FwOiAwLCBib3JkZXJCb3R0b206ICcxcHggc29saWQgIzMzMycgfSwKICBsb2dvV3JhcDogeyBkaXNwbGF5OiAnZmxleCcsIGFsaWduSXRlbXM6ICdjZW50ZXInLCBtYXJnaW5SaWdodDogJzMycHgnLCBwYWRkaW5nOiAnMTRweCAwJyB9LAogIGxvZ29JbWc6ICB7IGhlaWdodDogJzI4cHgnLCBtYXJnaW5SaWdodDogJzEwcHgnIH0sCiAgbG9nb1RleHQ6IHsgY29sb3I6ICcjZjhmOWZhJywgZm9udFdlaWdodDogODAwLCBmb250U2l6ZTogJzE4cHgnLCBsZXR0ZXJTcGFjaW5nOiAnMC41cHgnIH0sCiAgdGFiOiAoYWN0aXZlKSA9PiAoewogICAgcGFkZGluZzogJzE4cHggMjJweCcsCiAgICBjb2xvcjogYWN0aXZlID8gJyNmOGY5ZmEnIDogJ3JnYmEoMjQ4LDI0OSwyNTAsMC42KScsCiAgICBib3JkZXJCb3R0b206IGFjdGl2ZSA/ICczcHggc29saWQgI2Q0YWYzNycgOiAnM3B4IHNvbGlkIHRyYW5zcGFyZW50JywKICAgIGN1cnNvcjogJ3BvaW50ZXInLCBmb250V2VpZ2h0OiBhY3RpdmUgPyA3MDAgOiA0MDAsIGZvbnRTaXplOiAnMTRweCcsCiAgICBiYWNrZ3JvdW5kOiAnbm9uZScsIGJvcmRlcjogJ25vbmUnLAogIH0pLAogIGRvY3NCdG46IHsKICAgIG1hcmdpbkxlZnQ6ICdhdXRvJywKICAgIGJhY2tncm91bmQ6ICdub25lJywKICAgIGJvcmRlcjogJzFweCBzb2xpZCAjMmEyYjNhJywKICAgIGNvbG9yOiAnIzljYTBiOCcsCiAgICBib3JkZXJSYWRpdXM6ICc2cHgnLAogICAgcGFkZGluZzogJzZweCAxNHB4JywKICAgIGZvbnRTaXplOiAnMTJweCcsCiAgICBjdXJzb3I6ICdwb2ludGVyJywKICAgIGZvbnRXZWlnaHQ6IDYwMCwKICAgIGxldHRlclNwYWNpbmc6ICcwLjNweCcsCiAgICBkaXNwbGF5OiAnZmxleCcsCiAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJywKICAgIGdhcDogJzZweCcsCiAgfSwKICBtYWluOiB7IGZsZXg6IDEgfSwKICBjYXJkOiB7IG1heFdpZHRoOiAnMTEwMHB4JywgbWFyZ2luOiAnMzBweCBhdXRvJywgYmFja2dyb3VuZDogJyMxMTEyMTcnLCBib3JkZXJSYWRpdXM6ICcxMHB4JywgYm94U2hhZG93OiAnMCAycHggMTZweCByZ2JhKDAsMCwwLDAuNiknLCBib3JkZXI6ICcxcHggc29saWQgIzIyMicgfSwKfTsKCi8vIEZvb3Rlci1zcGVjaWZpYyBzdHlsZXMga2VwdCBzZXBhcmF0ZSBmb3IgY2xhcml0eQpjb25zdCBzZiA9IHsKICBmb290ZXI6IHsKICAgIGJhY2tncm91bmQ6ICcjMDAwJywKICAgIGJvcmRlclRvcDogJzFweCBzb2xpZCAjMWUxZjJlJywKICAgIHBhZGRpbmc6ICcxMnB4IDQwcHgnLAogICAgZGlzcGxheTogJ2ZsZXgnLAogICAgYWxpZ25JdGVtczogJ2NlbnRlcicsCiAgICBnYXA6ICcxMHB4JywKICAgIGZvbnRTaXplOiAnMTJweCcsCiAgICBjb2xvcjogJyM0YTRkNjYnLAogICAgZmxleFdyYXA6ICd3cmFwJywKICB9LAogIGNvcHk6ICAgICAgeyBjb2xvcjogJyM0YTRkNjYnLCB3aGl0ZVNwYWNlOiAnbm93cmFwJyB9LAogIHNlcDogICAgICAgeyBjb2xvcjogJyMyYTJiM2EnLCB1c2VyU2VsZWN0OiAnbm9uZScgfSwKICB0aWNrZXI6IHsKICAgIGRpc3BsYXk6ICdpbmxpbmUtZmxleCcsCiAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJywKICAgIGdhcDogJzZweCcsCiAgICBmb250RmFtaWx5OiAiJ0NvdXJpZXIgTmV3JywgbW9ub3NwYWNlIiwKICAgIGZvbnRTaXplOiAnMTFweCcsCiAgICBjb2xvcjogJyM1YTdhNWEnLAogICAgbGV0dGVyU3BhY2luZzogJzAuNXB4JywKICB9LAogIHRpY2tlckRvdDogewogICAgd2lkdGg6ICc2cHgnLAogICAgaGVpZ2h0OiAnNnB4JywKICAgIGJvcmRlclJhZGl1czogJzUwJScsCiAgICBiYWNrZ3JvdW5kOiAnIzNhNmEzYScsCiAgICBib3hTaGFkb3c6ICcwIDAgNHB4ICMzYTZhM2EnLAogICAgZmxleFNocmluazogMCwKICB9LAogIHJlcG9MaW5rOiB7CiAgICBkaXNwbGF5OiAnaW5saW5lLWZsZXgnLAogICAgYWxpZ25JdGVtczogJ2NlbnRlcicsCiAgICBnYXA6ICc1cHgnLAogICAgY29sb3I6ICcjNGE0ZDY2JywKICAgIHRleHREZWNvcmF0aW9uOiAnbm9uZScsCiAgICB0cmFuc2l0aW9uOiAnY29sb3IgMC4xNXMnLAogIH0sCn07CgovKiDilIDilIAgbWFpbiBhcHAg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovCmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEFwcCgpIHsKICBjb25zdCBbdGFiLCAgICAgICAgc2V0VGFiXSAgICAgICAgPSB1c2VTdGF0ZSgnZGFzaGJvYXJkJyk7CiAgY29uc3QgW3Nob3dSZWFkbWUsIHNldFNob3dSZWFkbWVdID0gdXNlU3RhdGUoZmFsc2UpOwoKICByZXR1cm4gKAogICAgPFRvYXN0UHJvdmlkZXI+CiAgICAgIDxkaXYgc3R5bGU9e3MuYXBwfT4KICAgICAgICA8bmF2IHN0eWxlPXtzLm5hdn0+CiAgICAgICAgICA8ZGl2IHN0eWxlPXtzLmxvZ29XcmFwfT4KICAgICAgICAgICAgPGltZyBzcmM9Ii9zdGF0aWMvbXBtLWxvZ28ucG5nIiBhbHQ9Ik1QTSIgc3R5bGU9e3MubG9nb0ltZ30gLz4KICAgICAgICAgICAgPGRpdiBzdHlsZT17cy5sb2dvVGV4dH0+Q1BBUyBUcmFja2VyPC9kaXY+CiAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICB7dGFicy5tYXAodCA9PiAoCiAgICAgICAgICAgIDxidXR0b24ga2V5PXt0LmlkfSBzdHlsZT17cy50YWIodGFiID09PSB0LmlkKX0gb25DbGljaz17KCkgPT4gc2V0VGFiKHQuaWQpfT4KICAgICAgICAgICAgICB7dC5sYWJlbH0KICAgICAgICAgICAgPC9idXR0b24+CiAgICAgICAgICApKX0KCiAgICAgICAgICA8YnV0dG9uIHN0eWxlPXtzLmRvY3NCdG59IG9uQ2xpY2s9eygpID0+IHNldFNob3dSZWFkbWUodHJ1ZSl9IHRpdGxlPSJPcGVuIGFkbWluIGRvY3VtZW50YXRpb24iPgogICAgICAgICAgICA8c3Bhbj4/PC9zcGFuPiBEb2NzCiAgICAgICAgICA8L2J1dHRvbj4KICAgICAgICA8L25hdj4KCiAgICAgICAgPGRpdiBzdHlsZT17cy5tYWlufT4KICAgICAgICAgIDxkaXYgc3R5bGU9e3MuY2FyZH0+CiAgICAgICAgICAgIHt0YWIgPT09ICdkYXNoYm9hcmQnID8gPERhc2hib2FyZCAvPiA6IDxWaW9sYXRpb25Gb3JtIC8+fQogICAgICAgICAgPC9kaXY+CiAgICAgICAgPC9kaXY+CgogICAgICAgIDxBcHBGb290ZXIgLz4KCiAgICAgICAge3Nob3dSZWFkbWUgJiYgPFJlYWRtZU1vZGFsIG9uQ2xvc2U9eygpID0+IHNldFNob3dSZWFkbWUoZmFsc2UpfSAvPn0KICAgICAgPC9kaXY+CiAgICA8L1RvYXN0UHJvdmlkZXI+CiAgKTsKfQo= \ No newline at end of file