From 9acde36f50a3487cb66f2b6044d9e588223ff678 Mon Sep 17 00:00:00 2001 From: Brian McGonagill Date: Thu, 19 Mar 2026 06:10:30 -0500 Subject: [PATCH] Updated the styles to use Pico-css --- backend/prisma/schema.prisma | 1 + backend/src/routes/games.ts | 50 ++++ frontend/index.html | 3 +- frontend/src/pages/CreateGamePage.vue | 199 +++---------- frontend/src/pages/DashboardPage.vue | 213 ++++---------- frontend/src/pages/EditGamePage.vue | 235 ++++----------- frontend/src/pages/GameLivePage.vue | 272 +++++------------ frontend/src/pages/GamePage.vue | 369 +++++++++--------------- frontend/src/pages/HomePage.vue | 164 +++-------- frontend/src/pages/InvitePage.vue | 130 ++------- frontend/src/pages/JoinGamePage.vue | 167 +++-------- frontend/src/pages/LoginPage.vue | 126 ++------ frontend/src/pages/PlayGamePage.vue | 242 ++++------------ frontend/src/pages/RegisterPage.vue | 144 +++------ frontend/src/pages/SpectateGamePage.vue | 205 ++++--------- frontend/src/services/api.ts | 6 +- frontend/src/style.css | 289 ------------------- frontend/src/types/index.ts | 2 +- 18 files changed, 691 insertions(+), 2126 deletions(-) diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index d8ebfb8..4ed3053 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -119,6 +119,7 @@ enum GameStatus { DRAFT LIVE ENDED + ARCHIVED } enum TeamStatus { diff --git a/backend/src/routes/games.ts b/backend/src/routes/games.ts index 97c48a7..3455f7b 100644 --- a/backend/src/routes/games.ts +++ b/backend/src/routes/games.ts @@ -251,6 +251,56 @@ router.post('/:id/end', authenticate, async (req: AuthRequest, res: Response) => } }); +router.post('/:id/archive', authenticate, async (req: AuthRequest, res: Response) => { + try { + const id = req.params.id as string; + + const game = await prisma.game.findUnique({ where: { id } }); + if (!game) { + return res.status(404).json({ error: 'Game not found' }); + } + + if (game.gameMasterId !== req.user!.id) { + return res.status(403).json({ error: 'Not authorized' }); + } + + const updated = await prisma.game.update({ + where: { id }, + data: { status: 'ARCHIVED' } + }); + + res.json(updated); + } catch (error) { + console.error('Archive game error:', error); + res.status(500).json({ error: 'Failed to archive game' }); + } +}); + +router.post('/:id/unarchive', authenticate, async (req: AuthRequest, res: Response) => { + try { + const id = req.params.id as string; + + const game = await prisma.game.findUnique({ where: { id } }); + if (!game) { + return res.status(404).json({ error: 'Game not found' }); + } + + if (game.gameMasterId !== req.user!.id) { + return res.status(403).json({ error: 'Not authorized' }); + } + + const updated = await prisma.game.update({ + where: { id }, + data: { status: 'ENDED' } + }); + + res.json(updated); + } catch (error) { + console.error('Unarchive game error:', error); + res.status(500).json({ error: 'Failed to unarchive game' }); + } +}); + router.get('/:id/invite', async (req: AuthRequest, res: Response) => { try { const id = req.params.id as string; diff --git a/frontend/index.html b/frontend/index.html index 096d706..02d3466 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,8 @@ - frontend + + Treasure Trails
diff --git a/frontend/src/pages/CreateGamePage.vue b/frontend/src/pages/CreateGamePage.vue index 0024b67..9834865 100644 --- a/frontend/src/pages/CreateGamePage.vue +++ b/frontend/src/pages/CreateGamePage.vue @@ -96,191 +96,80 @@ onUnmounted(() => { diff --git a/frontend/src/pages/DashboardPage.vue b/frontend/src/pages/DashboardPage.vue index 6f1344a..cff6b2e 100644 --- a/frontend/src/pages/DashboardPage.vue +++ b/frontend/src/pages/DashboardPage.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/pages/EditGamePage.vue b/frontend/src/pages/EditGamePage.vue index 5896b31..7d08b25 100644 --- a/frontend/src/pages/EditGamePage.vue +++ b/frontend/src/pages/EditGamePage.vue @@ -178,224 +178,91 @@ onUnmounted(() => { diff --git a/frontend/src/pages/GameLivePage.vue b/frontend/src/pages/GameLivePage.vue index 712bcf1..4e0f9c9 100644 --- a/frontend/src/pages/GameLivePage.vue +++ b/frontend/src/pages/GameLivePage.vue @@ -164,240 +164,114 @@ onUnmounted(() => { diff --git a/frontend/src/pages/GamePage.vue b/frontend/src/pages/GamePage.vue index 55825e4..8e4d5a3 100644 --- a/frontend/src/pages/GamePage.vue +++ b/frontend/src/pages/GamePage.vue @@ -39,6 +39,28 @@ async function publishGame() { } } +async function archiveGame() { + if (!confirm('Are you sure you want to archive this game?')) return; + + try { + await gameService.archive(gameId.value); + await loadGame(); + } catch (err) { + alert('Failed to archive game'); + } +} + +async function unarchiveGame() { + if (!confirm('Are you sure you want to unarchive this game?')) return; + + try { + await gameService.unarchive(gameId.value); + await loadGame(); + } catch (err) { + alert('Failed to unarchive game'); + } +} + async function endGame() { if (!confirm('Are you sure you want to end this game?')) return; @@ -67,255 +89,132 @@ onMounted(() => { diff --git a/frontend/src/pages/HomePage.vue b/frontend/src/pages/HomePage.vue index b77904d..837a613 100644 --- a/frontend/src/pages/HomePage.vue +++ b/frontend/src/pages/HomePage.vue @@ -26,160 +26,80 @@ onMounted(() => { diff --git a/frontend/src/pages/InvitePage.vue b/frontend/src/pages/InvitePage.vue index b1dd861..3ad96b9 100644 --- a/frontend/src/pages/InvitePage.vue +++ b/frontend/src/pages/InvitePage.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/pages/JoinGamePage.vue b/frontend/src/pages/JoinGamePage.vue index 3fea163..e8c204c 100644 --- a/frontend/src/pages/JoinGamePage.vue +++ b/frontend/src/pages/JoinGamePage.vue @@ -84,147 +84,52 @@ onMounted(() => { - - diff --git a/frontend/src/pages/LoginPage.vue b/frontend/src/pages/LoginPage.vue index 3fae9ee..49e8c6e 100644 --- a/frontend/src/pages/LoginPage.vue +++ b/frontend/src/pages/LoginPage.vue @@ -29,119 +29,43 @@ async function handleSubmit() { diff --git a/frontend/src/pages/PlayGamePage.vue b/frontend/src/pages/PlayGamePage.vue index bf2e1f6..77bc00f 100644 --- a/frontend/src/pages/PlayGamePage.vue +++ b/frontend/src/pages/PlayGamePage.vue @@ -5,7 +5,7 @@ import { io, Socket } from 'socket.io-client'; import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; import { useAuthStore } from '../stores/auth'; -import type { Game, Team, Leg, ChatMessage } from '../types'; +import type { Game, Team, ChatMessage } from '../types'; import { teamService, uploadService } from '../services/api'; const route = useRoute(); @@ -219,165 +219,99 @@ onUnmounted(() => { diff --git a/frontend/src/pages/RegisterPage.vue b/frontend/src/pages/RegisterPage.vue index 468a0d9..34f8f90 100644 --- a/frontend/src/pages/RegisterPage.vue +++ b/frontend/src/pages/RegisterPage.vue @@ -30,130 +30,52 @@ async function handleSubmit() { diff --git a/frontend/src/pages/SpectateGamePage.vue b/frontend/src/pages/SpectateGamePage.vue index 69e9203..d96d698 100644 --- a/frontend/src/pages/SpectateGamePage.vue +++ b/frontend/src/pages/SpectateGamePage.vue @@ -115,186 +115,83 @@ onUnmounted(() => { diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 5cf51de..2deebcd 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -30,8 +30,10 @@ export const gameService = { create: (data: Partial) => api.post('/games', data), update: (id: string, data: Partial) => api.put(`/games/${id}`, data), delete: (id: string) => api.delete(`/games/${id}`), - publish: (id: string) => api.post(`/${id}/publish`), - end: (id: string) => api.post(`/${id}/end`), + publish: (id: string) => api.post(`/games/${id}/publish`), + end: (id: string) => api.post(`/games/${id}/end`), + archive: (id: string) => api.post(`/games/${id}/archive`), + unarchive: (id: string) => api.post(`/games/${id}/unarchive`), getInvite: (id: string) => api.get<{ inviteCode: string }>(`/games/${id}/invite`), }; diff --git a/frontend/src/style.css b/frontend/src/style.css index 527d4fb..7f61fcf 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -1,296 +1,7 @@ -:root { - --text: #6b6375; - --text-h: #08060d; - --bg: #fff; - --border: #e5e4e7; - --code-bg: #f4f3ec; - --accent: #aa3bff; - --accent-bg: rgba(170, 59, 255, 0.1); - --accent-border: rgba(170, 59, 255, 0.5); - --social-bg: rgba(244, 243, 236, 0.5); - --shadow: - rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; - - --sans: system-ui, 'Segoe UI', Roboto, sans-serif; - --heading: system-ui, 'Segoe UI', Roboto, sans-serif; - --mono: ui-monospace, Consolas, monospace; - - font: 18px/145% var(--sans); - letter-spacing: 0.18px; - color-scheme: light dark; - color: var(--text); - background: var(--bg); - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - @media (max-width: 1024px) { - font-size: 16px; - } -} - -@media (prefers-color-scheme: dark) { - :root { - --text: #9ca3af; - --text-h: #f3f4f6; - --bg: #16171d; - --border: #2e303a; - --code-bg: #1f2028; - --accent: #c084fc; - --accent-bg: rgba(192, 132, 252, 0.15); - --accent-border: rgba(192, 132, 252, 0.5); - --social-bg: rgba(47, 48, 58, 0.5); - --shadow: - rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; - } - - #social .button-icon { - filter: invert(1) brightness(2); - } -} - body { margin: 0; } -h1, -h2 { - font-family: var(--heading); - font-weight: 500; - color: var(--text-h); -} - -h1 { - font-size: 56px; - letter-spacing: -1.68px; - margin: 32px 0; - @media (max-width: 1024px) { - font-size: 36px; - margin: 20px 0; - } -} -h2 { - font-size: 24px; - line-height: 118%; - letter-spacing: -0.24px; - margin: 0 0 8px; - @media (max-width: 1024px) { - font-size: 20px; - } -} -p { - margin: 0; -} - -code, -.counter { - font-family: var(--mono); - display: inline-flex; - border-radius: 4px; - color: var(--text-h); -} - -code { - font-size: 15px; - line-height: 135%; - padding: 4px 8px; - background: var(--code-bg); -} - -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; - color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; - - &:hover { - border-color: var(--accent-border); - } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - } -} - -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); - } -} - #app { - width: 1126px; - max-width: 100%; - margin: 0 auto; - text-align: center; - border-inline: 1px solid var(--border); min-height: 100svh; - display: flex; - flex-direction: column; - box-sizing: border-box; -} - -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } -} - -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { - position: relative; - width: 100%; - - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; - } - - &::before { - left: 0; - border-left-color: var(--border); - } - &::after { - right: 0; - border-right-color: var(--border); - } } diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 35d0de5..d83e3a5 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -17,7 +17,7 @@ export interface Game { searchRadius?: number; timeLimitPerLeg?: number; timeDeductionPenalty?: number; - status: 'DRAFT' | 'LIVE' | 'ENDED'; + status: 'DRAFT' | 'LIVE' | 'ENDED' | 'ARCHIVED'; inviteCode?: string; createdAt: string; updatedAt: string;