diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index ae7505b..bdec6bc 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -4,7 +4,7 @@ name: API Tests on Supabase DB on: workflow_dispatch: - branches: [ "main" ] + branches: ["main"] permissions: contents: read @@ -13,7 +13,7 @@ permissions: jobs: api-tests: runs-on: ubuntu-latest - + env: # makes env vars available to all steps DATABASE_URL: ${{ secrets.DATABASE_URL }} @@ -32,11 +32,9 @@ jobs: node-version: ${{ matrix.node-version }} - run: pnpm install --frozen-lockfile - - name: Create .env for db package run: echo "DATABASE_URL=${DATABASE_URL}" > packages/db/.env - name: Create .env for api package run: echo "DATABASE_URL=${DATABASE_URL}" > packages/api/.env - - run: pnpm run test:api diff --git a/.github/workflows/check-types.yml b/.github/workflows/check-types.yml index 1a981d6..459ee24 100644 --- a/.github/workflows/check-types.yml +++ b/.github/workflows/check-types.yml @@ -4,11 +4,11 @@ name: Type Checking on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] workflow_dispatch: - branches: [ "main" ] + branches: ["main"] permissions: contents: read diff --git a/apps/docs/app/page.module.css b/apps/docs/app/page.module.css index 6108b60..e769a99 100644 --- a/apps/docs/app/page.module.css +++ b/apps/docs/app/page.module.css @@ -68,7 +68,10 @@ padding: 0 20px; font-family: var(--font-geist-sans); border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; cursor: pointer; display: flex; align-items: center; @@ -96,7 +99,10 @@ button.secondary { padding: 0 20px; font-family: var(--font-geist-sans); border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; cursor: pointer; display: flex; align-items: center; diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 7aef056..aaaa7ac 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -14,7 +14,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css index a259478..b0f7fbf 100644 --- a/apps/web/app/globals.css +++ b/apps/web/app/globals.css @@ -47,91 +47,113 @@ } @keyframes spin { - 100% { transform: rotate(360deg); } + 100% { + transform: rotate(360deg); + } } @keyframes slideUp { - from { - transform: translateY(100px); - opacity: 0; - } - - to { - transform: translateY(0); - opacity: 1; - } + 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); - } + 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); - } + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } } @keyframes pulse { - 0% { - opacity: 1; - } + 0% { + opacity: 1; + } - 50% { - opacity: 0.4; - } + 50% { + opacity: 0.4; + } - 100% { - opacity: 1; - } + 100% { + opacity: 1; + } } @keyframes scrollText { - 0%, 20% { - transform: translateX(0); - } - 80%, 100% { - transform: translateX(min(0px, calc(-100% + 100cqw))); - } + 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); } + 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); } + 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; - } + 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); } + from { + transform: translateX(-100%); + } + to { + transform: translateX(0); + } } @theme { @@ -144,15 +166,15 @@ --color-base: var(--bg-base); --color-panel: var(--bg-panel); --color-panel-hover: var(--bg-panel-hover); - + --color-primary: var(--text-primary); --color-secondary: var(--text-secondary); --color-border-color: var(--border-color); - + --color-neon-blue: var(--neon-blue); --color-neon-red: var(--neon-red); --color-neon-yellow: var(--neon-yellow); - + --color-status-success: var(--status-success); --color-status-warning: var(--status-warning); --color-status-danger: var(--status-danger); @@ -168,7 +190,8 @@ --animate-pan: autoPan 20s linear infinite; --animate-scroll-text: scrollText 5s ease-in-out infinite alternate; - --animate-slide-up: slideUp 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; + --animate-slide-up: slideUp 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) + forwards; --animate-fade-in: fadeIn 0.2s ease-out forwards; --animate-fade-up: fadeUp 0.3s ease-out forwards; --animate-pulse-glow: pulseGlow 2s infinite alternate; @@ -178,71 +201,71 @@ } body { - background-color: var(--bg-base); - color: var(--text-primary); - transition: - background-color 0.3s ease, - color 0.3s ease; - margin: 0; - padding: 0; - overflow: hidden; - font-family: var(--font-chakra), sans-serif; + background-color: var(--bg-base); + color: var(--text-primary); + transition: + background-color 0.3s ease, + color 0.3s ease; + margin: 0; + padding: 0; + overflow: hidden; + font-family: var(--font-chakra), sans-serif; } p { - font-family: var(--font-nunito), sans-serif; + font-family: var(--font-nunito), sans-serif; } .map-container { - width: 100vw; - height: 100vh; - position: absolute; - top: 0; - left: 0; - z-index: 0; + width: 100vw; + height: 100vh; + position: absolute; + top: 0; + left: 0; + z-index: 0; } .tactical-panel { - @apply bg-panel backdrop-blur-md border border-border-color rounded-2xl text-primary shadow-[0_8px_32px_rgba(0,0,0,0.15)] transition-colors duration-300; + @apply bg-panel backdrop-blur-md border border-border-color rounded-2xl text-primary shadow-[0_8px_32px_rgba(0,0,0,0.15)] transition-colors duration-300; } .tactical-button { - @apply bg-panel border border-border-color text-primary rounded-lg font-chakra font-semibold cursor-pointer transition-all duration-200 hover:bg-panel-hover hover:-translate-y-[2px] active:translate-y-[1px]; + @apply bg-panel border border-border-color text-primary rounded-lg font-chakra font-semibold cursor-pointer transition-all duration-200 hover:bg-panel-hover hover:-translate-y-[2px] active:translate-y-[1px]; } .tactical-button:hover { - background: var(--bg-panel-hover); - transform: translateY(-2px); + background: var(--bg-panel-hover); + transform: translateY(-2px); } .tactical-button:active { - transform: translateY(1px); + transform: translateY(1px); } .tactical-button-primary { - @apply bg-neon-blue/15 border border-neon-blue text-neon-blue shadow-[0_0_10px_var(--shadow-glow)] rounded-lg font-chakra font-semibold cursor-pointer transition-all duration-200 hover:bg-neon-blue hover:text-base hover:shadow-[0_0_20px_var(--color-neon-blue)] active:translate-y-[1px]; + @apply bg-neon-blue/15 border border-neon-blue text-neon-blue shadow-[0_0_10px_var(--shadow-glow)] rounded-lg font-chakra font-semibold cursor-pointer transition-all duration-200 hover:bg-neon-blue hover:text-base hover:shadow-[0_0_20px_var(--color-neon-blue)] active:translate-y-[1px]; } .tactical-button-primary:hover { - background: var(--neon-blue); - color: var(--bg-base); - box-shadow: 0 0 20px var(--neon-blue); + background: var(--neon-blue); + color: var(--bg-base); + box-shadow: 0 0 20px var(--neon-blue); } .no-scrollbar::-webkit-scrollbar { - display: none; + display: none; } .icon-button, .control-button { - @apply w-11 h-11 bg-panel backdrop-blur-md border border-border-color rounded-xl text-primary flex items-center justify-center cursor-pointer transition-transform duration-100 font-chakra active:scale-95; + @apply w-11 h-11 bg-panel backdrop-blur-md border border-border-color rounded-xl text-primary flex items-center justify-center cursor-pointer transition-transform duration-100 font-chakra active:scale-95; } .icon-button:active, .control-button:active { - transform: scale(0.92); + transform: scale(0.92); } .control-button { - @apply border-none rounded-none; -} \ No newline at end of file + @apply border-none rounded-none; +} diff --git a/apps/web/app/page.module.css b/apps/web/app/page.module.css index 6108b60..e769a99 100644 --- a/apps/web/app/page.module.css +++ b/apps/web/app/page.module.css @@ -68,7 +68,10 @@ padding: 0 20px; font-family: var(--font-geist-sans); border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; cursor: pointer; display: flex; align-items: center; @@ -96,7 +99,10 @@ button.secondary { padding: 0 20px; font-family: var(--font-geist-sans); border: 1px solid transparent; - transition: background 0.2s, color 0.2s, border-color 0.2s; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; cursor: pointer; display: flex; align-items: center; diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index 54cc4b7..38736d6 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -215,7 +215,7 @@ export default function Home() { )} diff --git a/apps/web/components/EditPinModal.tsx b/apps/web/components/EditPinModal.tsx index d2842e7..3e3ed4e 100644 --- a/apps/web/components/EditPinModal.tsx +++ b/apps/web/components/EditPinModal.tsx @@ -98,7 +98,7 @@ export function EditPinModal({ onSave, onCancel, pin }: IEditPinModalProps) { }, [formMethods, pin.description, pin.pinTags, pin.title]); return ( -
+
- - +
+ + +
)}
@@ -279,7 +281,7 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { // biome-ignore lint/a11y/noStaticElementInteractions: // biome-ignore lint/a11y/useKeyWithClickEvents:
{/** biome-ignore lint/a11y/noStaticElementInteractions: */} @@ -527,26 +529,28 @@ export function ExpandedPinView({ pinId, onClose }: ExpandedPinViewProps) { ) : (
- - +
+ + +
)}
diff --git a/apps/web/components/HeadsUpDisplay.tsx b/apps/web/components/HeadsUpDisplay.tsx index 136007d..fc6ac9b 100644 --- a/apps/web/components/HeadsUpDisplay.tsx +++ b/apps/web/components/HeadsUpDisplay.tsx @@ -26,7 +26,7 @@ export function HeadsUpDisplay({ const isLoggedIn = useMemo(() => !!sessionData?.user?.id, [sessionData]); return ( -
+
{/* BOTTOM SECTION */}
{/* ADD PIN BUTTON (Only if NO pin is selected AND we are logged in) */} diff --git a/apps/web/components/PinDetailsCard.tsx b/apps/web/components/PinDetailsCard.tsx index 2916deb..59f92de 100644 --- a/apps/web/components/PinDetailsCard.tsx +++ b/apps/web/components/PinDetailsCard.tsx @@ -43,7 +43,7 @@ export function PinDetailsCard({ return (
{/* HEADER */} @@ -108,7 +108,7 @@ export function PinDetailsCard({ )} onClick={onLockClick} > - {isLocked ? "TARGET LOCKED" : "LOCK TARGET"} + {isLocked ? "NAVIGATING..." : "NAVIGATE"}
diff --git a/apps/web/components/TargetLine.tsx b/apps/web/components/TargetLine.tsx index 351d775..e07b36f 100644 --- a/apps/web/components/TargetLine.tsx +++ b/apps/web/components/TargetLine.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useRef } from "react"; +import { useEffect, useState, useRef } from "react"; import { useMap } from "@vis.gl/react-google-maps"; interface TargetLineProps { @@ -12,20 +12,29 @@ interface TargetLineProps { export function TargetLine({ start, end, - color = "var(--neon-blue)", + color = "--neon-blue", }: TargetLineProps) { const map = useMap(); const polylineRef = useRef(null); const animationRef = useRef(0); + const [resolvedColor, setResolvedColor] = useState("#00e5ff"); useEffect(() => { if (!map || !window.google) return; + const element = document.documentElement; + const styles = getComputedStyle(element); + const hexCode = styles.getPropertyValue(color).trim(); + + if (hexCode) { + setResolvedColor(hexCode); + } + const lineSymbol = { path: "M 0,-1 0,1", strokeOpacity: 1, scale: 3, - strokeColor: color, + strokeColor: resolvedColor, }; const polyline = new window.google.maps.Polyline({ @@ -64,7 +73,7 @@ export function TargetLine({ polylineRef.current.setMap(null); } }; - }, [map, start, end, color]); + }, [map, start, end, color, resolvedColor]); return null; } diff --git a/apps/web/components/TopBar.tsx b/apps/web/components/TopBar.tsx index 485134f..c32a5e4 100644 --- a/apps/web/components/TopBar.tsx +++ b/apps/web/components/TopBar.tsx @@ -84,7 +84,7 @@ export function TopBar({ ]; return ( -
+
{/* === LEFT ZONE === */}
{/* === CENTER ZONE (Search + Filters) === */} -
-
+
+
-
+
{filters.map((filter) => { const color = getPinColor(filter); const isActive = activeFilter === filter; @@ -289,10 +296,17 @@ export function TopBar({ {/* === RIGHT ZONE (Full Height Tool Stack) === */}
{/* Top Group */} -
+