From c17d6b6b700daf3205bb999c57c04570986bc30e Mon Sep 17 00:00:00 2001 From: Oracle Date: Tue, 28 Apr 2026 15:59:47 +0200 Subject: [PATCH] Add Signup/Signin page, query profile information via API and add footer with its respective subpages --- README.md | 140 ++++++++++---- dist/_astro/Layout.D3ovbguN.css | 1 - dist/_astro/Layout.slfrh7tA.css | 1 + dist/about/index.html | 8 + dist/challenges/1/index.html | 28 ++- dist/challenges/2/index.html | 26 ++- dist/challenges/3/index.html | 28 ++- dist/challenges/4/index.html | 26 ++- dist/challenges/5/index.html | 26 ++- dist/faq/index.html | 1 + dist/imprint/index.html | 7 + dist/index.html | 8 +- dist/privacy/index.html | 18 ++ dist/profile/index.html | 259 ++++++++++++++++++++++++- dist/signin/index.html | 11 ++ dist/signup/index.html | 9 + dist/terms/index.html | 28 +++ src/components/DiffViewer.astro | 33 ++-- src/components/Footer.astro | 56 ++++++ src/layouts/Layout.astro | 2 + src/pages/about.astro | 65 +++++++ src/pages/challenges/[slug].astro | 14 +- src/pages/faq.astro | 61 ++++++ src/pages/imprint.astro | 42 ++++ src/pages/index.astro | 30 +-- src/pages/privacy.astro | 85 +++++++++ src/pages/profile.astro | 308 +++++++++++++++++++++++++++--- src/pages/signin.astro | 108 +++++++++++ src/pages/signup.astro | 121 ++++++++++++ src/pages/terms.astro | 94 +++++++++ 30 files changed, 1490 insertions(+), 154 deletions(-) delete mode 100644 dist/_astro/Layout.D3ovbguN.css create mode 100644 dist/_astro/Layout.slfrh7tA.css create mode 100644 dist/about/index.html create mode 100644 dist/faq/index.html create mode 100644 dist/imprint/index.html create mode 100644 dist/privacy/index.html create mode 100644 dist/signin/index.html create mode 100644 dist/signup/index.html create mode 100644 dist/terms/index.html create mode 100644 src/components/Footer.astro create mode 100644 src/pages/about.astro create mode 100644 src/pages/faq.astro create mode 100644 src/pages/imprint.astro create mode 100644 src/pages/privacy.astro create mode 100644 src/pages/signin.astro create mode 100644 src/pages/signup.astro create mode 100644 src/pages/terms.astro diff --git a/README.md b/README.md index b6de9b9..5be1bc8 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,116 @@ -# Astro Starter Kit: Basics +# PR Dojo -```sh -bun create astro@latest -- --template basics +A code review practice platform where users hunt for bugs in rejected PR code, earn XP, and submit fixes. + +## Features + +- **Challenge-based learning** — Browse through real-world buggy code challenges +- **Interactive diff viewer** — Click on lines to mark them as buggy with visual feedback +- **Inline fix submission** — Write fixes per-marked line or as a unified diff +- **XP system** — Earn points for finding and fixing bugs +- **Difficulty ratings** — Challenges range from 1 to 5 stars +- **Hints system** — Hover over marked lines to reveal contextual hints + +## Tech Stack + +- **Astro 6** — Static site generator +- **Tailwind CSS v4** — Utility-first CSS via `@tailwindcss/vite` +- **TypeScript** — Strict mode +- **Node.js 22+** — Runtime + +## Getting Started + +### Prerequisites + +- Node.js >= 22.12.0 +- Bun package manager + +### Installation + +```bash +bun install ``` -> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! +### Development -## 🚀 Project Structure - -Inside of your Astro project, you'll see the following folders and files: - -```text -/ -├── public/ -│ └── favicon.svg -├── src -│   ├── assets -│   │   └── astro.svg -│   ├── components -│   │   └── Welcome.astro -│   ├── layouts -│   │   └── Layout.astro -│   └── pages -│   └── index.astro -└── package.json +```bash +bun dev ``` -To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/). +Starts the dev server at `localhost:4321`. -## 🧞 Commands +### Build -All commands are run from the root of the project, from a terminal: +```bash +bun build +``` -| Command | Action | -| :------------------------ | :----------------------------------------------- | -| `bun install` | Installs dependencies | -| `bun dev` | Starts local dev server at `localhost:4321` | -| `bun build` | Build your production site to `./dist/` | -| `bun preview` | Preview your build locally, before deploying | -| `bun astro ...` | Run CLI commands like `astro add`, `astro check` | -| `bun astro -- --help` | Get help using the Astro CLI | +Produces a static site in `dist/`. -## 👀 Want to learn more? +### Preview -Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). +```bash +bun preview +``` + +Locally previews the production build. + +## Project Structure + +``` +src/ +├── data/ +│ └── challenges.json # Challenge data (code, hints, expected lines) +├── pages/ +│ ├── index.astro # Challenge listing + hero +│ ├── profile.astro # User profile / XP dashboard +│ └── challenges/ +│ └── [slug].astro # Single challenge view +├── components/ +│ ├── DiffViewer.astro # Interactive diff viewer with line marking +│ └── Welcome.astro # Legacy starter component +├── layouts/ +│ └── Layout.astro # Root layout with header/nav/footer +└── styles/ + └── global.css # Global styles +``` + +## Challenge Data Format + +Each challenge in `src/data/challenges.json` contains: + +| Field | Type | Description | +|-------|------|-------------| +| `id` | number | Unique identifier | +| `title` | string | Challenge name | +| `repository` | string | GitHub repo path | +| `baseSha` | string | Base commit SHA | +| `difficulty` | number | 1-5 stars | +| `xpValue` | number | XP reward | +| `bugType` | string | Category (e.g., "Memory Safety") | +| `file` | string | Filename | +| `code` | string | Buggy source code | +| `hints` | string[] | Array of "Line N: description" hints | +| `expectedLines` | number[] | Lines containing bugs | +| `expectedPatch` | string | Unified diff of the fix | + +## Development Notes + +- Tailwind CSS v4 uses the Vite plugin — no `tailwind.config.js` or `@layer` directives +- Astro SSR renders everything client-side by default; add `client:*` directives only when interactivity is needed +- The `full_plan.md` documents the planned backend architecture (reference only, not a blind spec) + +## Current Status + +**Frontend complete, backend pending.** + +The site currently runs as a static frontend with hardcoded challenge data. The planned backend will be built with either Quarkus or Node.js + SQLite to support: + +- User authentication and XP tracking +- Persistent bug submissions +- Challenge progress tracking +- Leaderboards + +## License + +MIT diff --git a/dist/_astro/Layout.D3ovbguN.css b/dist/_astro/Layout.D3ovbguN.css deleted file mode 100644 index 144913b..0000000 --- a/dist/_astro/Layout.D3ovbguN.css +++ /dev/null @@ -1 +0,0 @@ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-white:#fff;--spacing:.25rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.start{inset-inline-start:var(--spacing)}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.-mx-2{margin-inline:calc(var(--spacing) * -2)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-2{margin-left:calc(var(--spacing) * 2)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-20{height:calc(var(--spacing) * 20)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:calc(var(--spacing) * 0)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-full{width:100%}.max-w-6xl{max-width:var(--container-6xl)}.flex-1{flex:1}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-\[\#30363d\]{border-color:#30363d}.bg-\[\#0a3064\]{background-color:#0a3064}.bg-\[\#0d1117\]{background-color:#0d1117}.bg-\[\#1f6feb\]{background-color:#1f6feb}.bg-\[\#58a6ff\]{background-color:#58a6ff}.bg-\[\#161b22\]{background-color:#161b22}.bg-\[\#21262d\]{background-color:#21262d}.bg-\[\#a5d6ff\]{background-color:#a5d6ff}.bg-\[\#f8514920\]{background-color:#f8514920}.bg-\[\#ff7b7233\]{background-color:#ff7b7233}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.pr-4{padding-right:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-pre{white-space:pre}.text-\[\#8b949e\]{color:#8b949e}.text-\[\#58a6ff\]{color:#58a6ff}.text-\[\#79c0ff\]{color:#79c0ff}.text-\[\#484f58\]{color:#484f58}.text-\[\#30363d\]{color:#30363d}.text-\[\#a5d6ff\]{color:#a5d6ff}.text-\[\#c9d1d9\]{color:#c9d1d9}.text-\[\#e6edf3\]{color:#e6edf3}.text-\[\#f85149\]{color:#f85149}.text-\[\#ff7b72\]{color:#ff7b72}.text-\[3ac840\]{color:3ac840}.text-white{color:var(--color-white)}.italic{font-style:italic}.no-underline{text-decoration-line:none}.opacity-0{opacity:0}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-\[\#161b22\]:hover{background-color:#161b22}.hover\:bg-\[\#388bfd\]:hover{background-color:#388bfd}.hover\:bg-\[\#30363d\]:hover{background-color:#30363d}.hover\:bg-\[\#f8514930\]:hover{background-color:#f8514930}.hover\:text-\[\#c9d1d9\]:hover{color:#c9d1d9}.hover\:text-\[\#f85149\]:hover{color:#f85149}}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-0:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-\[\#58a6ff\]:focus{--tw-ring-color:#58a6ff}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-\[\#21262d\]:disabled{background-color:#21262d}.disabled\:text-\[\#484f58\]:disabled{color:#484f58}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:root{--bg-primary:#0d1117;--bg-secondary:#161b22;--bg-tertiary:#21262d;--border-color:#30363d;--text-primary:#c9d1d9;--text-secondary:#8b949e;--text-muted:#6e7681;--blue-900:#0a3064;--blue-800:#1a549d;--blue-700:#1f6feb;--blue-600:#388bfd;--blue-500:#58a6ff;--blue-400:#79c0ff;--blue-300:#a5d6ff;--accent-purple:#a371f7;--accent-orange:#f2cc60;--accent-red:#f85149;--btn-primary:#1f6feb;--btn-primary-hover:#388bfd;--btn-secondary:#21262d;--btn-secondary-hover:#30363d}body{background-color:var(--bg-primary);color:var(--text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}a,a:hover{text-decoration:none}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}html,body{margin:0;width:100%;height:100%} diff --git a/dist/_astro/Layout.slfrh7tA.css b/dist/_astro/Layout.slfrh7tA.css new file mode 100644 index 0000000..5c621aa --- /dev/null +++ b/dist/_astro/Layout.slfrh7tA.css @@ -0,0 +1 @@ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-4xl:56rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.start{inset-inline-start:var(--spacing)}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.-mx-2{margin-inline:calc(var(--spacing) * -2)}.mx-auto{margin-inline:auto}.my-6{margin-block:calc(var(--spacing) * 6)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-4{margin-left:calc(var(--spacing) * 4)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-3{height:calc(var(--spacing) * 3)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-20{height:calc(var(--spacing) * 20)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-0{width:calc(var(--spacing) * 0)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-20{width:calc(var(--spacing) * 20)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[200px\]{min-width:200px}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-\[\#1f6feb\]\/40{border-color:#1f6feb66}.border-\[\#8b949e\]\/40{border-color:#8b949e66}.border-\[\#388bfd\]\/40{border-color:#388bfd66}.border-\[\#30363d\]{border-color:#30363d}.border-\[\#a5d6ff\]\/40{border-color:#a5d6ff66}.border-\[\#a371f7\]\/40{border-color:#a371f766}.border-\[\#f2cc60\]\/40{border-color:#f2cc6066}.border-\[\#f85149\]\/40{border-color:#f8514966}.bg-\[\#0a3064\]{background-color:#0a3064}.bg-\[\#0d1117\]{background-color:#0d1117}.bg-\[\#1f6feb\]{background-color:#1f6feb}.bg-\[\#1f6feb\]\/20{background-color:#1f6feb33}.bg-\[\#8b949e\]\/20{background-color:#8b949e33}.bg-\[\#58a6ff\]{background-color:#58a6ff}.bg-\[\#161b22\]{background-color:#161b22}.bg-\[\#388bfd\]\/20{background-color:#388bfd33}.bg-\[\#21262d\]{background-color:#21262d}.bg-\[\#a5d6ff\]\/20{background-color:#a5d6ff33}.bg-\[\#a371f7\]\/20{background-color:#a371f733}.bg-\[\#f2cc60\]\/20{background-color:#f2cc6033}.bg-\[\#f85149\]\/20{background-color:#f8514933}.bg-\[\#f8514920\]{background-color:#f8514920}.bg-\[\#ff7b7233\]{background-color:#ff7b7233}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pr-4{padding-right:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-pre{white-space:pre}.text-\[\#3ac840\]{color:#3ac840}.text-\[\#3fb950\]{color:#3fb950}.text-\[\#8b949e\]{color:#8b949e}.text-\[\#58a6ff\]{color:#58a6ff}.text-\[\#79c0ff\]{color:#79c0ff}.text-\[\#388bfd\]{color:#388bfd}.text-\[\#484f58\]{color:#484f58}.text-\[\#30363d\]{color:#30363d}.text-\[\#a5d6ff\]{color:#a5d6ff}.text-\[\#a371f7\]{color:#a371f7}.text-\[\#c9d1d9\]{color:#c9d1d9}.text-\[\#e6edf3\]{color:#e6edf3}.text-\[\#f2cc60\]{color:#f2cc60}.text-\[\#f85149\]{color:#f85149}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.no-underline{text-decoration-line:none}.placeholder-\[\#484f58\]::placeholder{color:#484f58}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-500{--tw-duration:.5s;transition-duration:.5s}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.hover\:bg-\[\#161b22\]:hover{background-color:#161b22}.hover\:bg-\[\#388bfd\]:hover{background-color:#388bfd}.hover\:bg-\[\#30363d\]:hover{background-color:#30363d}.hover\:bg-\[\#f8514930\]:hover{background-color:#f8514930}.hover\:text-\[\#79c0ff\]:hover{color:#79c0ff}.hover\:text-\[\#c9d1d9\]:hover{color:#c9d1d9}.hover\:text-\[\#f85149\]:hover{color:#f85149}}.focus\:border-\[\#58a6ff\]:focus{border-color:#58a6ff}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-0:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-\[\#58a6ff\]:focus{--tw-ring-color:#58a6ff}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-\[\#21262d\]:disabled{background-color:#21262d}.disabled\:text-\[\#484f58\]:disabled{color:#484f58}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:64rem){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:root{--bg-primary:#0d1117;--bg-secondary:#161b22;--bg-tertiary:#21262d;--border-color:#30363d;--text-primary:#c9d1d9;--text-secondary:#8b949e;--text-muted:#6e7681;--blue-900:#0a3064;--blue-800:#1a549d;--blue-700:#1f6feb;--blue-600:#388bfd;--blue-500:#58a6ff;--blue-400:#79c0ff;--blue-300:#a5d6ff;--accent-purple:#a371f7;--accent-orange:#f2cc60;--accent-red:#f85149;--btn-primary:#1f6feb;--btn-primary-hover:#388bfd;--btn-secondary:#21262d;--btn-secondary-hover:#30363d}body{background-color:var(--bg-primary);color:var(--text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}a,a:hover{text-decoration:none}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}html,body{margin:0;width:100%;height:100%} diff --git a/dist/about/index.html b/dist/about/index.html new file mode 100644 index 0000000..161ce07 --- /dev/null +++ b/dist/about/index.html @@ -0,0 +1,8 @@ + PR Dojo - Code Review Practice

About PR Dojo

PR Dojo is a practice platform for developers who want to sharpen their code review skills. We believe that the best way to become a better reviewer is by practicing on real-world code that didn't make it through review. +

Our Mission

+Every day, thousands of pull requests are rejected, revised, or merged with bugs. These rejected PRs contain valuable learning opportunities — real bugs, real edge cases, real design mistakes. PR Dojo curates these mistakes into structured challenges where you can practice identifying issues and writing fixes. +

How It Works

1. Pick a Challenge

Browse our collection of buggy code snippets sourced from real rejected PRs. Each challenge includes a description, difficulty rating, and bug type categorization.

2. Find the Bugs

Review the code carefully, looking for logic errors, security vulnerabilities, performance issues, and style problems. Use hints if you get stuck.

3. Submit Your Fix

Write a patch that resolves the identified issues. Submit your fix and earn XP based on the difficulty and quality of your solution.

Why Practice Code Review?

+Strong code review skills are one of the highest-leverage abilities a developer can have. Reviewing code helps you: +

  • Catch bugs before they reach production
  • Learn new patterns and techniques from others' code
  • Develop a critical eye for edge cases and security issues
  • Improve your own writing by understanding what to avoid
  • Communicate feedback constructively to teammates

Bug Types We Cover

Our challenges span a wide range of common bug categories:

Logic Errors Security Vulnerabilities Performance Issues Edge Cases Type Errors API Misuse Resource Leaks

Get Involved

+PR Dojo is an open project. If you have rejected PRs you'd like to contribute as challenges, or if you want to help build the platform, check out our GitHub repository and open an issue or pull request. +

\ No newline at end of file diff --git a/dist/challenges/1/index.html b/dist/challenges/1/index.html index db9db37..314233a 100644 --- a/dist/challenges/1/index.html +++ b/dist/challenges/1/index.html @@ -1,9 +1,9 @@ - PR Dojo - Code Review Practice -
← Back to Challenges / Challenge #1

Memory Leak in Database Connection

★★★☆☆
📁 facebook/react 🔢 abc1234 Memory Safety
★★★☆☆
Difficulty
+100 XP reward
file.js
1 class DatabaseConnector { -• Line 15: Connection handle not released after use
2 constructor(url) {
3 this.url = url;
4 this.connection = null;
5 }
6
7 connect() {
8 this.connection = createConnection(this.url);
9 }
10
11 query(sql) {
12 return this.connection.execute(sql);
13 }
14
15 disconnect() { -• Connection handle not released after use
16 // Memory leak: connection never closed -• Resource cleanup missing in disconnect method
17 }
18 }

Hints:

  • Line 15: Connection handle not released after use
  • Line 16: Resource cleanup missing in disconnect method
\ No newline at end of file diff --git a/dist/signin/index.html b/dist/signin/index.html new file mode 100644 index 0000000..9a29e06 --- /dev/null +++ b/dist/signin/index.html @@ -0,0 +1,11 @@ + PR Dojo - Code Review Practice

Sign in to PR Dojo

Continue your code review practice

or

+Don't have an account? Sign up

\ No newline at end of file diff --git a/dist/signup/index.html b/dist/signup/index.html new file mode 100644 index 0000000..32beb9b --- /dev/null +++ b/dist/signup/index.html @@ -0,0 +1,9 @@ + PR Dojo - Code Review Practice

Create your account

Join PR Dojo to track your progress and earn XP

or

+Already have an account? Sign in

\ No newline at end of file diff --git a/dist/terms/index.html b/dist/terms/index.html new file mode 100644 index 0000000..e3044f0 --- /dev/null +++ b/dist/terms/index.html @@ -0,0 +1,28 @@ + PR Dojo - Code Review Practice

Terms of Service

+Last updated: April 28, 2026

Acceptance of Terms

+By accessing and using PR Dojo, you accept and agree to be bound by these Terms of Service. If you do not agree to these terms, do not use this service. +

Description of Service

+PR Dojo provides an educational platform for practicing code review skills through interactive challenges. The service includes: +

  • Buggy code challenges sourced from real rejected PRs
  • Hint systems to guide learning
  • XP and ranking systems to track progress
  • Fix submission and review capabilities

User Accounts

+To access certain features, you may need to create an account. You are responsible for maintaining the confidentiality of your account credentials and for all activities under your account. +

Acceptable Use

You agree not to:

  • Use the service for any unlawful purpose
  • Attempt to gain unauthorized access to any part of the service
  • Interfere with or disrupt the service or servers
  • Submit malicious code as fixes
  • Scrape or copy challenge content for redistribution
  • Impersonate another user

Intellectual Property

+All content on PR Dojo, including challenge descriptions, code snippets, hints, and the platform design, is the intellectual property of PR Dojo or its contributors and is protected by copyright and other intellectual property laws. +

+You may not reproduce, distribute, modify, or create derivative works from our content without explicit permission. +

User Submissions

+When you submit fixes or suggestions, you grant PR Dojo a non-exclusive, royalty-free license to use, display, and incorporate your submissions into the platform. You retain ownership of your submissions. +

Disclaimers

+PR Dojo is provided "as is" without warranties of any kind, either express or implied. We do not guarantee that the challenges are free from errors or that the service will be uninterrupted. +

+The code challenges are for educational purposes only. Any real-world code patterns shown may not reflect best practices or current standards. +

Limitation of Liability

+In no event shall PR Dojo or its contributors be liable for any indirect, incidental, special, consequential, or punitive damages arising from your use of the service. +

Termination

+We reserve the right to suspend or terminate accounts that violate these terms, or to discontinue the service entirely, with or without notice. +

Changes to Terms

+We may modify these Terms at any time. Continued use of the service after changes constitutes acceptance of the new terms. +

Governing Law

+These Terms shall be governed by and construed in accordance with the laws of your jurisdiction, without regard to conflict of law principles. +

Contact

+For questions about these Terms, contact us at: +

legal@prdojo.example.com

\ No newline at end of file diff --git a/src/components/DiffViewer.astro b/src/components/DiffViewer.astro index 774016c..024dffd 100644 --- a/src/components/DiffViewer.astro +++ b/src/components/DiffViewer.astro @@ -31,16 +31,16 @@ const lines = code.split('\n'); title={`Mark line ${lineNum} as buggy`} > - + {lineNum} - + {line || ' '} {hasHint && ( - + )} @@ -52,19 +52,7 @@ const lines = code.split('\n');
- {hints.length > 0 && ( -
-

Hints:

-
    - {hints.map((hint) => ( -
  • - - {hint} -
  • - ))} -
-
- )} + @@ -87,6 +75,19 @@ const lines = code.split('\n'); tr.bugged { background-color: #f8514918; } + .diff-viewer-container:not(.revealed) tr.bugged .line-number.has-hint-color { + color: #f85149 !important; + } + .diff-viewer-container:not(.revealed) tr:not(.bugged) span.line-number.has-hint-color { + color: #8b949e !important; + font-weight: normal !important; + } + .diff-viewer-container.revealed tr.bugged .hint { + display: inline; + } + .diff-viewer-container:not(.revealed) td > span.has-hint-bg { + background-color: transparent !important; + } diff --git a/src/pages/signin.astro b/src/pages/signin.astro new file mode 100644 index 0000000..631c585 --- /dev/null +++ b/src/pages/signin.astro @@ -0,0 +1,108 @@ +--- +import Layout from '../layouts/Layout.astro'; +--- + + +
+ +
+ +
+ +
+
+
+
+

Sign in to PR Dojo

+

Continue your code review practice

+
+ +
{ e.preventDefault(); alert('Sign in is not available yet. Backend API is not implemented.'); }}> + +
+ + +
+ + +
+ + +
+ + +
+ + + Forgot password? + +
+ + + +
+ + +
+
+ or +
+
+ + + + + +

+ Don't have an account? Sign up +

+
+
+
+
+
diff --git a/src/pages/signup.astro b/src/pages/signup.astro new file mode 100644 index 0000000..b856397 --- /dev/null +++ b/src/pages/signup.astro @@ -0,0 +1,121 @@ +--- +import Layout from '../layouts/Layout.astro'; +--- + + +
+ +
+ +
+ +
+
+
+
+

Create your account

+

Join PR Dojo to track your progress and earn XP

+
+ +
{ e.preventDefault(); alert('Sign up is not available yet. Backend API is not implemented.'); }}> + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + +
+ + +
+
+ or +
+
+ + + + + +

+ Already have an account? Sign in +

+
+
+
+
+
diff --git a/src/pages/terms.astro b/src/pages/terms.astro new file mode 100644 index 0000000..6ecd8e1 --- /dev/null +++ b/src/pages/terms.astro @@ -0,0 +1,94 @@ +--- +import Layout from '../layouts/Layout.astro'; +--- + + +
+

Terms of Service

+ +
+

+ Last updated: {new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })} +

+ +

Acceptance of Terms

+

+ By accessing and using PR Dojo, you accept and agree to be bound by these Terms of Service. If you do not agree to these terms, do not use this service. +

+ +

Description of Service

+

+ PR Dojo provides an educational platform for practicing code review skills through interactive challenges. The service includes: +

+
    +
  • Buggy code challenges sourced from real rejected PRs
  • +
  • Hint systems to guide learning
  • +
  • XP and ranking systems to track progress
  • +
  • Fix submission and review capabilities
  • +
+ +

User Accounts

+

+ To access certain features, you may need to create an account. You are responsible for maintaining the confidentiality of your account credentials and for all activities under your account. +

+ +

Acceptable Use

+

You agree not to:

+
    +
  • Use the service for any unlawful purpose
  • +
  • Attempt to gain unauthorized access to any part of the service
  • +
  • Interfere with or disrupt the service or servers
  • +
  • Submit malicious code as fixes
  • +
  • Scrape or copy challenge content for redistribution
  • +
  • Impersonate another user
  • +
+ +

Intellectual Property

+

+ All content on PR Dojo, including challenge descriptions, code snippets, hints, and the platform design, is the intellectual property of PR Dojo or its contributors and is protected by copyright and other intellectual property laws. +

+

+ You may not reproduce, distribute, modify, or create derivative works from our content without explicit permission. +

+ +

User Submissions

+

+ When you submit fixes or suggestions, you grant PR Dojo a non-exclusive, royalty-free license to use, display, and incorporate your submissions into the platform. You retain ownership of your submissions. +

+ +

Disclaimers

+

+ PR Dojo is provided "as is" without warranties of any kind, either express or implied. We do not guarantee that the challenges are free from errors or that the service will be uninterrupted. +

+

+ The code challenges are for educational purposes only. Any real-world code patterns shown may not reflect best practices or current standards. +

+ +

Limitation of Liability

+

+ In no event shall PR Dojo or its contributors be liable for any indirect, incidental, special, consequential, or punitive damages arising from your use of the service. +

+ +

Termination

+

+ We reserve the right to suspend or terminate accounts that violate these terms, or to discontinue the service entirely, with or without notice. +

+ +

Changes to Terms

+

+ We may modify these Terms at any time. Continued use of the service after changes constitutes acceptance of the new terms. +

+ +

Governing Law

+

+ These Terms shall be governed by and construed in accordance with the laws of your jurisdiction, without regard to conflict of law principles. +

+ +

Contact

+

+ For questions about these Terms, contact us at: +

+

legal@prdojo.example.com

+
+
+