From 3f3ef3d1a96da99b0d25b45c455a26cf422d9597 Mon Sep 17 00:00:00 2001 From: Daniel Kronovet Date: Thu, 19 Mar 2026 14:35:39 -0400 Subject: [PATCH] Add Watch Demo and View Code cards to results page. Extracted PlayIcon, VideoIcon, and CodeIcon into a shared Icons.tsx component to avoid duplication between EntryCard and Results pages. Added video_url and repo_url cards alongside the existing Play Now card, with purple and blue color schemes respectively. Co-Authored-By: Claude Haiku 4.5 --- client/src/components/EntryCard.tsx | 31 +------------------- client/src/components/Icons.tsx | 29 +++++++++++++++++++ client/src/pages/Results.css | 44 +++++++++++++++++++++++++++++ client/src/pages/Results.tsx | 26 ++++++++--------- 4 files changed, 87 insertions(+), 43 deletions(-) create mode 100644 client/src/components/Icons.tsx diff --git a/client/src/components/EntryCard.tsx b/client/src/components/EntryCard.tsx index 0ae793c..47c27d1 100644 --- a/client/src/components/EntryCard.tsx +++ b/client/src/components/EntryCard.tsx @@ -1,38 +1,9 @@ import { useState } from 'react'; import { Entry } from '../hooks/useJudging'; +import { PlayIcon, VideoIcon, CodeIcon } from './Icons'; import MetricChip from './MetricChip'; import './EntryCard.css'; -function PlayIcon() { - return ( - - - - - - - - ); -} - -function VideoIcon() { - return ( - - - - - ); -} - -function CodeIcon() { - return ( - - - - - ); -} - function renderBold(text: string) { const parts = text.split(/\*\*(.+?)\*\*/g); return parts.map((part, i) => (i % 2 === 1 ? {part} : part)); diff --git a/client/src/components/Icons.tsx b/client/src/components/Icons.tsx new file mode 100644 index 0000000..84593b2 --- /dev/null +++ b/client/src/components/Icons.tsx @@ -0,0 +1,29 @@ +export function PlayIcon() { + return ( + + + + + + + + ); +} + +export function VideoIcon() { + return ( + + + + + ); +} + +export function CodeIcon() { + return ( + + + + + ); +} diff --git a/client/src/pages/Results.css b/client/src/pages/Results.css index 60903d7..379ff35 100644 --- a/client/src/pages/Results.css +++ b/client/src/pages/Results.css @@ -274,6 +274,50 @@ transform: translateY(-1px); } +.results-action-link { + display: inline-flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 2px; + font-size: 13px; + font-weight: 600; + letter-spacing: 0.04em; + text-decoration: none; + padding: 8px 12px; + align-self: stretch; + border-radius: 6px; + transition: all 0.2s ease; +} + +.results-video-link { + color: #c084fc; + background: #c084fc12; + border: 1px solid #c084fc30; +} + +.results-video-link:hover { + color: #d8b4fe; + background: #c084fc20; + border-color: #c084fc60; + box-shadow: 0 0 12px #c084fc25; + transform: translateY(-1px); +} + +.results-code-link { + color: #60a5fa; + background: #60a5fa12; + border: 1px solid #60a5fa30; +} + +.results-code-link:hover { + color: #93c5fd; + background: #60a5fa20; + border-color: #60a5fa60; + box-shadow: 0 0 12px #60a5fa25; + transform: translateY(-1px); +} + /* ─── Nav ─── */ .results-nav { diff --git a/client/src/pages/Results.tsx b/client/src/pages/Results.tsx index 09b5a1c..edbcef4 100644 --- a/client/src/pages/Results.tsx +++ b/client/src/pages/Results.tsx @@ -2,22 +2,10 @@ import { useEffect, useState } from 'react'; import { useParams, Link, Navigate } from 'react-router-dom'; import { formatJamTitle } from '../utils/jam'; import { Entry } from '../hooks/useJudging'; +import { PlayIcon, VideoIcon, CodeIcon } from '../components/Icons'; import MetricChip from '../components/MetricChip'; import './Results.css'; - -function PlayIcon() { - return ( - - - - - - - - ); -} - interface RankedEntry { entry: Entry; weight: number; @@ -121,6 +109,18 @@ export default function Results() { Play Now )} + {r.entry.video_url && ( + + + Watch Demo + + )} + {r.entry.repo_url && ( + + + View Code + + )}