diff --git a/package.json b/package.json
index 6ffb430..b365661 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-hover-card": "^1.1.15",
+ "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tabs": "^1.1.13",
"@tanstack/react-query": "^5.85.5",
@@ -53,6 +54,8 @@
"jotai": "^2.13.1",
"lucide-react": "^0.542.0",
"next": "15.5.2",
+ "next-themes": "^0.4.6",
+ "parse-git-diff": "^0.0.19",
"prexit": "^2.3.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
@@ -60,6 +63,7 @@
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^15.6.6",
"remark-gfm": "^4.0.1",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"ulid": "^3.0.1",
"zod": "^4.1.5"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6badbfa..8ba52a2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -29,6 +29,9 @@ importers:
'@radix-ui/react-hover-card':
specifier: ^1.1.15
version: 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-select':
+ specifier: ^2.2.6
+ version: 2.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
'@radix-ui/react-slot':
specifier: ^1.2.3
version: 1.2.3(@types/react@19.1.12)(react@19.1.1)
@@ -56,6 +59,12 @@ importers:
next:
specifier: 15.5.2
version: 15.5.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ next-themes:
+ specifier: ^0.4.6
+ version: 0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ parse-git-diff:
+ specifier: ^0.0.19
+ version: 0.0.19
prexit:
specifier: ^2.3.0
version: 2.3.0
@@ -77,6 +86,9 @@ importers:
remark-gfm:
specifier: ^4.0.1
version: 4.0.1
+ sonner:
+ specifier: ^2.0.7
+ version: 2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
tailwind-merge:
specifier: ^3.3.1
version: 3.3.1
@@ -842,6 +854,9 @@ packages:
resolution: {integrity: sha512-7J6ca1tK0duM2BgVB+CuFMh3idlIVASOP2QvOCbNWDc6JnvjtKa9nufPoJQQ4xrwBonwgT1TIhRRcEtzdVgWsA==}
engines: {node: ^20.9.0 || >=22.0.0, npm: '>=10.8.2'}
+ '@radix-ui/number@1.1.1':
+ resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
+
'@radix-ui/primitive@1.1.3':
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
@@ -1072,6 +1087,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-select@2.2.6':
+ resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-slot@1.2.3':
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
peerDependencies:
@@ -1175,6 +1203,19 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-visually-hidden@1.2.3':
+ resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/rect@1.1.1':
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
@@ -2517,6 +2558,12 @@ packages:
resolution: {integrity: sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ next-themes@0.4.6:
+ resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
+ peerDependencies:
+ react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
next@15.5.2:
resolution: {integrity: sha512-H8Otr7abj1glFhbGnvUt3gz++0AF1+QoCXEBmd/6aKbfdFwrn0LpA836Ed5+00va/7HQSDD+mOoVhn3tNy3e/Q==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
@@ -2618,6 +2665,9 @@ packages:
parse-entities@4.0.2:
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
+ parse-git-diff@0.0.19:
+ resolution: {integrity: sha512-oh3giwKzsPlOhekiDDyd/pfFKn04IZoTjEThquhfKigwiUHymiP/Tp6AN5nGIwXQdWuBTQvz9AaRdN5TBsJ8MA==}
+
parse-ms@4.0.0:
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
engines: {node: '>=18'}
@@ -2883,6 +2933,12 @@ packages:
resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==}
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
+ sonner@2.0.7:
+ resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
+ peerDependencies:
+ react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -3800,6 +3856,8 @@ snapshots:
'@phun-ky/typeof@1.2.8': {}
+ '@radix-ui/number@1.1.1': {}
+
'@radix-ui/primitive@1.1.3': {}
'@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
@@ -4026,6 +4084,35 @@ snapshots:
'@types/react': 19.1.12
'@types/react-dom': 19.1.9(@types/react@19.1.12)
+ '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ dependencies:
+ '@radix-ui/number': 1.1.1
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.12)(react@19.1.1)
+ '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ aria-hidden: 1.2.6
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+ react-remove-scroll: 2.7.1(@types/react@19.1.12)(react@19.1.1)
+ optionalDependencies:
+ '@types/react': 19.1.12
+ '@types/react-dom': 19.1.9(@types/react@19.1.12)
+
'@radix-ui/react-slot@1.2.3(@types/react@19.1.12)(react@19.1.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1)
@@ -4110,6 +4197,15 @@ snapshots:
optionalDependencies:
'@types/react': 19.1.12
+ '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+ optionalDependencies:
+ '@types/react': 19.1.12
+ '@types/react-dom': 19.1.9(@types/react@19.1.12)
+
'@radix-ui/rect@1.1.1': {}
'@rollup/rollup-android-arm-eabi@4.49.0':
@@ -5567,6 +5663,11 @@ snapshots:
dependencies:
type-fest: 2.19.0
+ next-themes@0.4.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+
next@15.5.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
dependencies:
'@next/env': 15.5.2
@@ -5714,6 +5815,8 @@ snapshots:
is-decimal: 2.0.1
is-hexadecimal: 2.0.1
+ parse-git-diff@0.0.19: {}
+
parse-ms@4.0.0: {}
parse-path@7.1.0:
@@ -6078,6 +6181,11 @@ snapshots:
ip-address: 10.0.1
smart-buffer: 4.2.0
+ sonner@2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+
source-map-js@1.2.1: {}
source-map-support@0.5.21:
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 9b74311..0aa6bf9 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
+import { Toaster } from "../components/ui/sonner";
import { QueryClientProviderWrapper } from "../lib/api/QueryClientProviderWrapper";
import { RootErrorBoundary } from "./components/RootErrorBoundary";
import { ServerEventsProvider } from "./components/ServerEventsProvider";
@@ -47,6 +48,7 @@ export default async function RootLayout({
{children}
+