diff --git a/apps/web/app/admin/page.tsx b/apps/web/app/admin/page.tsx index 38c5ddc..8ac3308 100644 --- a/apps/web/app/admin/page.tsx +++ b/apps/web/app/admin/page.tsx @@ -195,32 +195,14 @@ export default function AdminDashboard() {
{theme === "dark" ? ( <> - + - NIGHT + NIGHT ) : ( <> - + @@ -231,7 +213,7 @@ export default function AdminDashboard() { - DAY + DAY )}
@@ -310,10 +292,10 @@ export default function AdminDashboard() { {totalPins}
- AWAITING ACTION + PENDING PINS {pendingPinCount} @@ -327,19 +309,19 @@ export default function AdminDashboard() { {globalVerificationRate}% -
-
+
+
@@ -724,7 +706,19 @@ export default function AdminDashboard() { setIsDeletingPin(true); }} > - DELETE + + + + )} @@ -921,15 +915,15 @@ export default function AdminDashboard() { style={{ borderColor: index === 0 - ? "var(--neon-yellow, #FFD700)" + ? "var(--neon-yellow)" : "var(--neon-blue)", color: index === 0 - ? "var(--neon-yellow, #FFD700)" + ? "var(--neon-yellow)" : "var(--neon-blue)", background: index === 0 - ? "color-mix(in srgb, var(--neon-yellow, #FFD700) 15%, transparent)" + ? "color-mix(in srgb, var(--neon-yellow) 15%, transparent)" : "color-mix(in srgb, var(--neon-blue) 15%, transparent)", }} > @@ -949,7 +943,7 @@ export default function AdminDashboard() { style={{ color: index === 0 - ? "var(--neon-yellow, #FFD700)" + ? "var(--neon-yellow)" : "var(--text-primary)", }} > @@ -1080,7 +1074,7 @@ export default function AdminDashboard() { width: 100%; background: transparent; border: 1px solid var(--border-color); - color: #ff4d4d; + color: var(--status-danger); padding: 12px; border-radius: 8px; font-family: var(--font-chakra); @@ -1091,9 +1085,9 @@ export default function AdminDashboard() { } .sign-out-btn:hover { - background: color-mix(in srgb, #ff4d4d 10%, transparent); - border-color: #ff4d4d; - } + background: color-mix(in srgb, var(--status-danger) 10%, transparent); + border-color: var(--status-danger); + } /* --- MAIN AREA --- */ .main-wrapper { @@ -1230,9 +1224,9 @@ export default function AdminDashboard() { } .status-badge { - background: color-mix(in srgb, var(--neon-green) 15%, transparent); - color: var(--neon-green); - border: 1px solid var(--neon-green); + background: color-mix(in srgb, var(--status-success) 15%, transparent); + color: var(--status-success); + border: 1px solid var(--status-success); padding: 4px 8px; border-radius: 4px; font-family: var(--font-chakra); @@ -1242,9 +1236,9 @@ export default function AdminDashboard() { } .count-badge { - background: color-mix(in srgb, var(--neon-yellow, #FFD700) 15%, transparent); - color: var(--neon-yellow, #FFD700); - border: 1px solid var(--neon-yellow, #FFD700); + background: color-mix(in srgb, var(--status-warning) 15%, transparent); + color: var(--status-warning); + border: 1px solid var(--status-warning); padding: 2px 8px; border-radius: 12px; font-family: var(--font-nunito); @@ -1280,7 +1274,7 @@ export default function AdminDashboard() { .pin-list-item { display: flex; align-items: center; justify-content: space-between; background: var(--bg-panel-hover); border: 1px solid var(--border-color); border-radius: 12px; padding: 12px 16px; transition: all 0.2s ease; } .pin-list-item:hover { border-color: color-mix(in srgb, var(--text-secondary) 50%, transparent); background: color-mix(in srgb, var(--bg-panel-hover) 80%, var(--border-color)); } .pin-info-group { display: flex; align-items: center; gap: 16px; } - .list-diamond { width: 32px; height: 32px; transform: rotate(45deg); border: 1.5px solid; display: flex; align-items: center; justify-content: center; flex-shrink: 0; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } + .list-diamond { width: 32px; height: 32px; transform: rotate(45deg); border: 1.5px solid; display: flex; align-items: center; justify-content: center; flex-shrink: 0; box-shadow: 0 4px 10px var(--border-color); } .list-diamond span { transform: rotate(-45deg); font-family: var(--font-cubao-wide); font-size: 14px; } .pin-text { display: flex; flex-direction: column; gap: 4px; } .pin-title { font-family: var(--font-chakra); font-size: 14px; font-weight: 700; color: var(--text-primary); letter-spacing: 0.05em; } @@ -1352,8 +1346,8 @@ export default function AdminDashboard() { .progress-fill { height: 100%; - background: var(--pin-food); - box-shadow: 0 0 10px color-mix(in srgb, var(--pin-food) 50%, transparent); + background: var(--status-success); + box-shadow: 0 0 10px color-mix(in srgb, var(--status-success) 50%, transparent); border-radius: 3px; transition: width 1s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @@ -1367,9 +1361,9 @@ export default function AdminDashboard() { letter-spacing: 0.05em; } - .detail-item.verified { color: var(--neon-green); } - .detail-item.pending { color: var(--neon-yellow, #FFD700); } - .detail-item.rejected { color: #ff4d4d; } + .detail-item.verified { color: var(--status-success); } + .detail-item.pending { color: var(--status-warning); } + .detail-item.rejected { color: var(--status-danger); } /* Category Distribution */ .distribution-section { @@ -1434,10 +1428,10 @@ export default function AdminDashboard() { } .approve-btn:hover { - background: color-mix(in srgb, var(--pin-food) 15%, transparent); - border-color: var(--pin-food); - color: var(--pin-food); - transform: scale(1.05); + background: color-mix(in srgb, var(--status-success) 15%, transparent); + border-color: var(--status-success); + color: var(--status-success); + transform: scale(1.05); } .approve-btn:active { @@ -1460,11 +1454,11 @@ export default function AdminDashboard() { } .reject-btn:hover { - background: color-mix(in srgb, #ff4d4d 15%, transparent); - border-color: #ff4d4d; - color: #ff4d4d; - transform: scale(1.05); - } + background: color-mix(in srgb, var(--status-danger) 15%, transparent); + border-color: var(--status-danger); + color: var(--status-danger); + transform: scale(1.05); + } .reject-btn:active { transform: scale(0.95); @@ -1594,7 +1588,7 @@ export default function AdminDashboard() { @media (max-width: 768px) { .sidebar { position: fixed; top: 0; left: 0; height: 100%; transform: translateX(-100%); } .sidebar.open { transform: translateX(0); } - .mobile-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); backdrop-filter: blur(4px); z-index: 99; } + .mobile-overlay { position: fixed; inset: 0; background: var(--border-color); backdrop-filter: blur(4px); z-index: 99; } .hamburger-btn { display: flex; align-items: center; justify-content: center; } .dashboard-header { padding: 0 16px; } .dashboard-grid { grid-template-columns: 1fr; } diff --git a/apps/web/app/dashboard/page.tsx b/apps/web/app/dashboard/page.tsx index e2ae445..44d6d64 100644 --- a/apps/web/app/dashboard/page.tsx +++ b/apps/web/app/dashboard/page.tsx @@ -118,11 +118,10 @@ export default function Dashboard() { className="nav-item" onClick={goToAdmin} style={{ - color: "#ff4d4d", - border: - "1px solid color-mix(in srgb, #ff4d4d 30%, transparent)", - background: "color-mix(in srgb, #ff4d4d 5%, transparent)", - }} + color: "var(--status-danger)", + border: "1px solid color-mix(in srgb, var(--status-danger) 30%, transparent)", + background: "color-mix(in srgb, var(--status-danger) 5%, transparent)", + }} >
- NIGHT + NIGHT ) : ( <> @@ -188,7 +187,7 @@ export default function Dashboard() { height="14" viewBox="0 0 24 24" fill="none" - stroke="var(--pin-transit)" + stroke="var(--theme-sun)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" @@ -203,7 +202,7 @@ export default function Dashboard() { - DAY + DAY )}
@@ -270,11 +269,10 @@ export default function Dashboard() { {data?.userRole === "admin" ? "ADMIN" : "REGULAR USER"} @@ -364,17 +362,6 @@ export default function Dashboard() {

YOUR STATISTICS

- - SUMMARIZED -
@@ -537,14 +524,7 @@ export default function Dashboard() {

YOUR RECENT PINS

- + {stats.recentList?.length}
@@ -730,7 +710,7 @@ export default function Dashboard() { width: 100%; background: transparent; border: 1px solid var(--border-color); - color: #ff4d4d; + color: var(--status-danger); padding: 12px; border-radius: 8px; font-family: var(--font-chakra); @@ -741,8 +721,8 @@ export default function Dashboard() { } .sign-out-btn:hover { - background: color-mix(in srgb, #ff4d4d 10%, transparent); - border-color: #ff4d4d; + background: color-mix(in srgb, var(--status-danger) 10%, transparent); + border-color: var(--status-danger); } /* --- MAIN AREA --- */ @@ -862,9 +842,9 @@ export default function Dashboard() { /* Badges */ .status-badge { - background: color-mix(in srgb, var(--neon-green) 15%, transparent); - color: var(--neon-green); - border: 1px solid var(--neon-green); + background: color-mix(in srgb, var(--status-success) 15%, transparent); + color: var(--status-success); + border: 1px solid var(--status-success); padding: 4px 8px; border-radius: 4px; font-family: var(--font-chakra); @@ -874,9 +854,9 @@ export default function Dashboard() { } .count-badge { - background: color-mix(in srgb, var(--neon-yellow, #FFD700) 15%, transparent); - color: var(--neon-yellow, #FFD700); - border: 1px solid var(--neon-yellow, #FFD700); + background: color-mix(in srgb, var(--status-warning) 15%, transparent); + color: var(--status-warning); + border: 1px solid var(--status-warning); padding: 2px 8px; border-radius: 12px; font-family: var(--font-nunito); @@ -1079,10 +1059,6 @@ export default function Dashboard() { font-size: 11px; } - @keyframes spin { - 100% { transform: rotate(360deg); } - } - /* --- TELEMETRY MODULE STYLES --- */ .telemetry-body { gap: 24px; @@ -1157,7 +1133,7 @@ export default function Dashboard() { align-items: center; justify-content: center; flex-shrink: 0; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 4px 10px var(--border-color); } .list-diamond span { @@ -1244,8 +1220,8 @@ export default function Dashboard() { .progress-fill { height: 100%; - background: var(--pin-food); - box-shadow: 0 0 10px color-mix(in srgb, var(--pin-food) 50%, transparent); + background: var(--status-success); + box-shadow: 0 0 10px color-mix(in srgb, var(--status-success) 50%, transparent); border-radius: 3px; transition: width 1s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @@ -1259,9 +1235,9 @@ export default function Dashboard() { letter-spacing: 0.05em; } - .detail-item.verified { color: var(--neon-green); } - .detail-item.pending { color: var(--neon-yellow, #FFD700); } - .detail-item.rejected { color: #ff4d4d; } + .detail-item.verified { color: var(--status-success); } + .detail-item.pending { color: var(--status-warning); } + .detail-item.rejected { color: var(--status-danger); } /* Category Distribution */ .distribution-section { @@ -1330,7 +1306,7 @@ export default function Dashboard() { .mobile-overlay { position: fixed; inset: 0; - background: rgba(0,0,0,0.6); + background: var(--border-color); backdrop-filter: blur(4px); z-index: 99; } diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index dd73ca8..3ebd735 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -1,26 +1,128 @@ @import "tailwindcss"; +@keyframes spin { + 100% { transform: rotate(360deg); } +} + +@keyframes slideUp { + from { + transform: translateY(100px); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes fadeUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes pulse { + 0% { + opacity: 1; + } + + 50% { + opacity: 0.4; + } + + 100% { + opacity: 1; + } +} + +@keyframes scrollText { + 0%, 20% { + transform: translateX(0); + } + 80%, 100% { + transform: translateX(min(0px, calc(-100% + 100cqw))); + } +} + +@keyframes extrudeRight { + from { opacity: 0; transform: translateX(-15px) scale(0.9); } + to { opacity: 1; transform: translateX(0) scale(1); } +} + +@keyframes pulseGlow { + 0% { box-shadow: 0 0 15px var(--shadow-glow), inset 0 0 10px var(--shadow-glow); } + 100% { box-shadow: 0 0 25px var(--shadow-glow), inset 0 0 15px var(--shadow-glow); } +} + +@keyframes radarPing { + 0% { + transform: scale(0.8); + opacity: 0.8; + } + 100% { + transform: scale(4.5); + opacity: 0; + } +} + +@keyframes slideRight { + from { transform: translateX(-100%); } + to { transform: translateX(0); } +} +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + :root { --bg-base: #f0f2f5; - --bg-panel: rgba(255, 255, 255, 0.9); + --bg-panel: rgba(255, 255, 255, 0.95); --bg-panel-hover: rgba(0, 0, 0, 0.05); --text-primary: #121212; --text-secondary: #555555; - --border-color: rgba(0, 0, 0, 0.15); + --border-color: rgba(0, 0, 0, 0.2); --shadow-glow: rgba(0, 136, 255, 0.2); - --pin-academic: #d91a4d; - --pin-food: #00995c; - --pin-social: #8e00e6; - --pin-transit: #d98200; - --pin-utility: #0088cc; + --pin-academic: #d91a4d; + --pin-food: #00995c; + --pin-social: #8e00e6; + --pin-transit: #d98200; + --pin-utility: #0088cc; + + --neon-blue: #0066cc; + --neon-red: #d90040; + --neon-yellow: #d4a017; + --theme-sun: #d98200; + --theme-moon: #8899a6; + + --status-success: #008844; + --status-warning: #d98200; + --status-danger: #cc0000; } .dark { --bg-base: #0f1115; - --bg-panel: rgba(10, 10, 12, 0.85); + --bg-panel: rgba(10, 10, 12, 0.95); --bg-panel-hover: rgba(255, 255, 255, 0.1); --text-primary: #ffffff; @@ -29,11 +131,21 @@ --border-color: rgba(255, 255, 255, 0.15); --shadow-glow: rgba(0, 229, 255, 0.2); - --pin-academic: #ff3366; - --pin-food: #00ff99; - --pin-social: #b026ff; - --pin-transit: #ffd700; - --pin-utility: #00e5ff; + --pin-academic: #ff3366; + --pin-food: #00ff99; + --pin-social: #b026ff; + --pin-transit: #ffd700; + --pin-utility: #00e5ff; + + --neon-blue: #00e5ff; + --neon-red: #ff0055; + --neon-yellow: #ffd700; + --theme-sun: #ffd700; + --theme-moon: #ffffff; + + --status-success: #00ff99; + --status-warning: #ffcc00; + --status-danger: #ff4d4d; } body { @@ -375,41 +487,3 @@ p { margin-top: 0; } } - -@keyframes slideUp { - from { - transform: translateY(100px); - opacity: 0; - } - - to { - transform: translateY(0); - opacity: 1; - } -} - -@keyframes fadeIn { - from { - opacity: 0; - transform: scale(0.95); - } - - to { - opacity: 1; - transform: scale(1); - } -} - -@keyframes pulse { - 0% { - opacity: 1; - } - - 50% { - opacity: 0.4; - } - - 100% { - opacity: 1; - } -} diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 03bb4ac..f93d841 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -222,7 +222,7 @@ export default function Home() { )} @@ -232,7 +232,7 @@ export default function Home() { const categoryDef = ZONE_CATEGORIES.find( (c) => c.id === zone.categoryId, ); - const zoneColor = categoryDef ? categoryDef.color : "#FFFFFF"; + const zoneColor = categoryDef ? categoryDef.color : "var(--bg-panel)"; return ( diff --git a/apps/web/app/sign-in/page.tsx b/apps/web/app/sign-in/page.tsx index 048bfbb..0441d2a 100644 --- a/apps/web/app/sign-in/page.tsx +++ b/apps/web/app/sign-in/page.tsx @@ -260,17 +260,6 @@ export default function SignIn() { .footer-text a { color: #555; } - - @keyframes fadeUp { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } - } `} ); diff --git a/apps/web/components/AddPinModal.tsx b/apps/web/components/AddPinModal.tsx index e0e3c49..d6feee1 100644 --- a/apps/web/components/AddPinModal.tsx +++ b/apps/web/components/AddPinModal.tsx @@ -95,7 +95,7 @@ export function AddPinModal({ coords, onSave, onCancel }: AddPinModalProps) { height="24" viewBox="0 0 24 24" fill="none" - stroke="var(--neon-blue, #00E5FF)" + stroke="var(--neon-blue)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" @@ -192,7 +192,7 @@ export function AddPinModal({ coords, onSave, onCancel }: AddPinModalProps) { .modal-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; - background: rgba(0, 0, 0, 0.7); + background: var(--border-color); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); display: flex; @@ -241,7 +241,7 @@ export function AddPinModal({ coords, onSave, onCancel }: AddPinModalProps) { .input-group span { font-family: var(--font-chakra), sans-serif; font-size: 12px; - color: var(--neon-blue, #00E5FF); + color: var(--neon-blue); letter-spacing: 0.1em; font-weight: 700; } @@ -259,7 +259,7 @@ export function AddPinModal({ coords, onSave, onCancel }: AddPinModalProps) { } input:focus, textarea:focus { - border-color: var(--neon-blue, #00E5FF); + border-color: var(--neon-blue); box-shadow: 0 0 10px var(--shadow-glow); } @@ -303,11 +303,6 @@ export function AddPinModal({ coords, onSave, onCancel }: AddPinModalProps) { opacity: 0.5; cursor: not-allowed; } - - @keyframes slideUp { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } - } `}
); diff --git a/apps/web/components/EditPinModal.tsx b/apps/web/components/EditPinModal.tsx index c449486..e180c47 100644 --- a/apps/web/components/EditPinModal.tsx +++ b/apps/web/components/EditPinModal.tsx @@ -106,7 +106,7 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { height="24" viewBox="0 0 24 24" fill="none" - stroke="var(--neon-blue, #00E5FF)" + stroke="var(--neon-blue)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" @@ -199,7 +199,7 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { .modal-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; - background: rgba(0, 0, 0, 0.7); + background: var(--border-color); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); display: flex; @@ -210,11 +210,13 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { } .modal-card { + background: var(--bg-base); + border: 1px solid var(--border-color); + border-radius: 12px; width: 100%; max-width: 400px; padding: 24px; animation: slideUp 0.3s cubic-bezier(0.16, 1, 0.3, 1); - background-color: black; } .modal-header { @@ -249,7 +251,7 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { .input-group span { font-family: var(--font-chakra), sans-serif; font-size: 12px; - color: var(--neon-blue, #00E5FF); + color: var(--neon-blue); letter-spacing: 0.1em; font-weight: 700; } @@ -267,7 +269,7 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { } input:focus, textarea:focus { - border-color: var(--neon-blue, #00E5FF); + border-color: var(--neon-blue); box-shadow: 0 0 10px var(--shadow-glow); } @@ -311,11 +313,6 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { opacity: 0.5; cursor: not-allowed; } - - @keyframes slideUp { - from { opacity: 0; transform: translateY(20px) scale(0.95); } - to { opacity: 1; transform: translateY(0) scale(1); } - } `}
); diff --git a/apps/web/components/ExpandedPinView.tsx b/apps/web/components/ExpandedPinView.tsx index 317d090..8de668f 100644 --- a/apps/web/components/ExpandedPinView.tsx +++ b/apps/web/components/ExpandedPinView.tsx @@ -148,7 +148,7 @@ const CommentNode = ({ font-size: 13px; outline: none; } - .reply-input:focus { border-color: var(--neon-blue, #00E5FF); } + .reply-input:focus { border-color: var(--neon-blue); } .form-btn { padding: 6px 12px; font-size: 11px; border-radius: 6px; } `}
@@ -201,7 +201,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { case "VERIFIED": return { text: "VERIFIED", - // color: "var(--neon-green, #00FF99)", + // color: "var(--status-success)", icon: ( {` .modal-overlay { position: fixed; inset: 0; - background: rgba(0, 0, 0, 0.7); backdrop-filter: blur(8px); + background: var(--border-color); backdrop-filter: blur(8px); z-index: 200; display: flex; align-items: center; justify-content: center; padding: 24px; animation: fadeIn 0.2s ease-out; pointer-events: auto; } .modal-content { - background: var(--bg-panel); + background: var(--bg-base); border: 1px solid var(--border-color); border-top: 4px solid ${color}; border-radius: 24px; @@ -319,7 +319,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { height: 70vh; display: flex; flex-direction: column; - box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3); + box-shadow: 0 30px 60px var(--border-color); animation: scalePop 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); overflow: hidden; position: relative; @@ -445,7 +445,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { {/* PIN ID */}
PIN ID - + {pin?.id?.padStart(7, "0")}
@@ -590,7 +590,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { .modal-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; - background: rgba(0, 0, 0, 0.7); + background: var(--border-color); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); display: flex; @@ -610,7 +610,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { height: 70vh; display: flex; flex-direction: column; - box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3); + box-shadow: 0 30px 60px var(--border-color); overflow: hidden; position: relative; padding: 0; @@ -730,8 +730,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { gap: 4px; min-width: 0; /* 1. Turn the container into a measurable query zone */ - container-type: inline-size; - /* 2. Hide the overflow from bleeding into other columns */ + container-type: inline-size; overflow: hidden; } @@ -745,17 +744,10 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { color: var(--text-primary); white-space: nowrap; width: max-content; - animation: autoPan 6s ease-in-out infinite alternate; - } - - .meta-value { - font-family: var(--font-nunito); - font-size: 14px; - font-weight: 700; - color: var(--text-primary); - white-space: nowrap; - overflow-x: auto; - scrollbar-width: none; /* Firefox */ + background-size: 200% 200%; + animation: scrollText 6s ease-in-out infinite alternate; + scrollbar-width: none; /* Firefox */ + overflow: hidden; } .meta-value::-webkit-scrollbar { display: none; /* Safari and Chrome */ @@ -771,14 +763,14 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { .font-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; letter-spacing: 0.05em; } .font-cubao-wide { font-family: var(--font-cubao-wide); font-weight: 100; letter-spacing: 0.1em;} .text-muted { color: var(--text-secondary); font-style: italic; } - .text-neon-green { color: var(--neon-green, #00FF99); text-shadow: 0 0 10px rgba(0, 255, 153, 0.3); } + .text-neon-green { color: var(--status-success); text-shadow: 0 0 10px var(--status-success); } - .danger-btn { border-color: #ff4d4d; color: #ff4d4d; padding: 12px; } - .danger-btn:hover { background: rgba(255, 77, 77, 0.1); transform: none;} + .danger-btn { border-color: var(--status-danger); color: var(--status-danger); padding: 12px; } + .danger-btn:hover { background: var(--status-danger); color: white; transform: none;} .delete-confirm-box { - background: rgba(255, 77, 77, 0.05); - border: 1px solid #ff4d4d; + background: var(--bg-panel-hover); + border: 1px solid var(--status-danger); border-radius: 12px; padding: 16px; display: flex; @@ -787,8 +779,8 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { } .delete-confirm-box p { margin: 0; color: var(--text-primary); font-family: var(--font-nunito); font-size: 14px; } .delete-actions { display: flex; gap: 8px; } - .danger-btn-solid { background: rgba(255, 77, 77, 0.2); border-color: #ff4d4d; color: #ff4d4d; box-shadow: none; flex: 1; padding: 10px;} - .danger-btn-solid:hover { background: #ff4d4d; color: white; box-shadow: 0 0 15px rgba(255, 77, 77, 0.4); } + .danger-btn-solid { background: var(--status-danger); border-color: var(--status-danger); color: white; box-shadow: none; flex: 1; padding: 10px;} + .danger-btn-solid:hover { background: var(--status-danger); color: white; box-shadow: 0 0 15px var(--status-danger);} .forum-section { margin-top: 8px; @@ -814,19 +806,8 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { border-radius: 6px; padding: 10px 12px; color: var(--text-primary); font-family: var(--font-nunito); font-size: 13px; outline: none; } - .reply-input:focus { border-color: var(--neon-blue, #00E5FF); } + .reply-input:focus { border-color: var(--neon-blue); } .form-btn { padding: 10px 16px; font-size: 11px; border-radius: 6px; } - - @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } - @keyframes scalePop { from { opacity: 0; transform: scale(0.95) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } } - @keyframes autoPan { - 0%, 20% { - transform: translateX(0); - } - 80%, 100% { - transform: translateX(min(0px, calc(100cqw - 100%))); - } - } `} ); diff --git a/apps/web/components/HeadsUpDisplay.tsx b/apps/web/components/HeadsUpDisplay.tsx index a73aede..cebbfb1 100644 --- a/apps/web/components/HeadsUpDisplay.tsx +++ b/apps/web/components/HeadsUpDisplay.tsx @@ -133,10 +133,7 @@ export function HeadsUpDisplay({ transform: scale(0.95); } - @keyframes pulseGlow { - 0% { box-shadow: 0 0 15px var(--shadow-glow), inset 0 0 10px var(--shadow-glow); } - 100% { box-shadow: 0 0 25px var(--shadow-glow), inset 0 0 15px var(--shadow-glow); } - } + `} ); diff --git a/apps/web/components/MapCursor.tsx b/apps/web/components/MapCursor.tsx index 2cad9e4..db2d3ad 100644 --- a/apps/web/components/MapCursor.tsx +++ b/apps/web/components/MapCursor.tsx @@ -16,13 +16,13 @@ export function MapCursor({ heading = 0 }: MapCursorProps) { height="24" viewBox="0 0 24 24" fill="none" - stroke="var(--neon-blue, #00E5FF)" + stroke="var(--neon-blue)" strokeWidth="2" strokeLinejoin="round" > @@ -50,7 +50,7 @@ export function MapCursor({ heading = 0 }: MapCursorProps) { width: 100%; height: 100%; background: transparent; - border: 1.5px solid var(--neon-blue, #00E5FF); + border: 1.5px solid var(--neon-blue); border-radius: 50%; opacity: 0; /* Hidden until animation starts */ animation: radarPing 2.5s cubic-bezier(0.215, 0.61, 0.355, 1) infinite; @@ -60,16 +60,7 @@ export function MapCursor({ heading = 0 }: MapCursorProps) { .pulse-ring.delay-1 { animation-delay: 0s; } .pulse-ring.delay-2 { animation-delay: 1.25s; } - @keyframes radarPing { - 0% { - transform: scale(0.8); - opacity: 0.8; - } - 100% { - transform: scale(4.5); - opacity: 0; - } - } + `} ); diff --git a/apps/web/components/PinDetailsCard.tsx b/apps/web/components/PinDetailsCard.tsx index a4e6e9e..56c5ddb 100644 --- a/apps/web/components/PinDetailsCard.tsx +++ b/apps/web/components/PinDetailsCard.tsx @@ -9,7 +9,7 @@ const detailsCardStyles = ` p-[24px] w-full max-w-[400px] flex flex-col gap-[16px] bg-[var(--bg-panel)] backdrop-filter-[blur(20px)] border border-solid border-[1px] border-[var(--border-color)] border-t-[3px] rounded-[20px] - shadow-[0_20px_40px_rgba(0, 0, 0, 0.3)] + shadow-[0_20px_40px_[var(--border-color)]] `; interface PinDetailsCardProps { diff --git a/apps/web/components/Polygon.tsx b/apps/web/components/Polygon.tsx index 8a8fd3d..2c56b69 100644 --- a/apps/web/components/Polygon.tsx +++ b/apps/web/components/Polygon.tsx @@ -16,9 +16,9 @@ interface PolygonProps { export function Polygon({ paths, - fillColor = "#00FF99", + fillColor = "var(--neon-green)", fillOpacity = 0.05, - strokeColor = "#00FF99", + strokeColor = "var(--neon-green)", strokeOpacity = 0.8, strokeWeight = 2, zIndex = 1, diff --git a/apps/web/components/Polyline.tsx b/apps/web/components/Polyline.tsx index 6f9756f..cacc6bd 100644 --- a/apps/web/components/Polyline.tsx +++ b/apps/web/components/Polyline.tsx @@ -13,7 +13,7 @@ interface PolylineProps { export function Polyline({ path, - color = "#FFD700", + color = "var(--pin-transit)", weight = 5, animateDirection = "forward", speed = 0.8 diff --git a/apps/web/components/Sidebar.tsx b/apps/web/components/Sidebar.tsx index 77c63f8..566252f 100644 --- a/apps/web/components/Sidebar.tsx +++ b/apps/web/components/Sidebar.tsx @@ -78,7 +78,7 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { .sidebar-overlay { position: fixed; inset: 0; - background: rgba(0, 0, 0, 0.6); + background: var(--border-color); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); z-index: 400; @@ -97,7 +97,7 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { z-index: 401; display: flex; flex-direction: column; - box-shadow: 20px 0 50px rgba(0,0,0,0.1); + box-shadow: 20px 0 50px var(--border-color); animation: slideRight 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); } @@ -165,7 +165,7 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { } .primary-action { - background: rgba(0, 229, 255, 0.1); + background: var(--bg-panel); border-color: var(--neon-blue); color: var(--neon-blue); } @@ -188,14 +188,7 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { letter-spacing: 0.1em; } - @keyframes slideRight { - from { transform: translateX(-100%); } - to { transform: translateX(0); } - } - @keyframes fadeIn { - from { opacity: 0; } - to { opacity: 1; } - } + `} ); diff --git a/apps/web/components/TargetLine.tsx b/apps/web/components/TargetLine.tsx index 63da668..ca47e7f 100644 --- a/apps/web/components/TargetLine.tsx +++ b/apps/web/components/TargetLine.tsx @@ -9,7 +9,7 @@ interface TargetLineProps { color?: string; } -export function TargetLine({ start, end, color = "#FF0055" }: TargetLineProps) { +export function TargetLine({ start, end, color = "var(--neon-blue)" }: TargetLineProps) { const map = useMap(); const polylineRef = useRef(null); const animationRef = useRef(0); diff --git a/apps/web/components/TopBar.tsx b/apps/web/components/TopBar.tsx index af610fa..b25554e 100644 --- a/apps/web/components/TopBar.tsx +++ b/apps/web/components/TopBar.tsx @@ -158,7 +158,7 @@ export function TopBar({ backgroundColor: isActive ? `${route.color}20` : "var(--bg-panel-hover)", - color: isActive ? route.color : "#aaa", + color: isActive ? route.color : "var(--text-secondary)", borderColor: isActive ? route.color : "transparent", boxShadow: isActive ? `0 0 10px ${route.color}40` @@ -212,7 +212,7 @@ export function TopBar({ backgroundColor: isActive ? `${category.color}20` : "var(--bg-panel-hover)", - color: isActive ? category.color : "#aaa", + color: isActive ? category.color : "var(--text-secondary)", borderColor: isActive ? category.color : "transparent", boxShadow: isActive ? `0 0 10px ${category.color}40` @@ -296,7 +296,7 @@ export function TopBar({ fill="none" stroke={ sessionData?.user - ? "var(--neon-green, #00FF99)" + ? "var(--status-success)" : "currentColor" } strokeWidth="2.5" @@ -316,7 +316,7 @@ export function TopBar({ height="20" viewBox="0 0 24 24" fill="none" - stroke="currentColor" + stroke="var(--theme-moon)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" @@ -329,7 +329,7 @@ export function TopBar({ height="20" viewBox="0 0 24 24" fill="none" - stroke="currentColor" + stroke="var(--theme-sun)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" diff --git a/package-lock.json b/package-lock.json index e64d7c2..86295f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,14 @@ "name": "UPWayPoint", "dependencies": { "@hookform/resolvers": "^5.2.2", + "clsx": "^2.1.1", + "tailwind-merge": "^3.5.0", "zod": "^4.3.6" }, "devDependencies": { "@biomejs/biome": "2.3.14", + "@tailwindcss/postcss": "^4.2.2", + "postcss": "^8.5.8", "prettier": "^3.7.4", "turbo": "^2.8.0", "typescript": "5.9.2" @@ -19,6 +23,19 @@ "node": ">=18" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@biomejs/biome": { "version": "2.3.14", "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.14.tgz", @@ -194,12 +211,709 @@ "react-hook-form": "^7.55.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@standard-schema/utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@tailwindcss/node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", + "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", + "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-arm64": "4.2.2", + "@tailwindcss/oxide-darwin-x64": "4.2.2", + "@tailwindcss/oxide-freebsd-x64": "4.2.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", + "@tailwindcss/oxide-linux-x64-musl": "4.2.2", + "@tailwindcss/oxide-wasm32-wasi": "4.2.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", + "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", + "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", + "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", + "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", + "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", + "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", + "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", + "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", + "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", + "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", + "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", + "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz", + "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.2.2", + "@tailwindcss/oxide": "4.2.2", + "postcss": "^8.5.6", + "tailwindcss": "4.2.2" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/prettier": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", @@ -243,6 +957,47 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", + "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz", + "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/turbo": { "version": "2.8.10", "resolved": "https://registry.npmjs.org/turbo/-/turbo-2.8.10.tgz", diff --git a/package.json b/package.json index e87d02a..326a8c3 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ }, "devDependencies": { "@biomejs/biome": "2.3.14", + "@tailwindcss/postcss": "^4.2.2", + "postcss": "^8.5.8", "prettier": "^3.7.4", "turbo": "^2.8.0", "typescript": "5.9.2" @@ -24,6 +26,8 @@ }, "dependencies": { "@hookform/resolvers": "^5.2.2", + "clsx": "^2.1.1", + "tailwind-merge": "^3.5.0", "zod": "^4.3.6" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 881de43..6dedd9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@hookform/resolvers': specifier: ^5.2.2 version: 5.2.2(react-hook-form@7.71.2(react@19.2.0)) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 zod: specifier: ^4.3.6 version: 4.3.6 @@ -18,6 +24,12 @@ importers: '@biomejs/biome': specifier: 2.3.14 version: 2.3.14 + '@tailwindcss/postcss': + specifier: ^4.2.2 + version: 4.2.2 + postcss: + specifier: ^8.5.8 + version: 8.5.8 prettier: specifier: ^3.7.4 version: 3.7.4 @@ -2956,10 +2968,6 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} @@ -6125,12 +6133,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.5.8: dependencies: nanoid: 3.3.11 @@ -6560,7 +6562,7 @@ snapshots: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.6 + postcss: 8.5.8 rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: