diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 97f0e81..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "prisma.pinToPrisma6": true -} diff --git a/AGENTS.md b/AGENTS.md index 8029dc9..650701c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# OPENSOLVE — DESIGN SYSTEM & IMPLEMENTATION GUIDE (Cursor Agent Spec) +✅ OPEN SOLVE — MASTER REDESIGN & IMPLEMENTATION PROMPT You are the **principal product/UI engineer for OpenSolve**, an open-source LeetCode alternative. @@ -8,617 +8,444 @@ Your job is to **completely redesign** the given page(s) and all of their nested - **Tailwind CSS** - **Customized shadcn/ui components** - **TanStack Table** -- **hugeicons-react** for all icons +- **hugeicons-react** for all icons (see Section 4.4) This is NOT a tweak or refinement. -This is a **full visual + UX rebuild** while keeping the **existing data structures, hooks, and behavior intact**. +This is a **full visual + UX rebuild** while keeping the existing data structures, hooks, and behavior intact. --- -## [00] ROLE & PRIORITIES - -**Role:** -You are responsible for the **UI/UX layer** only. You may reorganize components, JSX, and Tailwind classes, but: - -1. **Do NOT break logic** - - Keep existing hooks, tRPC calls, React Query usage, and business rules. - - Keep prop names and types unless explicitly told otherwise. - -2. **Absolute MUSTs (never violate):** - - `font-mono` for **all** text (headings, labels, body, buttons). - - **No rounded corners** anywhere → always `rounded-none`. - - **Semantic Tailwind tokens only** (`bg-background`, `text-foreground`, etc.). - - **hugeicons-react only** for icons (via `@/components/icons` or direct imports). - - Designs must work in **both light and dark mode**. - - All marketing/UX copy should be configurable (via `config/*.ts`), not hard-coded in components. - -3. **When redesigning a page, output in this structure:** - 1. **Brief UX Plan** (4–6 bullets). - 2. **Main Page Component** (full TSX with imports). - 3. **Nested Components** (any additional components you introduce). - 4. **Config File** (if applicable; put strings/copy here). - 5. **Notes** (integration points, assumptions, domain considerations). - ---- - -## [01] PROJECT CONTEXT (OPENSOLVE) +## 0. Project Context (OpenSolve) OpenSolve is: -- A **competitive programming / algorithmic practice platform**. -- Built with **Next.js**, **PostgreSQL/Prisma**, **tRPC**, **React Query**, **Tailwind**, and **shadcn/ui**. -- Uses a **RabbitMQ + Docker judge** (plus an inline simulator fallback) for submissions. -- Includes rich domain entities like: +- A competitive programming / algorithmic practice platform +- Built with **Next.js**, **PostgreSQL/Prisma**, **tRPC**, **React Query**, **Tailwind**, and **shadcn/ui** +- Uses a **RabbitMQ + Docker judge** for submissions +- Has rich domain entities: - `User`, `Problem`, `ProblemVersion`, `Tag`, `Difficulty`, `Company` - `Submission`, `Language`, `Verdict`, `TestCase` - `Contest`, `ContestProblem`, `ContestRegistration`, `ContestSnapshot`, `ContestClarification` - `Discussion`, `TrailInsight`, `Badge`, `Leaderboard*`, `SystemSetting`, `Incident`, etc. -Everything you design must feel **native** to this domain: - -> Coding, problems, submissions, contests, leaderboards, discussions, staff tools, admin consoles. +Everything you design must feel **native to this domain**: +coding, problems, submissions, contests, leaderboards, discussions, admin tooling. --- -## [02] DESIGN LANGUAGE — “BRUTALIST TERMINAL” +## 1. Goal: Complete Redesign (Not Modification) -### 2.1 Core Aesthetic +**Do NOT**: -OpenSolve uses a **brutalist, terminal-inspired** design. It should feel like a **serious developer tool**, not a generic SaaS. +- Do not preserve or slightly improve the current layout. +- Do not keep the same structure and just reskin. +- Do not keep “placeholder” structures from the old UI. -**Key principles:** +**Instead**: -- **No rounded corners** - - Always use `rounded-none` (buttons, cards, chips, panels, inputs). -- **Sharp borders** - - Emphasis: `border-2 border-border` or `border-2 border-primary`. - - Dividers: `border border-border`. -- **Monospace typography** - - `font-mono` for **all** text, including headings and buttons. -- **Numbered sections** - - Use bracket notation: `[01]`, `[02]`, `[03]` for major sections. -- **Functional minimalism** - - No decorative flourishes for their own sake. - - Let grid, spacing, typography, and subtle gradients carry the visual weight. -- **Magazine-style layouts** - - Asymmetric grids, bold headings, strong hierarchy. - ---- +- **Replace the entire page UI and all nested components** with a new, intentional, premium OpenSolve design. +- Create a layout and visual hierarchy that looks handcrafted and product-grade—**not** like a generic AI/Tailwind template. -## [03] COLOR SYSTEM — SEMANTIC ONLY +The new UI must make people think: -### 3.1 Semantic Tokens +> “There’s no way AI built this. This looks like a serious, professionally designed product.” -**Never** use raw hex colors or Tailwind’s gray/blue palettes (`text-gray-900`, `bg-white`, etc.). -Only use semantic tokens (which are mapped in CSS for light/dark modes): - -- `bg-background` / `text-foreground` — page background and primary text. -- `text-muted-foreground` — secondary text. -- `bg-card` / `text-card-foreground` — card surfaces. -- `bg-primary` / `text-primary-foreground` — primary actions and CTAs. -- `text-primary` — emphasis text. -- `bg-accent` — subtle backgrounds & hovers. -- `border-border` — all default borders. -- State colors (if defined): - - `bg-success`, `text-success`, `bg-success/10`, `border-success/30` - - `bg-warning`, `text-warning`, `bg-warning/10`, `border-warning/30` - - `bg-destructive`, `text-destructive`, `bg-destructive/10`, `border-destructive/30` - - `bg-info`, `text-info`, `bg-info/10`, `border-info/30` - -### 3.2 Gradients & Shadows (Subtle) +--- -Use Tailwind’s gradient utilities (or equivalent custom ones) **sparingly**, mostly for headings and hero sections: +## 2. Global Layout & Information Architecture (Enforce These Patterns) -- **Text gradients (headlines):** +OpenSolve uses a **unified app shell**: -```tsx -className = - "bg-gradient-to-br from-foreground via-foreground to-foreground/70 bg-clip-text text-transparent"; -``` +- **Left Sidebar** → main navigation (Problems, Submissions, Contests, Discussions, Trails, Profile, Admin, etc.) +- **Topbar** → page context and actions -- **Primary accent text:** +For any **authenticated/internal page** you redesign: - `className="bg-gradient-to-r from-primary via-primary to-primary/70 bg-clip-text text-transparent"` +1. **Sidebar (persistent)** + - Implement a clean, slim left sidebar for primary navigation. + - Include: + - Product logo/name + - Main nav items (Problems, Contests, Submissions, Leaderboard, Discussions, Trails) + - Admin/Staff area (only if roles permit) + - Use **icon + label** patterns (icons from `hugeicons-react`). + - Support collapse/minify on smaller screens (`md:` up). -- **Subtle background gradient:** +2. **Topbar (always present above content)** + Use the top bar to convey: + - Page **title** and **subtitle** or short context. + - **Breadcrumbs** (e.g., Problems → Two Sum → Submissions). + - Primary **page-level actions**: “New Contest”, “Create Problem”, “Edit”, “Upsolve”, etc. + - User identity: avatar + small dropdown. + - Optional environment/light indicators (e.g., `Dev`, `Staging` badge), if reasonable. - `className="bg-gradient-to-br from-primary/5 via-background to-background"` +3. **Content Area** + - Below the topbar, design a **clear main content layout**: + - For simple detail pages: single column + side rail. + - For complex pages (problem solving, contest dashboards): **split panes**, sticky headers, and clear sections. -- **Hover gradient overlay (e.g. cards):** +4. **Responsiveness** + - On small screens: + - Sidebar collapses into a top menu or overlay. + - Topbar remains, but simplified. + - Content stacks vertically, no horizontal scroll. - `
` - -- **Shadows:** - - Use `shadow-sm shadow-primary/10`, `shadow-md shadow-primary/20`, etc. - - Keep them subtle; this is not a neumorphic UI. +Use these patterns **consistently** across all redesigns unless a page is explicitly public/standalone (e.g., landing page, auth screens). --- -## [04] TYPOGRAPHY & SPACING - -### 4.1 Typography Scale (all `font-mono`) - -- **Hero display:** - - `className="font-mono text-6xl sm:text-7xl lg:text-8xl font-black leading-[1.05] tracking-tighter"` +## 3. Visual Direction & Design System -- **Section headlines:** +### 3.1 Color System — Modern Bright SaaS (Blue Primary) - `className="font-mono text-4xl sm:text-5xl lg:text-6xl font-black leading-tight tracking-tight"` +Use a **Modern Bright SaaS** style: -- **Subsection titles:** +- **Primary**: Blue (mid-saturated, not neon, not dull). + Think something in the range of Tailwind `blue-500` / `blue-600` for primary actions, with lighter tints for backgrounds/badges. +- **Neutrals**: A refined gray scale (e.g., slate/stone) for backgrounds, borders, and typography. +- **Accents** (used sparingly): + - Green for success (AC, RESOLVED, ACTIVE) + - Amber/orange for warnings (RETRYING, OFFSET, PENDING, FREEZE) + - Red/pink for errors/critical (FAILED, REJECTED, SEV1/SEV2) + - Purple or cyan for “special” or “featured” states (editorials, Trails, badges) - `className="font-mono text-xl font-bold"` +Support **both light and dark mode**: -- **Body text:** +- Use Tailwind `dark:` variants and/or CSS variables. +- Avoid hard-coded colors like `#000`, `#fff`; instead rely on semantic tokens and classes (e.g. `bg-background`, `text-foreground`, `border-border` if using shadcn theme). - `className="font-mono text-base leading-relaxed"` +### 3.2 Typography -- **Small / labels:** +- Use a clean, modern sans-serif. +- Establish a clear hierarchy: + - Page title: `text-2xl` / `text-3xl`, `font-semibold` + - Section headings: `text-lg` / `text-xl`, `font-semibold` + - Body: `text-sm` / `text/base`, comfortable line-height + - Meta text: `text-xs` / `text-[13px]`, muted +- Use consistent letter spacing and alignment. No random mix of weights. - `className="font-mono text-sm"` +### 3.3 Spacing & Layout Rhythm -- **Meta / micro text:** +- Use an **8-point spacing system**: 4, 8, 12, 16, 20, 24, etc. +- Prefer Tailwind spacing tokens (`p-4`, `px-6`, `gap-4`, `gap-6`) over arbitrary pixels. +- Use `max-w-*` and `mx-auto` for constrained layouts where it makes sense (e.g. auth pages, simple forms). - `className="font-mono text-xs text-muted-foreground"` +### 3.4 Surfaces & Depth -- **Section markers:** - - `className="font-mono text-xs font-bold text-primary/80"` - -### 4.2 Spacing System (8px base) - -Use Tailwind spacing aligned with 8px increments: - -- `gap-2` (8px), `gap-3` (12px), `gap-4` (16px), `gap-6` (24px), `gap-8` (32px), `gap-12` (48px). -- `p-4`, `p-6`, `p-8`, `p-12` for padding. -- Section vertical spacing: `py-24 lg:py-32` for major sections. +- Cards and panels should be: + - Subtly rounded (`rounded-xl`, `rounded-2xl` for primary surfaces). + - Light shadows (`shadow-sm`, `shadow-md`), not heavy, with subtle contrast between layers. +- Use separators and soft borders (`border-border`) to structure dense information (tables, timelines, details). --- -## [05] CORE COMPONENT PATTERNS - -### 5.1 Buttons (shadcn/ui-based) - -**Primary CTA:** - -```jsx - -``` - -**Secondary / Outline:** +## 4. Components, Icons & Libraries (OpenSolve Constraints) -```jsx - -``` - -**Ghost / text button:** - -```jsx - -``` - -**Icon button:** +### 4.1 Tech Stack -```jsx - -``` +- **Next.js + TypeScript** +- **Tailwind CSS** +- **shadcn/ui components (customized)** +- **TanStack Query (React Query) over tRPC** +- **TanStack Table** for data tables +- **hugeicons-react** for all icons (see below) -### 5.2 Cards / Panels +Do NOT introduce: -**Default card:** +- New UI libraries (no MUI, Chakra, DaisyUI, etc.). +- New motion libraries (no Framer Motion, no GSAP). +- Heavy CSS frameworks beyond Tailwind. -```jsx -
{/* content */}
-``` +### 4.2 shadcn/ui -**Interactive card with hover highlight:** +- Use shadcn components as your base: `Button`, `Card`, `Tabs`, `Dialog`, `DropdownMenu`, `Badge`, `Tooltip`, `Skeleton`, `Alert`, `Toast`, `Form`, `Input`, `Textarea`, `Select`, `Checkbox`, `Switch`, `Tabs`, `ScrollArea`, etc. +- **Customize them** to match the OpenSolve design system, instead of using vanilla shadcn styles: + - Adjust radii, colors, typography via classNames/tokens. + - Ensure consistency across all redesigned pages. -```jsx -
- {" "} -
{" "} -
{/* content */}
-
-``` +### 4.3 Data Tables — Use TanStack Table -### 5.3 Section Headers +For any list-heavy / admin / analytics page: -```jsx -
- [01] SECTION NAME

- SECTION HEADLINE

-``` +- Use the **existing TanStack Table abstraction** (e.g. a `DataTable` component already in the codebase). +- Do NOT hand-roll random HTML tables when a proper data table is needed. +- Enhance table UX with: + - Sticky headers + - Row hover states + - Clear sorting indicators + - Optional column visibility toggles + - Search & filters integrated into a table toolbar + - Pagination controls that feel native to the design -### 5.4 Stats +### 4.4 Icon System — Migrate to `hugeicons-react` (No `lucide-react`) -```jsx -
- {" "} -
- 50K+{" "} -
{" "} -
DEVELOPERS
-
-``` +OpenSolve is moving from `lucide-react` to **`hugeicons-react`**. +You must: -### 5.5 Grid with Pixel Dividers +1. **Never import from `lucide-react`.** + - Remove all existing lucide imports. + - Do not introduce new ones. + - Replace every lucide icon with a `hugeicons-react` icon. -```jsx -
- {" "} -
Item 1
{" "} -
Item 2
{" "} -
Item 3
-
-``` +2. **Use `hugeicons-react` for every icon**: + - Navigation icons (sidebar, topbar) + - Action icons (buttons, fab, menus) + - Status icons (success, error, warning, info) + - Domain icons (problems, contests, submissions, discussions, leaderboard, admin, incidents, settings, feature flags, judge, queues, etc.) ---- +3. **If you don’t know which `hugeicons-react` icon to use or how to import it**, you MUST: + - Perform an internet search to look up: + - The `hugeicons-react` package, + - Its icon list and naming conventions, + - The appropriate icon component name and import syntax. + - Then choose the most semantically appropriate icon (e.g. problem→code/algorithm icon, contests→trophy/flag, submissions→checklist or code-run icon, incidents→alert, etc.). -## [06] LAYOUT PATTERNS +4. **Consistency**: + - Use a consistent size (e.g. `className="h-4 w-4"` or `h-5 w-5`) for icons in a given context. + - Use consistent stroke/fill style (outlined vs filled) for icons in the same UI area. + - Use Tailwind utility classes to align icons (`inline-flex`, `items-center`, `gap-2`). -### 6.1 Top Navigation (Marketing / Public) +Example (illustrative, not exact): -```html - -``` +```tsx +import { CodeCircle01Icon, Trophy01Icon } from "hugeicons-react"; -### 6.2 App Shell (Authenticated) - -- Use existing `app-shell` / layout wrappers when present. -- Left sidebar with icons + labels. -- Collapsible on mobile. - -### 6.3 Hero Sections - -```jsx -
- {" "} -
- {" "} -
- {" "} - - {config.hero.badge}{" "} -
{" "} -

- {config.hero.headline.line1}
- {config.hero.headline.line2}
{" "} - - {config.hero.headline.line3}{" "} - {" "} -

{" "} -

{config.hero.description}

{" "} -
{/* Primary + secondary CTAs */}
{" "} -
{" "} -
{/* Feature visual / split editor / stats */}
-
+; ``` -### 6.4 Split Pane (Problem / Submission Pages) - -```jsx -
- {" "} -
- {/* Left pane: problem, meta, tests */}{" "} -
{" "} -
- {/* Right pane: editor, console, verdicts */}{" "} -
-
-``` +Apply this migration & usage pattern consistently in all redesigned components. --- -## [07] INTERACTIVE COMPONENTS +## 5. States & Domain-Specific Status Handling -### 7.1 Command Palette (⌘K) +You must **explicitly handle all relevant states** for the page you are redesigning. That includes both generic UX states and OpenSolve’s domain states. -**Expected for all main app contexts.** +### 5.1 Generic UX States (Always Design For) -- Opens with **⌘K** (Mac) / **Ctrl+K** (Windows/Linux). -- Keyboard navigation: arrow keys, Enter to select, ESC to close. -- Style: `rounded-none`, semantic colors, `font-mono`. +For every major section (lists, details, forms, editor, panels): -Implementation hint: +- **Loading state** → skeletons, shimmer, skeleton rows/cards. +- **Empty state** → friendly, domain-aware copy and a clear primary action (e.g. “Create your first contest”, “No submissions yet — try solving a problem”). +- **Error state** → clear message, optional “show technical details” toggle, retry button. +- **Partial/Degraded state** → e.g. when the judge is down but the editor still works. +- **Permission/Role gate** → e.g. curated tools visible only to `PROBLEM_CURATOR`/`ADMIN`. +- **Offline/Network issues** (if appropriate) → subtle banner about connectivity. -`// components/marketing/command-palette.tsx // or components/app/command-palette.tsx` +### 5.2 OpenSolve Domain States (Map To Visual Tokens) -### 7.2 Theme Toggle +Map important enums to **badges, chips, or color-coded text**. You don’t need to hard-code every case in JSX in this prompt, but your design must assume and support them. -Always include a theme toggle in nav / app shell: +Examples: -```jsx - -``` +- `UserStatus`: `ACTIVE`, `BANNED`, `SHADOW_BANNED` +- `UserRole`: `USER`, `PROBLEM_CURATOR`, `ADMIN`, `MODERATOR` +- `ProblemState`: `DRAFT`, `REVIEW`, `PUBLISHED`, `ARCHIVED` +- `ProblemVisibility`: `PUBLIC`, `UNLISTED`, `INTERNAL` +- `ProblemJudgeMode`: `AUTO`, `MANUAL`, `HYBRID` +- `TestCaseKind`: `SAMPLE`, `HIDDEN` +- `SubmissionStatus`: `QUEUED`, `RUNNING`, `SUCCEEDED`, `FAILED`, `RETRYING`, `MANUAL_PENDING` +- `ContestState`: `UPCOMING`, `RUNNING`, `FINISHED`, `ARCHIVED` +- `ContestVisibility`: `PUBLIC`, `PRIVATE` +- `ContestType`: `COMPETITIVE`, `EDUCATIONAL`, `PRIVATE`, `CUSTOM` +- `DiscussionState`: `VISIBLE`, `HIDDEN`, `REMOVED` +- `IncidentStatus`: `OPEN`, `INVESTIGATING`, `MITIGATED`, `MONITORING`, `RESOLVED` +- `IncidentSeverity`: `SEV1`, `SEV2`, `SEV3` -### 7.3 Tables (TanStack Table) - -For problems, submissions, users, contests, etc: - -```jsx - - {" "} - - {/* Filters, view toggles, etc. */}{" "} -
- } -/> -``` +General mapping guidelines: -Styling guidelines: +- **Positive or terminal-good** (e.g. `SUCCEEDED`, `PUBLISHED`, `ACTIVE`, `RESOLVED`) → green/blue badges. +- **Warning/liminal** (e.g. `REVIEW`, `RETRYING`, `UPCOMING`, `MANUAL_PENDING`, `MITIGATING`) → amber/yellow badges. +- **Danger/bad** (e.g. `FAILED`, `REJECTED`, `BANNED`, `SEV1`) → red badges. +- **Internal/system-only** or muted states (e.g. `INTERNAL`, `ARCHIVED`, `SHADOW_BANNED`) → gray/muted badges. -- Header row: `bg-muted font-mono text-xs font-bold uppercase`. -- Row: `border-b border-border hover:bg-accent`. -- Cells: `px-4 py-3 font-mono text-sm`. +Always ensure state is conveyed via **color + text + shape** (for accessibility). --- -## [08] STATES & DOMAIN BADGES +## 6. Page Types & UX Patterns (Use When Relevant) -### 8.1 Generic UX States +When the page you’re given is one of these, follow these patterns: -**Loading** → skeletons, not spinners: +- **Problem Library / Reader** + - Left column: filters (difficulty, tags, companies, status). + - Main: responsive grid or list of problems, status chips, acceptance rate, difficulty badges. + - Strong search & filter UX, with sticky controls on larger screens. -`
` +- **Problem Details + Editor** + - **Split layout**: statement pane and code editor pane. + - Statement: tabs for description, constraints, examples, editorial (if unlocked). + - Editor: language switcher, boilerplate, run vs submit, status strip with verdict and runtime. + - Persist drafts per problem + language. -**Empty** → clear message + action: +- **Submissions & History** + - Use **TanStack Table** with sortable columns (problem, verdict, time, language, runtime, memory). + - Filters for verdict, language, date range, contest vs practice. + - Row click → submission detail pane/page with code + case breakdown. -```jsx -
- {" "} -
No problems found
{" "} - -
-``` - -**Error** → border + background: +- **Contests (builder, dashboard, standings)** + - Contest builder → **multi-step form** (metadata → schedule → settings → problems → review). + - Standings → table with rank, handle, solves, penalty, with freeze state handled visually. + - Clear contest state (UPCOMING/RUNNING/FINISHED), countdown timers, registration state. -```jsx -
- {error.message} -
-``` +- **Discussions & Trails** + - Thread layout with clear indentation, reply counts, voting buttons, spoiler handling. + - Trail insights as structured cards with categories and upvotes, maybe a graph or relationship hints. -### 8.2 Domain-Specific Badges +- **Admin Panel** + - Use a **denser layout**, but still breathable. + - Overview metrics at top (incidents open, queue depth, recent failures). + - Tabs for Users, Problems, Submissions, Contests, Discussions, Incidents, Feature Flags, System Settings. + - Remember: **Admin can do everything**. Show powerful tools but with clear warnings and safeguards. -Use `Badge` from shadcn, customized: +Apply what’s relevant to the specific page you are redesigning. -` STATUS ` +--- -**Verdict:** +## 7. Forms, Modals, and Feedback -- `SUCCEEDED` → `AC` (Accepted): +### 7.1 Forms - ` AC ` +If the page includes a non-trivial form (contest builder, problem editor, settings, etc.): -- `FAILED` → `WA` / `RE` / etc (depending on verdict): +- For long/complex forms → convert into a **multi-step flow** with: + - Progress indicator + - Clear section grouping + - “Next” / “Back” actions - ` WA ` +- Use shadcn `Form` with proper label, description, and error text. +- Show inline validation and top-level error summary when needed. +- Mobile-friendly: no cramped inputs, adequate tap targets. -- `RUNNING`: +### 7.2 Modals (Preferred) vs Drawers - ` RUNNING ` +- Prefer **modals (Dialogs)** over drawers/sheets. +- Use shadcn `Dialog` for: + - Confirmation flows + - Quick create/edit forms + - Dangerous actions (delete problem, ban user, rejudge contest, etc.) -**Problem State:** +- Only use drawers/sheets if absolutely necessary for mobile or workflows that must remain anchored. -- `PUBLISHED`, `DRAFT`, `REVIEW` with matching semantic tokens. +### 7.3 Toasts / Feedback System -**Contest State:** +Every redesigned page must integrate the existing or new **toast system** using shadcn (or compatible pattern): -- `RUNNING` → `LIVE` -- `UPCOMING` -- `FINISHED` → `ENDED` +- Types: + - success + - error/failure + - warning + - info ---- +- Toasts must: + - Be accessible (ARIA labels, understandable message). + - Be responsive (sane max-width on mobile). + - Have distinct but subtle styling per variant. -## [09] FORMS, MODALS & TOASTS +Provide **example toast usages** in your response for key flows (e.g., save success, validation error, network failure). -### 9.1 Forms +--- -Multi-step for complex flows (problem authoring, contest creation): +## 8. Motion, Micro-Interactions & Performance -- Show progress: `[01]`, `[02]`, `[03]`. -- Use clear section breaks. +- **No external animation libraries** (no Framer Motion, no heavy animation packages). +- Use **lightweight CSS transitions** and Tailwind utilities only: + - `transition-all`, `transition-colors`, `transition-opacity` + - `duration-150` to `duration-300` + - `ease-out`, `ease-in-out` -Input pattern: +- Add reusable animation utilities in `globals.css` (or equivalent), e.g.: + - `.fade-in-soft` + - `.slide-up-soft` + - `.scale-on-hover` -```tsx -
- {" "} - {" "} - {" "} -

Helper text

-
-``` +- Apply them sparingly: + - Hover effects on cards/buttons + - Subtle entry animations for modals or dropdowns + - Soft highlight when data updates (optional) -### 9.2 Modals (Dialog) - -```tsx - - {" "} - - {" "} - - {" "} - MODAL TITLE {" "} - - Helper description.{" "} - {" "} - - {/* Content */}{" "} - - -``` - -### 9.3 Toasts - -`toast({ title: "Success", description: "Problem created successfully", className: "rounded-none border-2 border-success bg-success/5 font-mono text-sm", -});` +Do NOT over-animate. Prioritize **clarity and snappiness**. --- -## [10] RESPONSIVE DESIGN +## 9. Implementation Rules (Very Important) -Use mobile-first Tailwind patterns: +When you respond: -`className="text-sm sm:text-base md:text-lg lg:text-xl"` +1. **Do NOT add unnecessary comments** in the code. + - Only minimal structural comments where absolutely helpful (e.g., `// Main content`, `// Filters`). + - No conversational or explanatory comments inside the TSX. -Grids: +2. **Do NOT change data contracts**: + - Keep props, hooks, and API calls consistent with the existing page unless explicitly required. + - You’re redesigning the UI, not redefining backend contracts. -`className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"` +3. **TypeScript discipline**: + - Avoid `any`. + - Type component props properly. -Page container: +4. **Lint & Build Discipline**: + - Assume you will run: + - `npm run lint` + - `npm run build` -`className="mx-auto max-w-screen-2xl px-6 lg:px-12"` + - Your code must be valid, type-safe, and buildable. + - If you introduce patterns that would cause type/lint errors, fix them before finalizing your answer. -Always verify layouts for: +5. **Support dark & light mode** in all new styles: + - Use Tailwind `dark:` variants consistently. + - Ensure contrast ratios are readable. -- Small mobile (~375px) -- Tablet (~768px) -- Desktop (≥ 1280px) +6. **Icons**: + - Never use `lucide-react`. + - Always use `hugeicons-react`, and if unsure, look up the correct icon and import syntax via internet search. --- -## [11] ICON SYSTEM — HUGEICONS ONLY - -- **Never** use `lucide-react`. -- Use **hugeicons-react** or a local alias module: +## 10. Response Structure & Deliverables - ```tsx - import { Code2Icon, GithubIcon, ArrowRightIcon } from "@/components/icons";` - ``` - -- Sizes: - - Small: `className="h-4 w-4"` - - Medium: `className="h-5 w-5"` - - Large: `className="h-6 w-6"` - -If you don’t know the icon name, pick a semantically close one. - ---- +When you answer, always structure your response like this: -## [12] IMPLEMENTATION RULES - -### 12.1 TypeScript & Imports - -- TypeScript strict: **no `any`**. -- Prefer types inferred from existing code and types from `@/types`, `@/lib`, etc. -- Import order: - 1. React/Next. - 2. External libraries. - 3. Components (`@/components/...`). - 4. Utilities (`@/lib/...`). - 5. Config (`@/config/...`). - 6. Types. - -### 12.2 File Organization - -Follow this general layout: - -```txt -`components/ - marketing/ # Landing & public pages - problems/ # Problem-related components - contests/ # Contest-related components - workspace/ # Creator workspace components - admin/ # Admin console pieces - staff/ # Staff tools - ui/ # shadcn base components - -config/ - landing.ts # Landing page content - navigation.ts # Nav structure - page-*.ts # Per-page configs when needed - -lib/ - utils.ts # Utilities` -``` +1. **High-Level UX & Visual Plan (short)** + - 4–8 bullet points explaining the new layout and design decisions. -### 12.3 Config-Driven Content +2. **Updated Page Component(s)** + - Full **TSX/JSX** for the redesigned page. + - Include imports. + - Assume Next.js + TypeScript. -Example `config/landing.ts`: +3. **Nested Components** + - TSX for all **new or redesigned nested components** used by this page (e.g. toolbars, filters, summary cards, side panels, modals). + - Keep them in realistic locations (`components/...` etc.), but you don’t need to show file paths—just clear component definitions. -```tsx -`export const landingConfig = { hero: { badge: "ALPHA v0.1.0", headline: { line1: "CODE", line2: "COMPETE", line3: "CONQUER", - }, description: "Open-source algorithmic practice platform...", - }, stats: [ - { value: "50K+", label: "DEVELOPERS" }, - { value: "1M+", label: "SUBMISSIONS" }, - ], features: { items: [ - { num: "01", title: "...", description: "..." }, - ], - }, -}; export type LandingConfig = typeof landingConfig;`; -``` +4. **Styling / Theme Adjustments** + - Any Tailwind or `globals.css` additions (reusable animation utilities, color tokens, etc.). + - Any shadcn theme overrides if needed (can be shown as code snippets). -Usage: +5. **Toasts & State Handling Examples** + - Brief code snippet showing how to trigger success/error/warning/info toasts on this page. + - Show sample handling for loading, empty, and error states in the main UI. -```tsx -import { landingConfig } from "@/config/landing";

{landingConfig.hero.headline.line1}

;` -``` +6. **Short Notes for Future Pages** + - 3–5 bullets explaining how this design ties back into the global OpenSolve system so future pages can follow the same patterns. --- -## [13] REDESIGN RESPONSE STRUCTURE - -When asked to redesign a page: +## 11. Core Reminder -1. **Brief UX Plan** - - 4–6 bullets describing: - - Layout (sections, grids, split panes). - - Main interactions (filters, tables, command palette, etc.). - - How it applies OpenSolve brutalist/terminal principles. +- The current UI is **just a temporary testing version**. +- You are here to create a **premium, modern, bespoke** interface that feels: + - intentional + - cohesive across all OpenSolve surfaces + - tuned for serious power users (competitive programmers, problem setters, contest organizers, admins) -2. **Main Page Component (TSX)** - - Full component with imports. - - Uses semantic Tailwind classes and config-driven content. +- Avoid anything that looks like a copy-paste Tailwind template, a generic AI dashboard, or a portfolio starter. -3. **Nested Components** - - Any supporting components introduced (e.g. `ContestHeader`, `SubmissionsToolbar`). - - Keep responsibilities focused. +--- -4. **Config File (if necessary)** - - All non-trivial copy moved into `config/.ts`. +## 12. Input -5. **Notes** - - Any deviations from patterns. - - Integration with existing hooks, tRPC, or domain objects. +You will now be given **one or more pages** from the OpenSolve codebase. +Apply all rules above. diff --git a/AUTH_QUICKSTART.md b/AUTH_QUICKSTART.md index 127ac06..f4bbe2a 100644 --- a/AUTH_QUICKSTART.md +++ b/AUTH_QUICKSTART.md @@ -236,4 +236,3 @@ Session is auto-loaded in tRPC context. Use appropriate procedure type: - [ ] Review audit logs regularly - [ ] Test 2FA enrollment & recovery flows - [ ] Test email deliverability across providers - diff --git a/app/(auth)/auth/forgot-password/page.tsx b/app/(auth)/auth/forgot-password/page.tsx index 466290c..d1f0728 100644 --- a/app/(auth)/auth/forgot-password/page.tsx +++ b/app/(auth)/auth/forgot-password/page.tsx @@ -2,12 +2,8 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import Link from "next/link"; -import { toast } from "sonner"; - import { trpc } from "@/lib/trpc/client"; import { requestPasswordResetSchema, type RequestPasswordResetInput } from "@/lib/validators/auth"; -import { Button } from "@/components/ui/button"; import { Form, FormControl, @@ -15,14 +11,18 @@ import { FormItem, FormLabel, FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { ArrowRight, CheckCircle2, Mail } from "@/components/icons"; -import { authConfig } from "@/config/auth"; + Button, + Input, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui"; +import { toast } from "sonner"; +import Link from "next/link"; export default function ForgotPasswordPage() { - const { forgotPassword } = authConfig; - const form = useForm({ resolver: zodResolver(requestPasswordResetSchema), defaultValues: { @@ -45,95 +45,47 @@ export default function ForgotPasswordPage() { }; return ( -
-
- - - {forgotPassword.badge} - - [03] Password reset -
- -
-

- {forgotPassword.headline} -

-

- {forgotPassword.description} -

-
+ + + Reset Password + + Enter your email address and we'll send you a link to reset your password. + + + +
+ + ( + + Email + + + + + + )} + /> -
-
- Security notes -
-
- {forgotPassword.security.map((note) => ( -
- - {note} -
- ))} -
-
- - - - ( - - - Email address - - - - - - - )} - /> - - - - + + + -
-
- Remember your password? - +
+ Back to sign in -
-
- Need an account? - - Create account - - -
-
-
+ + ); } - diff --git a/app/(auth)/auth/magic-link/page.tsx b/app/(auth)/auth/magic-link/page.tsx index f44dc85..38a505f 100644 --- a/app/(auth)/auth/magic-link/page.tsx +++ b/app/(auth)/auth/magic-link/page.tsx @@ -1,27 +1,24 @@ "use client"; -import { useRouter, useSearchParams } from "next/navigation"; import { useEffect, useState } from "react"; -import { toast } from "sonner"; - -import { AlertTriangle, ArrowRight, CheckCircle2, Loader2, Sparkles } from "@/components/icons"; -import { Button } from "@/components/ui/button"; -import { authConfig } from "@/config/auth"; import { trpc } from "@/lib/trpc/client"; +import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui"; +import { useRouter, useSearchParams } from "next/navigation"; +import { toast } from "sonner"; +import { CheckCircle2, XCircle, Loader2 } from "@/components/icons"; export default function MagicLinkPage() { const router = useRouter(); const searchParams = useSearchParams(); const token = searchParams?.get("token") || ""; - const { magicLink } = authConfig; - const [status, setStatus] = useState<"loading" | "success" | "error">("loading"); const verifyMutation = trpc.auth.verifyMagicLink.useMutation({ onSuccess: () => { setStatus("success"); toast.success("Signed in successfully"); + // Slight delay so user sees success state setTimeout(() => router.push("/dashboard"), 500); }, onError: (error) => { @@ -41,159 +38,51 @@ export default function MagicLinkPage() { if (status === "loading") { return ( -
-
- - - {magicLink.badge} - - [08] Processing -
- -
-

- {magicLink.loading.headline} -

-

- {magicLink.loading.description} -

-
- -
-
-
-
- -
-

Validating magic link...

-
-
- -
-
- Security check -
-

- We're verifying your magic link token and establishing a secure session. This may - take a few seconds. -

-
-
+ + + + + Signing You In + + Validating your magic link… + + ); } if (status === "success") { return ( -
-
- - - Authenticated - - [09] Success -
- -
-

- {magicLink.success.headline} -

-

- {magicLink.success.description} -

-
- -
-
-
-
- -
-

Redirecting to dashboard...

-
-
- - - -
- - Or{" "} - - -
-
+ + + + + Signed In + + You’re being redirected to your dashboard. + + + + + ); } return ( -
-
- - - Failed - - [10] Error -
- -
-

- {magicLink.error.headline} -

-

- {magicLink.error.description} -

-
- -
-
- Common causes -
-
-

• Link has already been used (single-use only)

-

• Link expired (15 minute validity)

-

• Token was tampered with or corrupted

-

• Network error during validation

-
-
- - - -
-
- Need a new link? - -
-
- Use password instead? - -
-
-
+ + + + + Link Invalid or Expired + + This sign-in link is invalid or has expired. + + + + + ); } diff --git a/app/(auth)/auth/reset-password/page.tsx b/app/(auth)/auth/reset-password/page.tsx index d30cdc9..505f7a9 100644 --- a/app/(auth)/auth/reset-password/page.tsx +++ b/app/(auth)/auth/reset-password/page.tsx @@ -2,12 +2,8 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useRouter, useSearchParams } from "next/navigation"; -import { toast } from "sonner"; - import { trpc } from "@/lib/trpc/client"; import { resetPasswordSchema, type ResetPasswordInput } from "@/lib/validators/auth"; -import { Button } from "@/components/ui/button"; import { Form, FormControl, @@ -15,18 +11,22 @@ import { FormItem, FormLabel, FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { ArrowRight, CheckCircle2, ShieldCheck, AlertTriangle } from "@/components/icons"; -import { authConfig } from "@/config/auth"; + Button, + Input, + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui"; +import { toast } from "sonner"; +import { useRouter, useSearchParams } from "next/navigation"; export default function ResetPasswordPage() { const router = useRouter(); const searchParams = useSearchParams(); const token = searchParams?.get("token") || ""; - const { resetPassword } = authConfig; - const form = useForm({ resolver: zodResolver(resetPasswordSchema), defaultValues: { @@ -51,125 +51,57 @@ export default function ResetPasswordPage() { if (!token) { return ( -
-
- - - Invalid token - -
- -
-

- {resetPassword.invalid.headline} -

-

- {resetPassword.invalid.description} -

-
- - - -
- - Or{" "} - - -
-
+ + + Invalid Link + This password reset link is invalid or has expired. + + + + + ); } return ( -
-
- - - {resetPassword.badge} - - [04] New password -
- -
-

- {resetPassword.headline} -

-

- {resetPassword.description} -

-
- -
-
- Password requirements -
-
- {resetPassword.requirements.map((requirement) => ( -
- - {requirement} -
- ))} -
-
- -
- - ( - - - New password - - - - - - - )} - /> - - - - - -
-
- Password reset? - -
-
-
+ + + Set New Password + Enter your new password below. + + +
+ + ( + + New Password + + + + +

+ At least 8 characters with uppercase, lowercase, and numbers +

+
+ )} + /> + + + + +
+
); } - diff --git a/app/(auth)/auth/verify-email/page.tsx b/app/(auth)/auth/verify-email/page.tsx index acd9aa5..59f6388 100644 --- a/app/(auth)/auth/verify-email/page.tsx +++ b/app/(auth)/auth/verify-email/page.tsx @@ -1,21 +1,17 @@ "use client"; -import { useRouter, useSearchParams } from "next/navigation"; import { useEffect, useState } from "react"; -import { toast } from "sonner"; - -import { AlertTriangle, ArrowRight, CheckCircle2, Loader2 } from "@/components/icons"; -import { Button } from "@/components/ui/button"; -import { authConfig } from "@/config/auth"; import { trpc } from "@/lib/trpc/client"; +import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui"; +import { useRouter, useSearchParams } from "next/navigation"; +import { toast } from "sonner"; +import { CheckCircle2, XCircle, Loader2 } from "@/components/icons"; export default function VerifyEmailPage() { const router = useRouter(); const searchParams = useSearchParams(); const token = searchParams?.get("token") || ""; - const { verifyEmail } = authConfig; - const [status, setStatus] = useState<"loading" | "success" | "error">( token ? "loading" : "error", ); @@ -42,140 +38,53 @@ export default function VerifyEmailPage() { if (status === "loading") { return ( -
-
- - - {verifyEmail.badge} - - [05] Processing -
- -
-

- {verifyEmail.loading.headline} -

-

- {verifyEmail.loading.description} -

-
- -
-
-
-

Validating token...

-
-
-
+ + + + + Verifying Email + + Please wait while we verify your email address... + + ); } if (status === "success") { return ( -
-
- - - Verified - - [06] Complete -
- -
-

- {verifyEmail.success.headline} -

-

- {verifyEmail.success.description} -

-
- -
-
- Unlocked features -
-
- {verifyEmail.success.features.map((feature) => ( -
- - {feature} -
- ))} -
-
- - - -
- - Or{" "} - - -
-
+ + + + + Email Verified + + + Your email has been successfully verified. You can now access all features. + + + + + + ); } return ( -
-
- - - Failed - - [07] Error -
- -
-

- {verifyEmail.error.headline} -

-

- {verifyEmail.error.description} -

-
- -
-
- Next steps -
-
-

1. Sign in to your account

-

2. Navigate to Settings → Account

-

3. Request a new verification email

-
-
- - - -
-
- Need help? - -
-
-
+ + + + + Verification Failed + + This verification link is invalid or has expired. + + + + + ); } - diff --git a/app/(auth)/layout.tsx b/app/(auth)/layout.tsx index acf5919..ca23b1a 100644 --- a/app/(auth)/layout.tsx +++ b/app/(auth)/layout.tsx @@ -1,12 +1,8 @@ +import { getSession } from "@/lib/auth/session"; +import { Code2, Sparkles } from "@/components/icons"; import Link from "next/link"; -import type { PropsWithChildren } from "react"; import { redirect } from "next/navigation"; - -import { CommandPalette } from "@/components/marketing/command-palette"; -import { ThemeToggle } from "@/components/ui/theme-toggle"; -import { CheckCircle2, Code2, Sparkles } from "@/components/icons"; -import { authConfig } from "@/config/auth"; -import { getSession } from "@/lib/auth/session"; +import type { PropsWithChildren } from "react"; export const dynamic = "force-dynamic"; @@ -16,75 +12,72 @@ export default async function AuthLayout({ children }: PropsWithChildren) { redirect("/dashboard"); } - const { layout } = authConfig; - return ( - <> - -
-
-
- -
- -
-
- - OpenSolve - - - {layout.badge} - -
- -
- - ⌘K - - +
+
+
+ +
+ +
+ OpenSolve + +
+ +
+
+
+ + For developers, by developers
+

+ Master algorithms through deliberate practice +

+

+ Join a community of engineers solving problems, competing in contests, and sharpening + their craft every day. +

-
-
-
- +
+
+
12,000+
+
Active developers
+
+
+
500+
+
Curated problems
+
+
+
50+
+
Weekly contests
+
+
+
-
{children}
+
© 2025 OpenSolve. Built with care.
+
+ +
+
+
+ +
+ +
+ OpenSolve +
- + + {children} +
- +
); } diff --git a/app/(auth)/sign-in/page.tsx b/app/(auth)/sign-in/page.tsx index 476a8a6..fbd7a04 100644 --- a/app/(auth)/sign-in/page.tsx +++ b/app/(auth)/sign-in/page.tsx @@ -1,54 +1,54 @@ -import Link from "next/link"; - import { SignInForm } from "@/components/auth/sign-in-form"; -import { ArrowRight } from "@/components/icons"; -import { authConfig } from "@/config/auth"; +import Link from "next/link"; export default function SignInPage() { - const { signIn } = authConfig; - return ( -
-
- [02] Sign in - - - Auth required - +
+
+

Welcome back

+

Sign in to continue your learning journey

+ -
-
- Need a reset? - - {signIn.links.forgot.label} - + +
+
+
+ + or + +
-
- New here? + +
- {signIn.links.signup.label} - + Forgot your password? +
+ New to OpenSolve?{" "} + + Create an account + +
-
- By signing in, you agree to our{" "} - - {signIn.links.terms.label} - {" "} - and{" "} - - {signIn.links.privacy.label} - - . -
-
+ +
+ By signing in, you agree to our{" "} + + Terms + {" "} + and{" "} + + Privacy Policy + +
+
); } diff --git a/app/(auth)/sign-up/page.tsx b/app/(auth)/sign-up/page.tsx index 14ef8b9..dd41019 100644 --- a/app/(auth)/sign-up/page.tsx +++ b/app/(auth)/sign-up/page.tsx @@ -1,45 +1,46 @@ -import Link from "next/link"; - import { SignUpForm } from "@/components/auth/sign-up-form"; -import { ArrowRight } from "@/components/icons"; -import { authConfig } from "@/config/auth"; +import Link from "next/link"; export default function SignUpPage() { - const { signUp } = authConfig; - return ( -
-
- [02] Create your profile - - - Two-step onboarding - +
+
+

Create your account

+

Start solving problems and competing today

+ -
-
- Already registered? + +
+
+
+ + or + +
+
+ +
+ Already have an account?{" "} - {signUp.links.signin.label} - - -
-
- By creating an account, you agree to our{" "} - - {signUp.links.terms.label} - {" "} - and{" "} - - {signUp.links.privacy.label} + Sign in - .
-
+ +
+ By creating an account, you agree to our{" "} + + Terms + {" "} + and{" "} + + Privacy Policy + +
+ ); } diff --git a/app/(marketing)/page.tsx b/app/(marketing)/page.tsx index 1da6789..147b78d 100644 --- a/app/(marketing)/page.tsx +++ b/app/(marketing)/page.tsx @@ -1,338 +1,111 @@ -import { ArrowRight, Code2, Github } from "@/components/icons"; -import { CommandPalette } from "@/components/marketing/command-palette"; -import { SplitEditor } from "@/components/marketing/split-editor"; -import { ThemeToggleLanding } from "@/components/marketing/theme-toggle-landing"; -import { Button } from "@/components/ui"; -import { landingConfig } from "@/config/landing"; +import { + Badge, + Button, + Card, + CardContent, + CardHeader, + CardTitle, + ThemeToggle, +} from "@/components/ui"; import { siteConfig } from "@/config/site"; import Link from "next/link"; +import { Code2, Sparkles } from "@/components/icons"; export const revalidate = 21600; export default function Home() { return ( - <> - - -
-