diff --git a/client/src/App.jsx b/client/src/App.jsx index df8dadf..b3645c2 100755 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1 +1,76 @@ -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 +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)} />} +
+
+ ); +}