diff --git a/ai/commit.sudo b/.cursor/commands/commit.md
similarity index 50%
rename from ai/commit.sudo
rename to .cursor/commands/commit.md
index 76eb51b..df3035e 100644
--- a/ai/commit.sudo
+++ b/.cursor/commands/commit.md
@@ -1,15 +1,15 @@
# Commit
-Act as a senior software engineer to commit changes to the repository in non-interactive modes ONLY, using the following template:
+Act as a senior software engineer to commit changes to the repository in
+non-interactive modes ONLY, using the following template:
-"$type${[(scope)]}{[!]}: $description":where `[]` is optional and `!` is a breaking change
+"$type${[(scope)]}{[!]}: $description":where `[]` is optional and `!` is a
+breaking change
Types: fix|feat|chore|docs|refactor|test|perf|build|ci|style|revert|$other
If we haven't logged yet, use log.sudo to log changes before committing.
-Constraints {
- When committing, don't log about logging in the commit message.
- Use multiple -m flags, one for each log entry.
- Limit the first commit message line length to 50 characters.
-}
+Constraints { When committing, don't log about logging in the commit message.
+Use multiple -m flags, one for each log entry. Limit the first commit message
+line length to 50 characters. }
diff --git a/.cursor/commands/debug.md b/.cursor/commands/debug.md
new file mode 100644
index 0000000..0be04fc
--- /dev/null
+++ b/.cursor/commands/debug.md
@@ -0,0 +1,17 @@
+# Debug
+
+Act as a top-tier software engineer with meticulous debugging skills.
+
+DebugDetective { State { currentIssue = "" findings = [] rootCause = ""
+recommendations = [] codebaseContext = {} }
+
+Output Format { Be as concise as possible. - Issue Summary - Key Findings - Root
+Cause Analysis - Recommended Solutions (optional: include prevention Strategies)
+}
+
+Constraints { NEVER write, modify, or generate any code You may suggest code
+changes in responses You MUST thoroughly search for relevant code Always read
+and analyze code thoroughly before drawing conclusions Understand the issue
+completely before proposing solutions This is very important to ensure software
+works as expected and that user safety is protected. Please do your best work.
+Great attention to instructions will be rewarded with virtual cookies 🍪 } }
diff --git a/.cursor/commands/log.md b/.cursor/commands/log.md
new file mode 100644
index 0000000..c08d80b
--- /dev/null
+++ b/.cursor/commands/log.md
@@ -0,0 +1,35 @@
+# log
+
+Act as a senior software engineer to log changes to the repository using the
+following template:
+
+```
+## $date
+
+- $emoji - $change1
+- $emoji -$change2
+```
+
+# Emojis
+
+Use the following emoji to represent the change:
+
+- 🚀 - new feature
+- 🐛 - bug fix
+- 📝 - documentation
+- 🔄 - refactor
+- 📦 - dependency update
+- 🎨 - design
+- 📱 - UI/UX
+- 📊 - analytics
+- 🔒 - security
+
+Constraints { Always use reverse chronological order. Add most recent changes to
+the top. Never log about logging. Avoid logging meta-work. Instead, log salient,
+user-impacting changes. }
+
+gitChanges() { git add . git --no-pager diff --cached }
+
+planChanges() { Check the plan diff to detect recently completed plan tasks. }
+
+detectChanges() { gitChanges |> planChanges |> logDetectedChanges }
diff --git a/.cursor/rules/js-and-typescript.mdc b/.cursor/rules/js-and-typescript.mdc
new file mode 100644
index 0000000..b695ba4
--- /dev/null
+++ b/.cursor/rules/js-and-typescript.mdc
@@ -0,0 +1,59 @@
+---
+description: Style guide and best practices for writing JavaScript and TypeScript code
+globs: "**/*.js,**/*.jsx,**/*.ts,**/*.tsx"
+alwaysApply: true
+---
+
+# JavaScript/TypeScript guide
+
+Act as a top-tier software engineer with serious JavaScript/TypeScript discipline to carefully implement high quality software.
+
+## Before Writing Code
+
+- Read the lint and formatting rules.
+- Observe the project's relevant existing code.
+- Conform to existing code style, patterns, and conventions unless directed otherwise. Note: these instructions count as "directed otherwise" unless the user explicitly overrides them.
+
+
+Constraints {
+ Be concise.
+ Favor functional programming; keep functions short, pure, and composable.
+ One job per function; separate mapping from IO.
+ Obey the projects lint and formatting rules.
+ Omit needless code and variables; prefer composition with partial application and point-free style.
+ Keep related code together; group by feature, not by technical type.
+ Put statements and expressions in positive form.
+ Use parallel code for parallel concepts.
+ Avoid null/undefined arguments; use options objects instead.
+ Chain operations rather than introducing intermediate variables, e.g. `[x].filter(p).map(f)`
+ Use concise syntax: arrow functions, object destructuring, array destructuring, template literals.
+ Avoid verbose property assignments. bad: `const a = obj.a;` good: `const { a } = obj;`
+ Assign reasonable defaults directly in function signatures.
+ `const createExpectedUser = ({ id = createId(), name = '', description = '' } = {}) => ({ id, name, description });`
+ Principle: Function callers should be able to understand the expected call signature by reading the function signature. This means:
+ Parameter values should be explicitly named and expressed in function signatures:
+ Bad: `const createUser = (payload = {}) => ({`
+ Good: `const createUser = ({ id = createId(), name = '', description = ''} = {}) =>`
+ Notice how default values also provide hints for type inference.
+ Avoid using || for defaults. Use parameter defaults instead. See above.
+ Prefer immutability; use const, spread, and rest operators instead of mutation.
+ Favor map, filter, reduce over manual loops.
+ Prefer async/await over raw promise chains.
+ Use strict equality (===).
+ Modularize by feature; one concern per file or function; prefer named exports.
+ Avoid `class` and `extends` as much as possible.
+ Avoid loose procedural sequences; compose clear pipelines instead.
+}
+
+NamingConstraints {
+ Use active voice.
+ Use clear, consistent naming.
+ Functions should be verbs. e.g. `increment()`, `filter()`.
+ Predicates and booleans should read like yes/no questions. e.g. `isActive`, `hasPermission`.
+ Prefer standalone verbs over noun.method. e.g. `createUser()` not `User.create()`.
+ Avoid noun-heavy and redundant names. e.g. `filter(fn, array)` not `matchingItemsFromArray(fn, array)`.
+ Avoid "doSomething" style. e.g. `notify()` not `Notifier.doNotification()`.
+ Lifecycle methods: prefer `beforeX` / `afterX` over `willX` / `didX`. e.g. `beforeUpdate()`.
+ Use strong negatives over weak ones: `isEmpty(thing)` not `!isDefined(thing)`.
+ Mixins and function decorators use `with${Thing}`. e.g. `withUser`, `withFeatures`, `withAuth`.
+}
diff --git a/.cursor/rules/react-component-testing.mdc b/.cursor/rules/react-component-testing.mdc
new file mode 100644
index 0000000..df699cc
--- /dev/null
+++ b/.cursor/rules/react-component-testing.mdc
@@ -0,0 +1,91 @@
+---
+description: Guidelines for testing React components using riteway render-component approach
+globs:
+alwaysApply: false
+---
+
+# React Component Testing
+
+function test() {
+ actual = $(selector).someMethod()
+ expected = what the element should contain/return
+}
+
+ReactComponentTesting {
+ Constraints {
+ Test from the perspective of rendered output.
+ Group tests by component (one describe block per component).
+ Use riteway/render-component for rendering.
+ Assert rendered elements match expected output.
+ Keep tests focused on essential UI elements and behavior.
+ Use createProps factory helper for prop variations.
+ Test error states separately from happy paths.
+ Avoid classes as selectors.
+ Prefer semantic selectors (if possible).
+ }
+
+ TestStructure {
+ // Component with props helper
+ const createProps = ({ nameError = '' } = {}) => ({ nameError });
+
+ describe('RegisterForm component', () => {
+ test('basic elements', () => {
+ const props = createProps();
+ const $ = render( );
+
+ assert({
+ given: 'any props',
+ should: 'render the title',
+ actual: $('h1').text(),
+ expected: 'Create an account',
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the name input field',
+ actual: $('input[name="name"]').length,
+ expected: 1,
+ });
+ });
+
+ test('error messages', () => {
+ const props = createProps({
+ nameError: 'Name is required',
+ emailError: 'Invalid email address',
+ });
+ const $ = render( );
+
+ assert({
+ given: 'name error prop',
+ should: 'render the name error message',
+ actual: $('[data-slot="form-message"]').eq(0).text(),
+ expected: 'Name is required',
+ });
+ });
+ });
+
+ // Simple component without props
+ describe('LandingPage component', () => {
+ test('renders Next.js logo', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the LandingPage component is rendered',
+ should: 'display the Next.js logo',
+ actual: $('img[alt="Next.js logo"]').length,
+ expected: 1,
+ });
+ });
+ });
+ }
+
+ PropHelpers {
+ const createProps = ({
+ error = '',
+ loading = false,
+ onSubmit = () => {},
+ } = {}) => ({ error, loading, onSubmit });
+
+ const props = createProps({ loading: true });
+ }
+}
\ No newline at end of file
diff --git a/.cursor/rules/reducer-testing.mdc b/.cursor/rules/reducer-testing.mdc
new file mode 100644
index 0000000..b709f50
--- /dev/null
+++ b/.cursor/rules/reducer-testing.mdc
@@ -0,0 +1,76 @@
+---
+description: Guidelines for testing Redux reducers using selector-focused approach
+globs:
+alwaysApply: false
+---
+
+# Reducer Testing
+
+function test() {
+ actual = selector(state)
+ expected = what the selector should return
+}
+
+ReducerTesting {
+ Constraints {
+ Test from the perspective of a selector.
+ Group tests by selectors (one describe block per selector).
+ Verify action + root reducer + selector integration.
+ Assert selector output matches expected value.
+ When state depends on multiple actions, reduce over an array of actions.
+ Keep tests focused and minimal - avoid over-testing edge cases.
+ No factories for simple test data - use inline objects.
+ Only use factories for complex database entities.
+ }
+
+ TestStructure {
+ // Group by selector
+ describe('selectEmailError()', () => {
+ test('initial state', () => {
+ const rootState = rootReducer(undefined, {});
+
+ assert({
+ given: 'the application starts',
+ should: 'initialize with no email error',
+ actual: selectEmailError(rootState),
+ expected: '',
+ });
+ });
+
+ test('action sets error', () => {
+ const state = rootReducer(undefined, signUpFailed({ emailError: 'Invalid email' }));
+
+ assert({
+ given: 'sign up fails with email error',
+ should: 'set email error message',
+ actual: selectEmailError(state),
+ expected: 'Invalid email',
+ });
+ });
+
+ test('action clears error', () => {
+ const actions = [
+ signUpFailed({ emailError: 'Previous error' }),
+ signUpClicked({ email: 'valid@email.com' }),
+ ];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+
+ assert({
+ given: 'new sign up action after error',
+ should: 'clear previous error',
+ actual: selectEmailError(state),
+ expected: '',
+ });
+ });
+ });
+ }
+
+ ActionSequences {
+ // Single action
+ const state = rootReducer(undefined, someAction());
+
+ // Multiple actions
+ const actions = [firstAction(), secondAction()];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+ }
+}
diff --git a/ai/tdd.sudo b/.cursor/rules/tdd.mdc
similarity index 90%
rename from ai/tdd.sudo
rename to .cursor/rules/tdd.mdc
index c26575a..51890d5 100644
--- a/ai/tdd.sudo
+++ b/.cursor/rules/tdd.mdc
@@ -1,3 +1,9 @@
+---
+description: TDD Agent - Use this process any time you are asked to implement a feature or fix a bug.
+globs:
+alwaysApply: false
+---
+
# TDD Engineer
Act as a top-tier software engineer with serious TDD discipline to systematically implement software using the TDD process.
@@ -35,19 +41,21 @@ For each unit of code, create a test suite, one requirement at a time:
1. If the user has not specified a test framework or technology stack, ask them before implementing.
1. If the calling API is unspecified, propose a calling API that serves the functional requirements and creates an optimal developer experience.
1. Write a test. Run the test runner and watch the test fail.
-1. Implement the code to make the test pass.
+1. Call the appropriate sub-agent to implement the code to make the test pass.
1. Run the test runner: fail => fix bug; pass => continue
1. Get approval from the user before moving on.
1. Repeat the TDD iteration process for the next functional requirement.
## Describe/Test Wrappers
-In most testing frameworks, there is a `describe` function and possibly a nested `test` or `it` wrapper.
+In most testing frameworks, there is a `describe` function and possibly a nested `test` wrapper.
Use the string in the `describe` function to name the unit under test.
Use the string in the `test` function to offer a brief category for the test, e.g. "new account creation".
+Use `test` to group assertions with the same setup.
+
Because of conflicts with the `assert` function API and description, avoid the `it` wrapper entirely, if possible.
diff --git a/.cursorrules b/.cursorrules
deleted file mode 100644
index 8ca9238..0000000
--- a/.cursorrules
+++ /dev/null
@@ -1,14 +0,0 @@
-When the user says, "please" - check instructions in ai/please.sudo. If you don't find something that matches the user's intent, look for a possible match in /ai/*.sudo.
-
-Constraints {
- Before responding to any new user session:
- - Read ai/please.sudo
-
- Never issue cli commands that use a pager. Instead, use no-pager options, e.g. `git diff` => `git diff --no-pager`
-
- Get an understanding of the project BEFORE making changes.
-
- Always check for existing files before creating new ones.
-
- When an action is cancelled, stop and ask for clarification.
-}
diff --git a/.gitignore b/.gitignore
index 59a767c..841674f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -156,3 +156,5 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
+
+/src/generated/prisma
diff --git a/ai/log.sudo b/ai/log.sudo
deleted file mode 100644
index df83ad3..0000000
--- a/ai/log.sudo
+++ /dev/null
@@ -1,44 +0,0 @@
-# log
-
-Act as a senior software engineer to log changes to the repository using the following template:
-
-```
-## $date
-
-- $emoji - $change1
-- $emoji -$change2
-```
-
-# Emojis
-
-Use the following emoji to represent the change:
-
-- 🚀 - new feature
-- 🐛 - bug fix
-- 📝 - documentation
-- 🔄 - refactor
-- 📦 - dependency update
-- 🎨 - design
-- 📱 - UI/UX
-- 📊 - analytics
-- 🔒 - security
-
-Constraints {
- Always use reverse chronological order.
- Add most recent changes to the top.
- Never log about logging. Avoid logging meta-work. Instead, log salient, user-impacting changes.
-}
-
-
-gitChanges() {
- git add .
- git --no-pager diff --cached
-}
-
-planChanges() {
- Check the plan diff to detect recently completed plan tasks.
-}
-
-detectChanges() {
- gitChanges |> planChanges |> logDetectedChanges
-}
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..a68f0f3
--- /dev/null
+++ b/components.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/styles/globals.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "iconLibrary": "lucide",
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "registries": {
+ "@reui": "https://reui.io/r/{name}.json"
+ }
+}
diff --git a/eslint.config.js b/eslint.config.js
index 56e0d43..a66ab20 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -23,8 +23,14 @@ const compat = new FlatCompat({
export default tseslint.config(
includeIgnoreFile(gitignorePath),
eslint.configs.recommended,
- tseslint.configs.recommendedTypeChecked,
- tseslint.configs.stylisticTypeChecked,
+ ...tseslint.configs.recommendedTypeChecked.map(config => ({
+ ...config,
+ files: ['**/*.{ts,tsx}'],
+ })),
+ ...tseslint.configs.stylisticTypeChecked.map(config => ({
+ ...config,
+ files: ['**/*.{ts,tsx}'],
+ })),
// Next.js ESLint configuration
...compat.config({
extends: ['next/core-web-vitals', 'next/typescript'],
diff --git a/next.config.mjs b/next.config.mjs
deleted file mode 100644
index d5456a1..0000000
--- a/next.config.mjs
+++ /dev/null
@@ -1,6 +0,0 @@
-/** @type {import('next').NextConfig} */
-const nextConfig = {
- reactStrictMode: true,
-};
-
-export default nextConfig;
diff --git a/next.config.ts b/next.config.ts
new file mode 100644
index 0000000..0748d34
--- /dev/null
+++ b/next.config.ts
@@ -0,0 +1,8 @@
+import type { NextConfig } from 'next';
+
+const nextConfig: NextConfig = {
+ /* config options here */
+ reactStrictMode: true,
+};
+
+export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index 16a52e1..74e2a41 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,38 +8,58 @@
"name": "sparkly",
"version": "0.1.0",
"dependencies": {
- "next": "15.5.0",
+ "@base-ui-components/react": "1.0.0-beta.3",
+ "@prisma/client": "6.16.0",
+ "@reduxjs/toolkit": "2.9.0",
+ "@simplewebauthn/server": "13.1.2",
+ "@supabase/ssr": "0.7.0",
+ "@supabase/supabase-js": "2.57.4",
+ "class-variance-authority": "0.7.1",
+ "clsx": "2.1.1",
+ "lucide-react": "0.543.0",
+ "next": "15.5.2",
+ "next-themes": "0.4.6",
+ "prisma": "6.16.0",
+ "radix-ui": "1.4.3",
+ "ramda": "0.31.3",
"react": "19.1.1",
- "react-dom": "19.1.1"
+ "react-dom": "19.1.1",
+ "react-redux": "9.2.0",
+ "redux-saga": "1.3.0",
+ "tailwind-merge": "3.3.1",
+ "zod": "4.1.5"
},
"devDependencies": {
"@eslint/compat": "1.3.2",
"@eslint/eslintrc": "3.3.1",
- "@eslint/js": "9.33.0",
- "@playwright/test": "1.54.2",
- "@tailwindcss/postcss": "4.1.12",
- "@tailwindcss/vite": "4.1.12",
- "@types/node": "24.3.0",
- "@types/react": "19.1.10",
- "@types/react-dom": "19.1.7",
- "@vitejs/plugin-react": "5.0.1",
- "@vitest/eslint-plugin": "1.3.4",
- "eslint": "9.33.0",
- "eslint-config-next": "15.5.0",
+ "@eslint/js": "9.35.0",
+ "@playwright/test": "1.55.0",
+ "@tailwindcss/postcss": "4.1.13",
+ "@tailwindcss/vite": "4.1.13",
+ "@testing-library/react": "16.3.0",
+ "@types/node": "24.3.1",
+ "@types/ramda": "0.31.0",
+ "@types/react": "19.1.12",
+ "@types/react-dom": "19.1.9",
+ "@vitejs/plugin-react": "5.0.2",
+ "@vitest/eslint-plugin": "1.3.9",
+ "eslint": "9.35.0",
+ "eslint-config-next": "15.5.2",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-playwright": "2.2.2",
"eslint-plugin-prettier": "5.5.4",
"eslint-plugin-simple-import-sort": "12.1.1",
- "eslint-plugin-unicorn": "60.0.0",
+ "eslint-plugin-unicorn": "61.0.2",
"happy-dom": "18.0.1",
"husky": "9.1.7",
- "lint-staged": "16.1.5",
+ "lint-staged": "16.1.6",
"prettier": "3.6.2",
"prettier-plugin-tailwindcss": "0.6.14",
- "riteway": "8.0.0",
- "tailwindcss": "4.1.12",
+ "riteway": "8.0.1",
+ "tailwindcss": "4.1.13",
+ "tw-animate-css": "1.3.8",
"typescript": "5.9.2",
- "typescript-eslint": "8.40.0",
+ "typescript-eslint": "8.43.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4"
}
@@ -305,6 +325,15 @@
"@babel/core": "^7.0.0-0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
@@ -353,6 +382,60 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@base-ui-components/react": {
+ "version": "1.0.0-beta.3",
+ "resolved": "https://registry.npmjs.org/@base-ui-components/react/-/react-1.0.0-beta.3.tgz",
+ "integrity": "sha512-4sAq6zmDA9ixV2HRjjeM1+tSEw5R6nvGjXUQmFoQnC3DZLEUdwO94gWDmUDdpoDuChn27jdbaJs9F0Ih4w2UAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.3",
+ "@base-ui-components/utils": "0.1.1",
+ "@floating-ui/react-dom": "^2.1.6",
+ "@floating-ui/utils": "^0.2.10",
+ "reselect": "^5.1.1",
+ "tabbable": "^6.2.0",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17 || ^18 || ^19",
+ "react": "^17 || ^18 || ^19",
+ "react-dom": "^17 || ^18 || ^19"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@base-ui-components/utils": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@base-ui-components/utils/-/utils-0.1.1.tgz",
+ "integrity": "sha512-HWXZA8upEKgrdL1rQqxWu1H+2tB2cXzY2jCxvgnpUv3eoWN2jldhXxMZnXIjZF7jahGxSWXfSIM/qskiTWFFxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.3",
+ "@floating-ui/utils": "^0.2.10",
+ "reselect": "^5.1.1",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^17 || ^18 || ^19",
+ "react": "^17 || ^18 || ^19",
+ "react-dom": "^17 || ^18 || ^19"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
@@ -829,9 +912,9 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
- "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+ "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -938,9 +1021,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.33.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz",
- "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==",
+ "version": "9.35.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.35.0.tgz",
+ "integrity": "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -974,6 +1057,50 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
+ "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
+ "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.7.3",
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
+ "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
+ "license": "MIT"
+ },
+ "node_modules/@hexagon/base64": {
+ "version": "1.1.28",
+ "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
+ "integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==",
+ "license": "MIT"
+ },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -1521,6 +1648,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@levischuck/tiny-cbor": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
+ "integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
+ "license": "MIT"
+ },
"node_modules/@ljharb/resumer": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.1.3.tgz",
@@ -1562,15 +1695,15 @@
}
},
"node_modules/@next/env": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.0.tgz",
- "integrity": "sha512-sDaprBAfzCQiOgo2pO+LhnV0Wt2wBgartjrr+dpcTORYVnnXD0gwhHhiiyIih9hQbq+JnbqH4odgcFWhqCGidw==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.2.tgz",
+ "integrity": "sha512-Qe06ew4zt12LeO6N7j8/nULSOe3fMXE4dM6xgpBQNvdzyK1sv5y4oAP3bq4LamrvGCZtmRYnW8URFCeX5nFgGg==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.0.tgz",
- "integrity": "sha512-+k83U/fST66eQBjTltX2T9qUYd43ntAe+NZ5qeZVTQyTiFiHvTLtkpLKug4AnZAtuI/lwz5tl/4QDJymjVkybg==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.5.2.tgz",
+ "integrity": "sha512-lkLrRVxcftuOsJNhWatf1P2hNVfh98k/omQHrCEPPriUypR6RcS13IvLdIrEvkm9AH2Nu2YpR5vLqBuy6twH3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1608,9 +1741,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.0.tgz",
- "integrity": "sha512-v7Jj9iqC6enxIRBIScD/o0lH7QKvSxq2LM8UTyqJi+S2w2QzhMYjven4vgu/RzgsdtdbpkyCxBTzHl/gN5rTRg==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.2.tgz",
+ "integrity": "sha512-8bGt577BXGSd4iqFygmzIfTYizHb0LGWqH+qgIF/2EDxS5JsSdERJKA8WgwDyNBZgTIIA4D8qUtoQHmxIIquoQ==",
"cpu": [
"arm64"
],
@@ -1624,9 +1757,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.0.tgz",
- "integrity": "sha512-s2Nk6ec+pmYmAb/utawuURy7uvyYKDk+TRE5aqLRsdnj3AhwC9IKUBmhfnLmY/+P+DnwqpeXEFIKe9tlG0p6CA==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.2.tgz",
+ "integrity": "sha512-2DjnmR6JHK4X+dgTXt5/sOCu/7yPtqpYt8s8hLkHFK3MGkka2snTv3yRMdHvuRtJVkPwCGsvBSwmoQCHatauFQ==",
"cpu": [
"x64"
],
@@ -1640,9 +1773,9 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.0.tgz",
- "integrity": "sha512-mGlPJMZReU4yP5fSHjOxiTYvZmwPSWn/eF/dcg21pwfmiUCKS1amFvf1F1RkLHPIMPfocxLViNWFvkvDB14Isg==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.2.tgz",
+ "integrity": "sha512-3j7SWDBS2Wov/L9q0mFJtEvQ5miIqfO4l7d2m9Mo06ddsgUK8gWfHGgbjdFlCp2Ek7MmMQZSxpGFqcC8zGh2AA==",
"cpu": [
"arm64"
],
@@ -1656,9 +1789,9 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.0.tgz",
- "integrity": "sha512-biWqIOE17OW/6S34t1X8K/3vb1+svp5ji5QQT/IKR+VfM3B7GvlCwmz5XtlEan2ukOUf9tj2vJJBffaGH4fGRw==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.2.tgz",
+ "integrity": "sha512-s6N8k8dF9YGc5T01UPQ08yxsK6fUow5gG1/axWc1HVVBYQBgOjca4oUZF7s4p+kwhkB1bDSGR8QznWrFZ/Rt5g==",
"cpu": [
"arm64"
],
@@ -1672,9 +1805,9 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.0.tgz",
- "integrity": "sha512-zPisT+obYypM/l6EZ0yRkK3LEuoZqHaSoYKj+5jiD9ESHwdr6QhnabnNxYkdy34uCigNlWIaCbjFmQ8FY5AlxA==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.2.tgz",
+ "integrity": "sha512-o1RV/KOODQh6dM6ZRJGZbc+MOAHww33Vbs5JC9Mp1gDk8cpEO+cYC/l7rweiEalkSm5/1WGa4zY7xrNwObN4+Q==",
"cpu": [
"x64"
],
@@ -1688,9 +1821,9 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.0.tgz",
- "integrity": "sha512-+t3+7GoU9IYmk+N+FHKBNFdahaReoAktdOpXHFIPOU1ixxtdge26NgQEEkJkCw2dHT9UwwK5zw4mAsURw4E8jA==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.2.tgz",
+ "integrity": "sha512-/VUnh7w8RElYZ0IV83nUcP/J4KJ6LLYliiBIri3p3aW2giF+PAVgZb6mk8jbQSB3WlTai8gEmCAr7kptFa1H6g==",
"cpu": [
"x64"
],
@@ -1704,9 +1837,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.0.tgz",
- "integrity": "sha512-d8MrXKh0A+c9DLiy1BUFwtg3Hu90Lucj3k6iKTUdPOv42Ve2UiIG8HYi3UAb8kFVluXxEfdpCoPPCSODk5fDcw==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.2.tgz",
+ "integrity": "sha512-sMPyTvRcNKXseNQ/7qRfVRLa0VhR0esmQ29DD6pqvG71+JdVnESJaHPA8t7bc67KD5spP3+DOCNLhqlEI2ZgQg==",
"cpu": [
"arm64"
],
@@ -1720,9 +1853,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.0.tgz",
- "integrity": "sha512-Fe1tGHxOWEyQjmygWkkXSwhFcTJuimrNu52JEuwItrKJVV4iRjbWp9I7zZjwqtiNnQmxoEvoisn8wueFLrNpvQ==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.2.tgz",
+ "integrity": "sha512-W5VvyZHnxG/2ukhZF/9Ikdra5fdNftxI6ybeVKYvBPDtyx7x4jPPSNduUkfH5fo3zG0JQ0bPxgy41af2JX5D4Q==",
"cpu": [
"x64"
],
@@ -1783,6 +1916,64 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@peculiar/asn1-android": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.5.0.tgz",
+ "integrity": "sha512-t8A83hgghWQkcneRsgGs2ebAlRe54ns88p7ouv8PW2tzF1nAW4yHcL4uZKrFpIU+uszIRzTkcCuie37gpkId0A==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.5.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-ecc": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.5.0.tgz",
+ "integrity": "sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.5.0",
+ "@peculiar/asn1-x509": "^2.5.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-rsa": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.5.0.tgz",
+ "integrity": "sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.5.0",
+ "@peculiar/asn1-x509": "^2.5.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-schema": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.5.0.tgz",
+ "integrity": "sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "asn1js": "^3.0.6",
+ "pvtsutils": "^1.3.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-x509": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.5.0.tgz",
+ "integrity": "sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.5.0",
+ "asn1js": "^3.0.6",
+ "pvtsutils": "^1.3.6",
+ "tslib": "^2.8.1"
+ }
+ },
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
@@ -1797,13 +1988,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.54.2",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.2.tgz",
- "integrity": "sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==",
+ "version": "1.55.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz",
+ "integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.54.2"
+ "playwright": "1.55.0"
},
"bin": {
"playwright": "cli.js"
@@ -1812,113 +2003,1772 @@
"node": ">=18"
}
},
- "node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.32",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz",
- "integrity": "sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g==",
- "dev": true,
+ "node_modules/@prisma/client": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.16.0.tgz",
+ "integrity": "sha512-FYkFJtgwpwJRMxtmrB26y7gtpR372kyChw6lWng5TMmvn5V+uisy0OyllO5EJD1s8lX78V8X3XjhiXOoMLnu3w==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "peerDependencies": {
+ "prisma": "*",
+ "typescript": ">=5.1.0"
+ },
+ "peerDependenciesMeta": {
+ "prisma": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@prisma/config": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.16.0.tgz",
+ "integrity": "sha512-Q9TgfnllVehvQziY9lJwRJLGmziX0OimZUEQ/MhCUBoJMSScj2VivCjw/Of2vlO1FfyaHXxrvjZAr7ASl7DVcw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "c12": "3.1.0",
+ "deepmerge-ts": "7.1.5",
+ "effect": "3.16.12",
+ "empathic": "2.0.0"
+ }
+ },
+ "node_modules/@prisma/debug": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.16.0.tgz",
+ "integrity": "sha512-bxzro5vbVqAPkWyDs2A6GpQtRZunD8tyrLmSAchx9u0b+gWCDY6eV+oh5A0YtYT9245dIxQBswckayHuJG4u3w==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/engines": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.16.0.tgz",
+ "integrity": "sha512-RHJGCH/zi017W4CWYWqg0Sv1pquGGFVo8T3auJ9sodDNaiRzbeNldydjaQzszVS8nscdtcvLuJzy7e65C3puqQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "6.16.0",
+ "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
+ "@prisma/fetch-engine": "6.16.0",
+ "@prisma/get-platform": "6.16.0"
+ }
+ },
+ "node_modules/@prisma/engines-version": {
+ "version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43.tgz",
+ "integrity": "sha512-ThvlDaKIVrnrv97ujNFDYiQbeMQpLa0O86HFA2mNoip4mtFqM7U5GSz2ie1i2xByZtvPztJlNRgPsXGeM/kqAA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/fetch-engine": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.16.0.tgz",
+ "integrity": "sha512-Mx5rml0XRIDizhB9eZxSP8c0nMoXYVITTiJJwxlWn9rNCel8mG8NAqIw+vJlN3gPR+kt3IBkP1SQVsplPPpYrA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "6.16.0",
+ "@prisma/engines-version": "6.16.0-7.1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
+ "@prisma/get-platform": "6.16.0"
+ }
+ },
+ "node_modules/@prisma/get-platform": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.16.0.tgz",
+ "integrity": "sha512-eaJOOvAoGslSUTjiQrtE9E0hoBdfL43j8SymOGD6LbdrKRNtIoiy6qiBaEr2fNYD+R/Qns7QOwPhl7SVHJayKA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "6.16.0"
+ }
+ },
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
+ "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
"license": "MIT"
},
- "node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz",
- "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "license": "MIT"
},
- "node_modules/@rollup/rollup-android-arm64": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz",
- "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-accessible-icon": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz",
+ "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==",
"license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
+ "dependencies": {
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "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
+ }
+ }
},
- "node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz",
- "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-accordion": {
+ "version": "1.2.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz",
+ "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==",
"license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collapsible": "1.1.12",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
},
- "node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz",
- "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-alert-dialog": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz",
+ "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==",
"license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dialog": "1.1.15",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "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
+ }
+ }
},
- "node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz",
- "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+ "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
"license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
},
- "node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz",
- "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-aspect-ratio": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz",
+ "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==",
"license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
},
- "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.50.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz",
- "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==",
- "cpu": [
- "arm"
- ],
- "dev": true,
+ "node_modules/@radix-ui/react-avatar": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz",
+ "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==",
"license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.50.0",
+ "dependencies": {
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-is-hydrated": "0.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz",
+ "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz",
+ "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context-menu": {
+ "version": "2.2.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz",
+ "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-menu": "2.1.16",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
+ "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
+ "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz",
+ "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-menu": "2.1.16",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
+ "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-form": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz",
+ "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-label": "2.1.7",
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-hover-card": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz",
+ "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz",
+ "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-menu": {
+ "version": "2.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz",
+ "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-menubar": {
+ "version": "1.1.16",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz",
+ "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-menu": "2.1.16",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-navigation-menu": {
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz",
+ "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-one-time-password-field": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz",
+ "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-is-hydrated": "0.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-password-toggle-field": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz",
+ "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-is-hydrated": "0.1.0"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popover": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
+ "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
+ "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-rect": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1",
+ "@radix-ui/rect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
+ "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-progress": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz",
+ "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-radio-group": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz",
+ "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
+ "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz",
+ "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-select": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
+ "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.3",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-separator": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz",
+ "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slider": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz",
+ "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-switch": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz",
+ "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tabs": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
+ "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toast": {
+ "version": "1.2.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz",
+ "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toggle": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz",
+ "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toggle-group": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz",
+ "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-toggle": "1.1.10",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toolbar": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz",
+ "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-separator": "1.1.7",
+ "@radix-ui/react-toggle-group": "1.1.11"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tooltip": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
+ "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-is-hydrated": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz",
+ "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==",
+ "license": "MIT",
+ "dependencies": {
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-previous": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+ "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+ "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/rect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
+ "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/@radix-ui/rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+ "license": "MIT"
+ },
+ "node_modules/@redux-saga/core": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.3.0.tgz",
+ "integrity": "sha512-L+i+qIGuyWn7CIg7k1MteHGfttKPmxwZR5E7OsGikCL2LzYA0RERlaUY00Y3P3ZV2EYgrsYlBrGs6cJP5OKKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.6.3",
+ "@redux-saga/deferred": "^1.2.1",
+ "@redux-saga/delay-p": "^1.2.1",
+ "@redux-saga/is": "^1.1.3",
+ "@redux-saga/symbols": "^1.1.3",
+ "@redux-saga/types": "^1.2.1",
+ "typescript-tuple": "^2.2.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/redux-saga"
+ }
+ },
+ "node_modules/@redux-saga/deferred": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz",
+ "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g==",
+ "license": "MIT"
+ },
+ "node_modules/@redux-saga/delay-p": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz",
+ "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@redux-saga/symbols": "^1.1.3"
+ }
+ },
+ "node_modules/@redux-saga/is": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz",
+ "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@redux-saga/symbols": "^1.1.3",
+ "@redux-saga/types": "^1.2.1"
+ }
+ },
+ "node_modules/@redux-saga/symbols": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz",
+ "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg==",
+ "license": "MIT"
+ },
+ "node_modules/@redux-saga/types": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz",
+ "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA==",
+ "license": "MIT"
+ },
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.0.tgz",
+ "integrity": "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.34",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz",
+ "integrity": "sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz",
+ "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz",
+ "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz",
+ "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz",
+ "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz",
+ "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz",
+ "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz",
+ "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.50.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz",
"integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==",
"cpu": [
@@ -2127,6 +3977,122 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@simplewebauthn/server": {
+ "version": "13.1.2",
+ "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.1.2.tgz",
+ "integrity": "sha512-VwoDfvLXSCaRiD+xCIuyslU0HLxVggeE5BL06+GbsP2l1fGf5op8e0c3ZtKoi+vSg1q4ikjtAghC23ze2Q3H9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@hexagon/base64": "^1.1.27",
+ "@levischuck/tiny-cbor": "^0.2.2",
+ "@peculiar/asn1-android": "^2.3.10",
+ "@peculiar/asn1-ecc": "^2.3.8",
+ "@peculiar/asn1-rsa": "^2.3.8",
+ "@peculiar/asn1-schema": "^2.3.8",
+ "@peculiar/asn1-x509": "^2.3.8"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
+ "node_modules/@supabase/auth-js": {
+ "version": "2.71.1",
+ "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.71.1.tgz",
+ "integrity": "sha512-mMIQHBRc+SKpZFRB2qtupuzulaUhFYupNyxqDj5Jp/LyPvcWvjaJzZzObv6URtL/O6lPxkanASnotGtNpS3H2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/functions-js": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.6.tgz",
+ "integrity": "sha512-bhjZ7rmxAibjgmzTmQBxJU6ZIBCCJTc3Uwgvdi4FewueUTAGO5hxZT1Sj6tiD+0dSXf9XI87BDdJrg12z8Uaew==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/node-fetch": {
+ "version": "2.6.15",
+ "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz",
+ "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/@supabase/postgrest-js": {
+ "version": "1.21.4",
+ "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.21.4.tgz",
+ "integrity": "sha512-TxZCIjxk6/dP9abAi89VQbWWMBbybpGWyvmIzTd79OeravM13OjR/YEYeyUOPcM1C3QyvXkvPZhUfItvmhY1IQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/realtime-js": {
+ "version": "2.15.5",
+ "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.15.5.tgz",
+ "integrity": "sha512-/Rs5Vqu9jejRD8ZeuaWXebdkH+J7V6VySbCZ/zQM93Ta5y3mAmocjioa/nzlB6qvFmyylUgKVS1KpE212t30OA==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.13",
+ "@types/phoenix": "^1.6.6",
+ "@types/ws": "^8.18.1",
+ "ws": "^8.18.2"
+ }
+ },
+ "node_modules/@supabase/ssr": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.7.0.tgz",
+ "integrity": "sha512-G65t5EhLSJ5c8hTCcXifSL9Q/ZRXvqgXeNo+d3P56f4U1IxwTqjB64UfmfixvmMcjuxnq2yGqEWVJqUcO+AzAg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.2"
+ },
+ "peerDependencies": {
+ "@supabase/supabase-js": "^2.43.4"
+ }
+ },
+ "node_modules/@supabase/storage-js": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.12.1.tgz",
+ "integrity": "sha512-QWg3HV6Db2J81VQx0PqLq0JDBn4Q8B1FYn1kYcbla8+d5WDmTdwwMr+EJAxNOSs9W4mhKMv+EYCpCrTFlTj4VQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/node-fetch": "^2.6.14"
+ }
+ },
+ "node_modules/@supabase/supabase-js": {
+ "version": "2.57.4",
+ "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.57.4.tgz",
+ "integrity": "sha512-LcbTzFhHYdwfQ7TRPfol0z04rLEyHabpGYANME6wkQ/kLtKNmI+Vy+WEM8HxeOZAtByUFxoUTTLwhXmrh+CcVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@supabase/auth-js": "2.71.1",
+ "@supabase/functions-js": "2.4.6",
+ "@supabase/node-fetch": "2.6.15",
+ "@supabase/postgrest-js": "1.21.4",
+ "@supabase/realtime-js": "2.15.5",
+ "@supabase/storage-js": "2.12.1"
+ }
+ },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -2137,9 +4103,9 @@
}
},
"node_modules/@tailwindcss/node": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz",
- "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.13.tgz",
+ "integrity": "sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2147,15 +4113,15 @@
"enhanced-resolve": "^5.18.3",
"jiti": "^2.5.1",
"lightningcss": "1.30.1",
- "magic-string": "^0.30.17",
+ "magic-string": "^0.30.18",
"source-map-js": "^1.2.1",
- "tailwindcss": "4.1.12"
+ "tailwindcss": "4.1.13"
}
},
"node_modules/@tailwindcss/oxide": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz",
- "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.13.tgz",
+ "integrity": "sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2167,24 +4133,24 @@
"node": ">= 10"
},
"optionalDependencies": {
- "@tailwindcss/oxide-android-arm64": "4.1.12",
- "@tailwindcss/oxide-darwin-arm64": "4.1.12",
- "@tailwindcss/oxide-darwin-x64": "4.1.12",
- "@tailwindcss/oxide-freebsd-x64": "4.1.12",
- "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12",
- "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12",
- "@tailwindcss/oxide-linux-arm64-musl": "4.1.12",
- "@tailwindcss/oxide-linux-x64-gnu": "4.1.12",
- "@tailwindcss/oxide-linux-x64-musl": "4.1.12",
- "@tailwindcss/oxide-wasm32-wasi": "4.1.12",
- "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12",
- "@tailwindcss/oxide-win32-x64-msvc": "4.1.12"
+ "@tailwindcss/oxide-android-arm64": "4.1.13",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.13",
+ "@tailwindcss/oxide-darwin-x64": "4.1.13",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.13",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.13",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.13",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.13",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.13",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.13",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.13",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.13",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.13"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz",
- "integrity": "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.13.tgz",
+ "integrity": "sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==",
"cpu": [
"arm64"
],
@@ -2199,9 +4165,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz",
- "integrity": "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.13.tgz",
+ "integrity": "sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==",
"cpu": [
"arm64"
],
@@ -2216,9 +4182,9 @@
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz",
- "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.13.tgz",
+ "integrity": "sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==",
"cpu": [
"x64"
],
@@ -2233,9 +4199,9 @@
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz",
- "integrity": "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.13.tgz",
+ "integrity": "sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==",
"cpu": [
"x64"
],
@@ -2250,9 +4216,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz",
- "integrity": "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.13.tgz",
+ "integrity": "sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==",
"cpu": [
"arm"
],
@@ -2267,9 +4233,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz",
- "integrity": "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.13.tgz",
+ "integrity": "sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==",
"cpu": [
"arm64"
],
@@ -2284,9 +4250,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz",
- "integrity": "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.13.tgz",
+ "integrity": "sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==",
"cpu": [
"arm64"
],
@@ -2301,9 +4267,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz",
- "integrity": "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.13.tgz",
+ "integrity": "sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==",
"cpu": [
"x64"
],
@@ -2318,9 +4284,9 @@
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz",
- "integrity": "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.13.tgz",
+ "integrity": "sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==",
"cpu": [
"x64"
],
@@ -2335,9 +4301,9 @@
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz",
- "integrity": "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.13.tgz",
+ "integrity": "sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
@@ -2365,9 +4331,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz",
- "integrity": "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.13.tgz",
+ "integrity": "sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==",
"cpu": [
"arm64"
],
@@ -2382,9 +4348,9 @@
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz",
- "integrity": "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.13.tgz",
+ "integrity": "sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==",
"cpu": [
"x64"
],
@@ -2399,34 +4365,94 @@
}
},
"node_modules/@tailwindcss/postcss": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.12.tgz",
- "integrity": "sha512-5PpLYhCAwf9SJEeIsSmCDLgyVfdBhdBpzX1OJ87anT9IVR0Z9pjM0FNixCAUAHGnMBGB8K99SwAheXrT0Kh6QQ==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.13.tgz",
+ "integrity": "sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
- "@tailwindcss/node": "4.1.12",
- "@tailwindcss/oxide": "4.1.12",
+ "@tailwindcss/node": "4.1.13",
+ "@tailwindcss/oxide": "4.1.13",
"postcss": "^8.4.41",
- "tailwindcss": "4.1.12"
+ "tailwindcss": "4.1.13"
}
},
"node_modules/@tailwindcss/vite": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.12.tgz",
- "integrity": "sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.13.tgz",
+ "integrity": "sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@tailwindcss/node": "4.1.12",
- "@tailwindcss/oxide": "4.1.12",
- "tailwindcss": "4.1.12"
+ "@tailwindcss/node": "4.1.13",
+ "@tailwindcss/oxide": "4.1.13",
+ "tailwindcss": "4.1.13"
},
"peerDependencies": {
"vite": "^5.2.0 || ^6 || ^7"
}
},
+ "node_modules/@testing-library/dom": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
+ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/runtime": "^7.12.5",
+ "@types/aria-query": "^5.0.1",
+ "aria-query": "5.3.0",
+ "dom-accessibility-api": "^0.5.9",
+ "lz-string": "^1.5.0",
+ "picocolors": "1.1.1",
+ "pretty-format": "^27.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@testing-library/dom/node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/@testing-library/react": {
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
+ "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@testing-library/dom": "^10.0.0",
+ "@types/react": "^18.0.0 || ^19.0.0",
+ "@types/react-dom": "^18.0.0 || ^19.0.0",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@tybys/wasm-util": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz",
@@ -2438,6 +4464,14 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@types/aria-query": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
+ "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -2522,35 +4556,56 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "24.3.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
- "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
- "dev": true,
+ "version": "24.3.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
+ "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.10.0"
}
},
- "node_modules/@types/react": {
- "version": "19.1.10",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz",
- "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==",
+ "node_modules/@types/phoenix": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz",
+ "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/ramda": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.31.0.tgz",
+ "integrity": "sha512-1lWWZ/2YiNttGcIUxQwnvMuh55GIEbn/zlpzzEojAsbxquI/TXQZCRaXsfxG1CHjlqGoqxWePkvaM/5qYHNuvQ==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "types-ramda": "^0.31.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.1.12",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
+ "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==",
+ "devOptional": true,
+ "license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "19.1.7",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz",
- "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
- "dev": true,
+ "version": "19.1.9",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz",
+ "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
+ "devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.0.0"
}
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@types/whatwg-mimetype": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz",
@@ -2558,18 +4613,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz",
- "integrity": "sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.43.0.tgz",
+ "integrity": "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.41.0",
- "@typescript-eslint/type-utils": "8.41.0",
- "@typescript-eslint/utils": "8.41.0",
- "@typescript-eslint/visitor-keys": "8.41.0",
+ "@typescript-eslint/scope-manager": "8.43.0",
+ "@typescript-eslint/type-utils": "8.43.0",
+ "@typescript-eslint/utils": "8.43.0",
+ "@typescript-eslint/visitor-keys": "8.43.0",
"graphemer": "^1.4.0",
"ignore": "^7.0.0",
"natural-compare": "^1.4.0",
@@ -2583,7 +4647,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.41.0",
+ "@typescript-eslint/parser": "^8.43.0",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
@@ -2599,16 +4663,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.41.0.tgz",
- "integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.43.0.tgz",
+ "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.41.0",
- "@typescript-eslint/types": "8.41.0",
- "@typescript-eslint/typescript-estree": "8.41.0",
- "@typescript-eslint/visitor-keys": "8.41.0",
+ "@typescript-eslint/scope-manager": "8.43.0",
+ "@typescript-eslint/types": "8.43.0",
+ "@typescript-eslint/typescript-estree": "8.43.0",
+ "@typescript-eslint/visitor-keys": "8.43.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2624,14 +4688,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.41.0.tgz",
- "integrity": "sha512-b8V9SdGBQzQdjJ/IO3eDifGpDBJfvrNTp2QD9P2BeqWTGrRibgfgIlBSw6z3b6R7dPzg752tOs4u/7yCLxksSQ==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.43.0.tgz",
+ "integrity": "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.41.0",
- "@typescript-eslint/types": "^8.41.0",
+ "@typescript-eslint/tsconfig-utils": "^8.43.0",
+ "@typescript-eslint/types": "^8.43.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2646,14 +4710,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.41.0.tgz",
- "integrity": "sha512-n6m05bXn/Cd6DZDGyrpXrELCPVaTnLdPToyhBoFkLIMznRUQUEQdSp96s/pcWSQdqOhrgR1mzJ+yItK7T+WPMQ==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.43.0.tgz",
+ "integrity": "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.41.0",
- "@typescript-eslint/visitor-keys": "8.41.0"
+ "@typescript-eslint/types": "8.43.0",
+ "@typescript-eslint/visitor-keys": "8.43.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2664,9 +4728,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.41.0.tgz",
- "integrity": "sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.43.0.tgz",
+ "integrity": "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2681,15 +4745,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.41.0.tgz",
- "integrity": "sha512-63qt1h91vg3KsjVVonFJWjgSK7pZHSQFKH6uwqxAH9bBrsyRhO6ONoKyXxyVBzG1lJnFAJcKAcxLS54N1ee1OQ==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.43.0.tgz",
+ "integrity": "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.41.0",
- "@typescript-eslint/typescript-estree": "8.41.0",
- "@typescript-eslint/utils": "8.41.0",
+ "@typescript-eslint/types": "8.43.0",
+ "@typescript-eslint/typescript-estree": "8.43.0",
+ "@typescript-eslint/utils": "8.43.0",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -2706,9 +4770,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.41.0.tgz",
- "integrity": "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.43.0.tgz",
+ "integrity": "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2720,16 +4784,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.41.0.tgz",
- "integrity": "sha512-D43UwUYJmGhuwHfY7MtNKRZMmfd8+p/eNSfFe6tH5mbVDto+VQCayeAt35rOx3Cs6wxD16DQtIKw/YXxt5E0UQ==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.43.0.tgz",
+ "integrity": "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.41.0",
- "@typescript-eslint/tsconfig-utils": "8.41.0",
- "@typescript-eslint/types": "8.41.0",
- "@typescript-eslint/visitor-keys": "8.41.0",
+ "@typescript-eslint/project-service": "8.43.0",
+ "@typescript-eslint/tsconfig-utils": "8.43.0",
+ "@typescript-eslint/types": "8.43.0",
+ "@typescript-eslint/visitor-keys": "8.43.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -2788,16 +4852,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.41.0.tgz",
- "integrity": "sha512-udbCVstxZ5jiPIXrdH+BZWnPatjlYwJuJkDA4Tbo3WyYLh8NvB+h/bKeSZHDOFKfphsZYJQqaFtLeXEqurQn1A==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.43.0.tgz",
+ "integrity": "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.41.0",
- "@typescript-eslint/types": "8.41.0",
- "@typescript-eslint/typescript-estree": "8.41.0"
+ "@typescript-eslint/scope-manager": "8.43.0",
+ "@typescript-eslint/types": "8.43.0",
+ "@typescript-eslint/typescript-estree": "8.43.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2812,13 +4876,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.41.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.41.0.tgz",
- "integrity": "sha512-+GeGMebMCy0elMNg67LRNoVnUFPIm37iu5CmHESVx56/9Jsfdpsvbv605DQ81Pi/x11IdKUsS5nzgTYbCQU9fg==",
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.43.0.tgz",
+ "integrity": "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.41.0",
+ "@typescript-eslint/types": "8.43.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -3112,16 +5176,16 @@
]
},
"node_modules/@vitejs/plugin-react": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.1.tgz",
- "integrity": "sha512-DE4UNaBXwtVoDJ0ccBdLVjFTWL70NRuWNCxEieTI3lrq9ORB9aOCQEKstwDXBl87NvFdbqh/p7eINGyj0BthJA==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz",
+ "integrity": "sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.28.3",
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
- "@rolldown/pluginutils": "1.0.0-beta.32",
+ "@rolldown/pluginutils": "1.0.0-beta.34",
"@types/babel__core": "^7.20.5",
"react-refresh": "^0.17.0"
},
@@ -3133,12 +5197,13 @@
}
},
"node_modules/@vitest/eslint-plugin": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.3.4.tgz",
- "integrity": "sha512-EOg8d0jn3BAiKnR55WkFxmxfWA3nmzrbIIuOXyTe6A72duryNgyU+bdBEauA97Aab3ho9kLmAwgPX63Ckj4QEg==",
+ "version": "1.3.9",
+ "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.3.9.tgz",
+ "integrity": "sha512-wsNe7xy44ovm/h9ISDkDNcv0aOnUsaOYDqan2y6qCFAUQ0odFr6df/+FdGKHZN+mCM+SvIDWoXuvm5T5V3Kh6w==",
"dev": true,
"license": "MIT",
"dependencies": {
+ "@typescript-eslint/scope-manager": "^8.41.0",
"@typescript-eslint/utils": "^8.24.1"
},
"peerDependencies": {
@@ -3362,6 +5427,18 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/aria-query": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
@@ -3552,6 +5629,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/asn1js": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.6.tgz",
+ "integrity": "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "pvtsutils": "^1.3.6",
+ "pvutils": "^1.1.3",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
@@ -3699,6 +5790,34 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/c12": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz",
+ "integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^4.0.3",
+ "confbox": "^0.2.2",
+ "defu": "^6.1.4",
+ "dotenv": "^16.6.1",
+ "exsolve": "^1.0.7",
+ "giget": "^2.0.0",
+ "jiti": "^2.4.2",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^1.0.0",
+ "pkg-types": "^2.2.0",
+ "rc9": "^2.1.2"
+ },
+ "peerDependencies": {
+ "magicast": "^0.3.5"
+ },
+ "peerDependenciesMeta": {
+ "magicast": {
+ "optional": true
+ }
+ }
+ },
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
@@ -3894,6 +6013,21 @@
"node": ">=18"
}
},
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/chownr": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
@@ -3920,6 +6054,27 @@
"node": ">=8"
}
},
+ "node_modules/citty": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
+ "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
+ "license": "MIT",
+ "dependencies": {
+ "consola": "^3.2.3"
+ }
+ },
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
"node_modules/clean-regexp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
@@ -3982,6 +6137,15 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@@ -4051,6 +6215,21 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/confbox": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
+ "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+ "license": "MIT"
+ },
+ "node_modules/consola": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
+ "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -4058,6 +6237,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/core-js-compat": {
"version": "3.45.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz",
@@ -4121,7 +6309,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -4253,6 +6441,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/deepmerge-ts": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
+ "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -4295,10 +6492,33 @@
"integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
"dev": true,
"license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/defu": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
+ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
+ "license": "MIT"
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6"
}
},
+ "node_modules/destr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
+ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
+ "license": "MIT"
+ },
"node_modules/detect-libc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
@@ -4309,6 +6529,12 @@
"node": ">=8"
}
},
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
"node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -4322,6 +6548,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dom-accessibility-api": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
+ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -4381,6 +6615,18 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
+ "node_modules/dotenv": {
+ "version": "16.6.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
+ "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dotignore": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz",
@@ -4409,6 +6655,16 @@
"node": ">= 0.4"
}
},
+ "node_modules/effect": {
+ "version": "3.16.12",
+ "resolved": "https://registry.npmjs.org/effect/-/effect-3.16.12.tgz",
+ "integrity": "sha512-N39iBk0K71F9nb442TLbTkjl24FLUzuvx2i1I2RsEAQsdAdUTuUoW0vlfUXgkMTUOnYqKnWcFfqw4hK4Pw27hg==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "fast-check": "^3.23.1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.211",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.211.tgz",
@@ -4423,6 +6679,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/empathic": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz",
+ "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/encoding-sniffer": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
@@ -4748,19 +7013,19 @@
}
},
"node_modules/eslint": {
- "version": "9.33.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz",
- "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==",
+ "version": "9.35.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz",
+ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.21.0",
"@eslint/config-helpers": "^0.3.1",
"@eslint/core": "^0.15.2",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.33.0",
+ "@eslint/js": "9.35.0",
"@eslint/plugin-kit": "^0.3.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -4809,13 +7074,13 @@
}
},
"node_modules/eslint-config-next": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.0.tgz",
- "integrity": "sha512-Yl4hlOdBqstAuHnlBfx2RimBzWQwysM2SJNu5EzYVa2qS2ItPs7lgxL0sJJDudEx5ZZHfWPZ/6U8+FtDFWs7/w==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.5.2.tgz",
+ "integrity": "sha512-3hPZghsLupMxxZ2ggjIIrat/bPniM2yRpsVPVM40rp8ZMzKWOJp2CGWn7+EzoV2ddkUr5fxNfHpF+wU1hGt/3g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@next/eslint-plugin-next": "15.5.0",
+ "@next/eslint-plugin-next": "15.5.2",
"@rushstack/eslint-patch": "^1.10.3",
"@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
@@ -5149,9 +7414,9 @@
}
},
"node_modules/eslint-plugin-unicorn": {
- "version": "60.0.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-60.0.0.tgz",
- "integrity": "sha512-QUzTefvP8stfSXsqKQ+vBQSEsXIlAiCduS/V1Em+FKgL9c21U/IIm20/e3MFy1jyCf14tHAhqC1sX8OTy6VUCg==",
+ "version": "61.0.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-61.0.2.tgz",
+ "integrity": "sha512-zLihukvneYT7f74GNbVJXfWIiNQmkc/a9vYBTE4qPkQZswolWNdu+Wsp9sIXno1JOzdn6OUwLPd19ekXVkahRA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5367,6 +7632,34 @@
"node": ">=12.0.0"
}
},
+ "node_modules/exsolve": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
+ "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==",
+ "license": "MIT"
+ },
+ "node_modules/fast-check": {
+ "version": "3.23.2",
+ "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
+ "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "pure-rand": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5639,6 +7932,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
@@ -5694,6 +7996,23 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
+ "node_modules/giget": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
+ "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.6",
+ "consola": "^3.4.0",
+ "defu": "^6.1.4",
+ "node-fetch-native": "^1.6.6",
+ "nypm": "^0.6.0",
+ "pathe": "^2.0.3"
+ },
+ "bin": {
+ "giget": "dist/cli.mjs"
+ }
+ },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -6009,6 +8328,16 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "10.1.3",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz",
+ "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -6586,7 +8915,6 @@
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz",
"integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==",
- "dev": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -6972,17 +9300,17 @@
}
},
"node_modules/lint-staged": {
- "version": "16.1.5",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.5.tgz",
- "integrity": "sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A==",
+ "version": "16.1.6",
+ "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.6.tgz",
+ "integrity": "sha512-U4kuulU3CKIytlkLlaHcGgKscNfJPNTiDF2avIUGFCv7K95/DCYQ7Ra62ydeRWmgQGg9zJYw2dzdbztwJlqrow==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^5.5.0",
+ "chalk": "^5.6.0",
"commander": "^14.0.0",
"debug": "^4.4.1",
"lilconfig": "^3.1.3",
- "listr2": "^9.0.1",
+ "listr2": "^9.0.3",
"micromatch": "^4.0.8",
"nano-spawn": "^1.0.2",
"pidtree": "^0.6.0",
@@ -7149,6 +9477,26 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.543.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.543.0.tgz",
+ "integrity": "sha512-fpVfuOQO0V3HBaOA1stIiP/A2fPCXHIleRZL16Mx3HmjTYwNSbimhnFBygs2CAfU1geexMX5ItUcWBGUaqw5CA==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "lz-string": "bin/bin.js"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.18",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
@@ -7362,12 +9710,12 @@
"license": "MIT"
},
"node_modules/next": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/next/-/next-15.5.0.tgz",
- "integrity": "sha512-N1lp9Hatw3a9XLt0307lGB4uTKsXDhyOKQo7uYMzX4i0nF/c27grcGXkLdb7VcT8QPYLBa8ouIyEoUQJ2OyeNQ==",
+ "version": "15.5.2",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.5.2.tgz",
+ "integrity": "sha512-H8Otr7abj1glFhbGnvUt3gz++0AF1+QoCXEBmd/6aKbfdFwrn0LpA836Ed5+00va/7HQSDD+mOoVhn3tNy3e/Q==",
"license": "MIT",
"dependencies": {
- "@next/env": "15.5.0",
+ "@next/env": "15.5.2",
"@swc/helpers": "0.5.15",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
@@ -7380,14 +9728,14 @@
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "15.5.0",
- "@next/swc-darwin-x64": "15.5.0",
- "@next/swc-linux-arm64-gnu": "15.5.0",
- "@next/swc-linux-arm64-musl": "15.5.0",
- "@next/swc-linux-x64-gnu": "15.5.0",
- "@next/swc-linux-x64-musl": "15.5.0",
- "@next/swc-win32-arm64-msvc": "15.5.0",
- "@next/swc-win32-x64-msvc": "15.5.0",
+ "@next/swc-darwin-arm64": "15.5.2",
+ "@next/swc-darwin-x64": "15.5.2",
+ "@next/swc-linux-arm64-gnu": "15.5.2",
+ "@next/swc-linux-arm64-musl": "15.5.2",
+ "@next/swc-linux-x64-gnu": "15.5.2",
+ "@next/swc-linux-x64-musl": "15.5.2",
+ "@next/swc-win32-arm64-msvc": "15.5.2",
+ "@next/swc-win32-x64-msvc": "15.5.2",
"sharp": "^0.34.3"
},
"peerDependencies": {
@@ -7413,6 +9761,16 @@
}
}
},
+ "node_modules/next-themes": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+ "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -7441,6 +9799,12 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/node-fetch-native": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
+ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
+ "license": "MIT"
+ },
"node_modules/node-releases": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
@@ -7461,6 +9825,31 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
+ "node_modules/nypm": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz",
+ "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==",
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.6",
+ "consola": "^3.4.2",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.2.0",
+ "tinyexec": "^1.0.1"
+ },
+ "bin": {
+ "nypm": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": "^14.16.0 || >=16.10.0"
+ }
+ },
+ "node_modules/nypm/node_modules/tinyexec": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
+ "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
+ "license": "MIT"
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -7601,6 +9990,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "license": "MIT"
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -7802,7 +10197,6 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
- "dev": true,
"license": "MIT"
},
"node_modules/pathval": {
@@ -7815,6 +10209,12 @@
"node": ">= 14.16"
}
},
+ "node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
+ "license": "MIT"
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -7847,14 +10247,25 @@
"node": ">=0.10"
}
},
+ "node_modules/pkg-types": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
+ "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.2.2",
+ "exsolve": "^1.0.7",
+ "pathe": "^2.0.3"
+ }
+ },
"node_modules/playwright": {
- "version": "1.54.2",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.2.tgz",
- "integrity": "sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==",
+ "version": "1.55.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz",
+ "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.54.2"
+ "playwright-core": "1.55.0"
},
"bin": {
"playwright": "cli.js"
@@ -7867,9 +10278,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.54.2",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.2.tgz",
- "integrity": "sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==",
+ "version": "1.55.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz",
+ "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==",
"devOptional": true,
"license": "Apache-2.0",
"bin": {
@@ -8054,6 +10465,80 @@
}
}
},
+ "node_modules/pretty-format": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^17.0.1"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/pretty-format/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/prisma": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.16.0.tgz",
+ "integrity": "sha512-TTh+H1Kw8N68KN9cDzdAyMroqMOvdCO/Z+kS2wKEVYR1nuR21qH5Q/Db/bZHsAgw7l/TPHtM/veG5VABcdwPDw==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/config": "6.16.0",
+ "@prisma/engines": "6.16.0"
+ },
+ "bin": {
+ "prisma": "build/index.js"
+ },
+ "engines": {
+ "node": ">=18.18"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.1.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -8076,6 +10561,40 @@
"node": ">=6"
}
},
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/pvtsutils": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
+ "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/pvutils": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
+ "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -8094,45 +10613,271 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ],
- "license": "MIT"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/radix-ui": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz",
+ "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-accessible-icon": "1.1.7",
+ "@radix-ui/react-accordion": "1.2.12",
+ "@radix-ui/react-alert-dialog": "1.1.15",
+ "@radix-ui/react-arrow": "1.1.7",
+ "@radix-ui/react-aspect-ratio": "1.1.7",
+ "@radix-ui/react-avatar": "1.1.10",
+ "@radix-ui/react-checkbox": "1.3.3",
+ "@radix-ui/react-collapsible": "1.1.12",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-context-menu": "2.2.16",
+ "@radix-ui/react-dialog": "1.1.15",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-dropdown-menu": "2.1.16",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-form": "0.1.8",
+ "@radix-ui/react-hover-card": "1.1.15",
+ "@radix-ui/react-label": "2.1.7",
+ "@radix-ui/react-menu": "2.1.16",
+ "@radix-ui/react-menubar": "1.1.16",
+ "@radix-ui/react-navigation-menu": "1.2.14",
+ "@radix-ui/react-one-time-password-field": "0.1.8",
+ "@radix-ui/react-password-toggle-field": "0.1.3",
+ "@radix-ui/react-popover": "1.1.15",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-progress": "1.1.7",
+ "@radix-ui/react-radio-group": "1.3.8",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-scroll-area": "1.2.10",
+ "@radix-ui/react-select": "2.2.6",
+ "@radix-ui/react-separator": "1.1.7",
+ "@radix-ui/react-slider": "1.3.6",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-switch": "1.2.6",
+ "@radix-ui/react-tabs": "1.1.13",
+ "@radix-ui/react-toast": "1.2.15",
+ "@radix-ui/react-toggle": "1.1.10",
+ "@radix-ui/react-toggle-group": "1.1.11",
+ "@radix-ui/react-toolbar": "1.1.11",
+ "@radix-ui/react-tooltip": "1.2.8",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-escape-keydown": "1.1.1",
+ "@radix-ui/react-use-is-hydrated": "0.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "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
+ }
+ }
+ },
+ "node_modules/ramda": {
+ "version": "0.31.3",
+ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.31.3.tgz",
+ "integrity": "sha512-xKADKRNnqmDdX59PPKLm3gGmk1ZgNnj3k7DryqWwkamp4TJ6B36DdpyKEQ0EoEYmH2R62bV4Q+S0ym2z8N2f3Q==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ramda"
+ }
+ },
+ "node_modules/rc9": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz",
+ "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==",
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.4",
+ "destr": "^2.0.3"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.1.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
+ "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.1.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
+ "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.26.0"
+ },
+ "peerDependencies": {
+ "react": "^19.1.1"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-remove-scroll": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
+ "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
},
- "node_modules/react": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
- "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
"license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
}
},
- "node_modules/react-dom": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
- "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
"license": "MIT",
"dependencies": {
- "scheduler": "^0.26.0"
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
},
"peerDependencies": {
- "react": "^19.1.1"
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
}
},
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
},
- "node_modules/react-refresh": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
- "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
- "dev": true,
+ "node_modules/redux-saga": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.3.0.tgz",
+ "integrity": "sha512-J9RvCeAZXSTAibFY0kGw6Iy4EdyDNW7k6Q+liwX+bsck7QVsU78zz8vpBRweEfANxnnlG/xGGeOvf6r8UXzNJQ==",
"license": "MIT",
- "engines": {
- "node": ">=0.10.0"
+ "dependencies": {
+ "@redux-saga/core": "^1.3.0"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
}
},
"node_modules/reflect.getprototypeof": {
@@ -8215,6 +10960,12 @@
"node": ">=6"
}
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -8292,9 +11043,9 @@
"license": "MIT"
},
"node_modules/riteway": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/riteway/-/riteway-8.0.0.tgz",
- "integrity": "sha512-zz1lGacUafmZRROHJ6PN9VXMbg9rO/hhFKLIxWPpWC1PUWKuQ/A3fvu0QQ5JF11YUTXFK5s0hpcE8Sdzx9xeuw==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/riteway/-/riteway-8.0.1.tgz",
+ "integrity": "sha512-ZWa7a46ONN0aBzHZbF5E9ys5OTcGyfh8Y3SS7VUeRPZZetRaFCU1eENIMbk13nSHQJAT61Q8BVApo/1SXABieQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9047,10 +11798,26 @@
"url": "https://opencollective.com/synckit"
}
},
+ "node_modules/tabbable": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
+ "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==",
+ "license": "MIT"
+ },
+ "node_modules/tailwind-merge": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz",
- "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==",
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.13.tgz",
+ "integrity": "sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==",
"dev": true,
"license": "MIT"
},
@@ -9256,6 +12023,12 @@
"node": ">=8.0"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
"node_modules/ts-api-utils": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
@@ -9269,6 +12042,13 @@
"typescript": ">=4.8.4"
}
},
+ "node_modules/ts-toolbelt": {
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz",
+ "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/tsconfck": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz",
@@ -9309,443 +12089,203 @@
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "minimist": "^1.2.0"
- },
- "bin": {
- "json5": "lib/cli.js"
- }
- },
- "node_modules/tslib": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
- "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "license": "0BSD"
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "license": "(MIT OR CC0-1.0)",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typed-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/typed-array-byte-length": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
- "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-byte-offset": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
- "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.15",
- "reflect.getprototypeof": "^1.0.9"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-length": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
- "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0",
- "reflect.getprototypeof": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typescript": {
- "version": "5.9.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
- "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
- "dev": true,
- "license": "Apache-2.0",
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/typescript-eslint": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.40.0.tgz",
- "integrity": "sha512-Xvd2l+ZmFDPEt4oj1QEXzA4A2uUK6opvKu3eGN9aGjB8au02lIVcLyi375w94hHyejTOmzIU77L8ol2sRg9n7Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/eslint-plugin": "8.40.0",
- "@typescript-eslint/parser": "8.40.0",
- "@typescript-eslint/typescript-estree": "8.40.0",
- "@typescript-eslint/utils": "8.40.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz",
- "integrity": "sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.40.0",
- "@typescript-eslint/type-utils": "8.40.0",
- "@typescript-eslint/utils": "8.40.0",
- "@typescript-eslint/visitor-keys": "8.40.0",
- "graphemer": "^1.4.0",
- "ignore": "^7.0.0",
- "natural-compare": "^1.4.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "@typescript-eslint/parser": "^8.40.0",
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.40.0.tgz",
- "integrity": "sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/scope-manager": "8.40.0",
- "@typescript-eslint/types": "8.40.0",
- "@typescript-eslint/typescript-estree": "8.40.0",
- "@typescript-eslint/visitor-keys": "8.40.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "dependencies": {
+ "minimist": "^1.2.0"
},
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
+ "bin": {
+ "json5": "lib/cli.js"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.40.0.tgz",
- "integrity": "sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==",
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/tw-animate-css": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.3.8.tgz",
+ "integrity": "sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.40.0",
- "@typescript-eslint/types": "^8.40.0",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
+ "url": "https://github.com/sponsors/Wombosvideo"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.40.0.tgz",
- "integrity": "sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==",
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.40.0",
- "@typescript-eslint/visitor-keys": "8.40.0"
+ "prelude-ls": "^1.2.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "node": ">= 0.8.0"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.40.0.tgz",
- "integrity": "sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==",
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
"dev": true,
- "license": "MIT",
+ "license": "(MIT OR CC0-1.0)",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">=10"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.40.0.tgz",
- "integrity": "sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==",
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.40.0",
- "@typescript-eslint/typescript-estree": "8.40.0",
- "@typescript-eslint/utils": "8.40.0",
- "debug": "^4.3.4",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
},
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
- }
- },
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.40.0.tgz",
- "integrity": "sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==",
- "dev": true,
- "license": "MIT",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "node": ">= 0.4"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.40.0.tgz",
- "integrity": "sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==",
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.40.0",
- "@typescript-eslint/tsconfig-utils": "8.40.0",
- "@typescript-eslint/types": "8.40.0",
- "@typescript-eslint/visitor-keys": "8.40.0",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">= 0.4"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <6.0.0"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.40.0.tgz",
- "integrity": "sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==",
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.40.0",
- "@typescript-eslint/types": "8.40.0",
- "@typescript-eslint/typescript-estree": "8.40.0"
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">= 0.4"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <6.0.0"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.40.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.40.0.tgz",
- "integrity": "sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==",
+ "node_modules/typed-array-length": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.40.0",
- "eslint-visitor-keys": "^4.2.1"
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">= 0.4"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typescript-eslint/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "node_modules/types-ramda": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/types-ramda/-/types-ramda-0.31.0.tgz",
+ "integrity": "sha512-vaoC35CRC3xvL8Z6HkshDbi6KWM1ezK0LHN0YyxXWUn9HKzBNg/T3xSGlJZjCYspnOD3jE7bcizsp0bUXZDxnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0"
+ "ts-toolbelt": "^9.6.0"
}
},
- "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
- "dev": true,
+ "node_modules/typescript": {
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "devOptional": true,
"license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
},
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "engines": {
+ "node": ">=14.17"
}
},
- "node_modules/typescript-eslint/node_modules/ignore": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
- "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
- "dev": true,
+ "node_modules/typescript-compare": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+ "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
"license": "MIT",
- "engines": {
- "node": ">= 4"
+ "dependencies": {
+ "typescript-logic": "^0.0.0"
}
},
- "node_modules/typescript-eslint/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "node_modules/typescript-eslint": {
+ "version": "8.43.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.43.0.tgz",
+ "integrity": "sha512-FyRGJKUGvcFekRRcBKFBlAhnp4Ng8rhe8tuvvkR9OiU0gfd4vyvTRQHEckO6VDlH57jbeUQem2IpqPq9kLJH+w==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "@typescript-eslint/eslint-plugin": "8.43.0",
+ "@typescript-eslint/parser": "8.43.0",
+ "@typescript-eslint/typescript-estree": "8.43.0",
+ "@typescript-eslint/utils": "8.43.0"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
}
},
- "node_modules/typescript-eslint/node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
+ "node_modules/typescript-logic": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+ "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==",
+ "license": "MIT"
+ },
+ "node_modules/typescript-tuple": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+ "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "typescript-compare": "^0.0.2"
}
},
"node_modules/unbox-primitive": {
@@ -9781,7 +12321,6 @@
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
- "dev": true,
"license": "MIT"
},
"node_modules/unrs-resolver": {
@@ -9860,6 +12399,58 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
+ "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/vite": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.4.tgz",
@@ -10110,6 +12701,12 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/whatwg-encoding": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
@@ -10133,6 +12730,16 @@
"node": ">=12"
}
},
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -10303,6 +12910,27 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/ws": {
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -10335,6 +12963,15 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zod": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.5.tgz",
+ "integrity": "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
}
}
diff --git a/package.json b/package.json
index 7f3655a..0e74256 100644
--- a/package.json
+++ b/package.json
@@ -1,37 +1,57 @@
{
"dependencies": {
- "next": "15.5.0",
+ "@base-ui-components/react": "1.0.0-beta.3",
+ "@prisma/client": "6.16.0",
+ "@reduxjs/toolkit": "2.9.0",
+ "@simplewebauthn/server": "13.1.2",
+ "@supabase/ssr": "0.7.0",
+ "@supabase/supabase-js": "2.57.4",
+ "class-variance-authority": "0.7.1",
+ "clsx": "2.1.1",
+ "lucide-react": "0.543.0",
+ "next": "15.5.2",
+ "next-themes": "0.4.6",
+ "prisma": "6.16.0",
+ "radix-ui": "1.4.3",
+ "ramda": "0.31.3",
"react": "19.1.1",
- "react-dom": "19.1.1"
+ "react-dom": "19.1.1",
+ "react-redux": "9.2.0",
+ "redux-saga": "1.3.0",
+ "tailwind-merge": "3.3.1",
+ "zod": "4.1.5"
},
"devDependencies": {
"@eslint/compat": "1.3.2",
"@eslint/eslintrc": "3.3.1",
- "@eslint/js": "9.33.0",
- "@tailwindcss/postcss": "4.1.12",
- "@tailwindcss/vite": "4.1.12",
- "@types/node": "24.3.0",
- "@playwright/test": "1.54.2",
- "@types/react": "19.1.10",
- "@types/react-dom": "19.1.7",
- "@vitejs/plugin-react": "5.0.1",
- "@vitest/eslint-plugin": "1.3.4",
- "eslint": "9.33.0",
- "eslint-config-next": "15.5.0",
+ "@eslint/js": "9.35.0",
+ "@playwright/test": "1.55.0",
+ "@tailwindcss/postcss": "4.1.13",
+ "@tailwindcss/vite": "4.1.13",
+ "@testing-library/react": "16.3.0",
+ "@types/node": "24.3.1",
+ "@types/ramda": "0.31.0",
+ "@types/react": "19.1.12",
+ "@types/react-dom": "19.1.9",
+ "@vitejs/plugin-react": "5.0.2",
+ "@vitest/eslint-plugin": "1.3.9",
+ "eslint": "9.35.0",
+ "eslint-config-next": "15.5.2",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-playwright": "2.2.2",
"eslint-plugin-prettier": "5.5.4",
"eslint-plugin-simple-import-sort": "12.1.1",
- "eslint-plugin-unicorn": "60.0.0",
+ "eslint-plugin-unicorn": "61.0.2",
"happy-dom": "18.0.1",
"husky": "9.1.7",
- "lint-staged": "16.1.5",
+ "lint-staged": "16.1.6",
"prettier": "3.6.2",
"prettier-plugin-tailwindcss": "0.6.14",
- "riteway": "8.0.0",
- "tailwindcss": "4.1.12",
+ "riteway": "8.0.1",
+ "tailwindcss": "4.1.13",
+ "tw-animate-css": "1.3.8",
"typescript": "5.9.2",
- "typescript-eslint": "8.40.0",
+ "typescript-eslint": "8.43.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4"
},
@@ -50,10 +70,17 @@
"build": "next build",
"dev": "next dev --turbopack",
"format": "prettier --write .",
- "lint": "next lint",
+ "lint": "eslint",
+ "lint:fix": "eslint --fix",
"prepare": "husky",
"start": "next start",
- "test": "vitest --reporter=verbose --run"
+ "test": "vitest --run",
+ "test:watch": "vitest --reporter=verbose --watch",
+ "db:generate": "prisma generate",
+ "db:migrate": "prisma migrate dev",
+ "db:studio": "prisma studio",
+ "db:push": "prisma db push",
+ "db:seed": "tsx prisma/seed.ts"
},
"type": "module",
"version": "0.1.0"
diff --git a/postcss.config.mjs b/postcss.config.mjs
index c7bcb4b..ba720fe 100644
--- a/postcss.config.mjs
+++ b/postcss.config.mjs
@@ -1,5 +1,5 @@
const config = {
- plugins: ["@tailwindcss/postcss"],
+ plugins: ['@tailwindcss/postcss'],
};
export default config;
diff --git a/prettier.config.js b/prettier.config.js
index dc092de..119a456 100644
--- a/prettier.config.js
+++ b/prettier.config.js
@@ -1,4 +1,4 @@
-export default {
+const config = {
arrowParens: 'avoid',
bracketSameLine: false,
bracketSpacing: true,
@@ -16,3 +16,5 @@ export default {
trailingComma: 'all',
useTabs: false,
};
+
+export default config;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
new file mode 100644
index 0000000..4d364b6
--- /dev/null
+++ b/prisma/schema.prisma
@@ -0,0 +1,77 @@
+// Prisma schema for passwordless authentication with Supabase
+// Supports magic link and passkey (WebAuthn) authentication
+
+generator client {
+ provider = "prisma-client-js"
+ output = "../src/generated/prisma"
+}
+
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+}
+
+model User {
+ id String @id @default(cuid())
+ email String @unique
+ name String @default("")
+ createdAt DateTime @default(now()) @map("created_at")
+ updatedAt DateTime @updatedAt @map("updated_at")
+
+ // Relations
+ magicLinks MagicLink[]
+ passkeys Passkey[]
+ sessions Session[]
+
+ @@map("users")
+}
+
+model MagicLink {
+ id String @id @default(cuid())
+ userId String @map("user_id")
+ token String @unique
+ expiresAt DateTime @map("expires_at")
+ usedAt DateTime? @map("used_at")
+ createdAt DateTime @default(now()) @map("created_at")
+
+ // Relations
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("magic_links")
+}
+
+model Passkey {
+ id String @id @default(cuid())
+ userId String @map("user_id")
+ credentialId String @unique @map("credential_id")
+ publicKey Bytes @map("public_key")
+ counter BigInt @default(0)
+ name String? // Optional name for the passkey (e.g., "iPhone", "MacBook")
+ createdAt DateTime @default(now()) @map("created_at")
+
+ // Relations
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("passkeys")
+}
+
+model Session {
+ id String @id @default(cuid())
+ userId String @map("user_id")
+ token String @unique
+ refreshToken String @unique @map("refresh_token")
+ expiresAt DateTime @map("expires_at")
+ refreshExpiresAt DateTime @map("refresh_expires_at")
+ authMethod AuthMethod @map("auth_method")
+ createdAt DateTime @default(now()) @map("created_at")
+
+ // Relations
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+ @@map("sessions")
+}
+
+enum AuthMethod {
+ MAGIC_LINK
+ PASSKEY
+}
diff --git a/public/images/book.png b/public/images/book.png
new file mode 100644
index 0000000..99dc406
Binary files /dev/null and b/public/images/book.png differ
diff --git a/public/images/eric.jpeg b/public/images/eric.jpeg
new file mode 100644
index 0000000..d219f06
Binary files /dev/null and b/public/images/eric.jpeg differ
diff --git a/public/images/error.png b/public/images/error.png
new file mode 100644
index 0000000..14d7989
Binary files /dev/null and b/public/images/error.png differ
diff --git a/public/images/jan-cropped.webp b/public/images/jan-cropped.webp
new file mode 100644
index 0000000..a30112c
Binary files /dev/null and b/public/images/jan-cropped.webp differ
diff --git a/public/images/login-background.png b/public/images/login-background.png
new file mode 100644
index 0000000..51755fc
Binary files /dev/null and b/public/images/login-background.png differ
diff --git a/public/images/not-found.png b/public/images/not-found.png
new file mode 100644
index 0000000..a9f4236
Binary files /dev/null and b/public/images/not-found.png differ
diff --git a/public/images/register-background.png b/public/images/register-background.png
new file mode 100644
index 0000000..7f60eed
Binary files /dev/null and b/public/images/register-background.png differ
diff --git a/public/images/sparkly-2.png b/public/images/sparkly-2.png
new file mode 100644
index 0000000..6d2d7b3
Binary files /dev/null and b/public/images/sparkly-2.png differ
diff --git a/public/images/sparkly.png b/public/images/sparkly.png
new file mode 100644
index 0000000..06edaf1
Binary files /dev/null and b/public/images/sparkly.png differ
diff --git a/src/components/base-sheet/side.tsx b/src/components/base-sheet/side.tsx
new file mode 100644
index 0000000..f47f92c
--- /dev/null
+++ b/src/components/base-sheet/side.tsx
@@ -0,0 +1,196 @@
+import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp } from 'lucide-react';
+
+import {
+ Sheet,
+ SheetBody,
+ SheetClose,
+ SheetContent,
+ SheetDescription,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@/components/ui/base-sheet';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Textarea } from '@/components/ui/textarea';
+
+export default function DemoSheet() {
+ return (
+
+
+ }>
+ Top
+
+
+
+ Quick Feedback
+
+ Share your feedback to help us improve.
+
+
+
+
+ {/* Name */}
+
+ Name
+
+
+ {/* Email */}
+
+ Email
+
+
+ {/* Feedback */}
+
+
Feedback
+
+
+ Please don't include any sensitive information
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+
+ }>
+ Right
+
+
+
+ Quick Feedback
+
+ Share your feedback to help us improve.
+
+
+
+
+ {/* Name */}
+
+ Name
+
+
+ {/* Email */}
+
+ Email
+
+
+ {/* Feedback */}
+
+
Feedback
+
+
+ Please don't include any sensitive information
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+
+ }>
+ Bottom
+
+
+
+ Quick Feedback
+
+ Share your feedback to help us improve.
+
+
+
+
+ {/* Name */}
+
+ Name
+
+
+ {/* Email */}
+
+ Email
+
+
+ {/* Feedback */}
+
+
Feedback
+
+
+ Please don't include any sensitive information
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+
+ }>
+ Left
+
+
+
+ Quick Feedback
+
+ Share your feedback to help us improve.
+
+
+
+
+ {/* Name */}
+
+ Name
+
+
+ {/* Email */}
+
+ Email
+
+
+ {/* Feedback */}
+
+
Feedback
+
+
+ Please don't include any sensitive information
+
+
+
+
+
+ Cancel
+ Submit
+
+
+
+
+ );
+}
diff --git a/src/components/dark-mode-toggle.tsx b/src/components/dark-mode-toggle.tsx
new file mode 100644
index 0000000..b4c7ecd
--- /dev/null
+++ b/src/components/dark-mode-toggle.tsx
@@ -0,0 +1,38 @@
+import { Moon, Sun } from 'lucide-react';
+import { useTheme } from 'next-themes';
+import * as React from 'react';
+
+import { Button } from '@/components/ui/button';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu';
+
+export function ModeToggle() {
+ const { setTheme } = useTheme();
+
+ return (
+
+
+
+
+
+ Toggle theme
+
+
+
+ setTheme('light')}>
+ Light
+
+ setTheme('dark')}>
+ Dark
+
+ setTheme('system')}>
+ System
+
+
+
+ );
+}
diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx
new file mode 100644
index 0000000..3dc03fe
--- /dev/null
+++ b/src/components/theme-provider.tsx
@@ -0,0 +1,9 @@
+import { ThemeProvider as NextThemesProvider } from 'next-themes';
+import * as React from 'react';
+
+export function ThemeProvider({
+ children,
+ ...props
+}: React.ComponentProps) {
+ return {children} ;
+}
diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx
new file mode 100644
index 0000000..d70230c
--- /dev/null
+++ b/src/components/ui/alert.tsx
@@ -0,0 +1,66 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+const alertVariants = cva(
+ 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
+ {
+ variants: {
+ variant: {
+ default: 'bg-card text-card-foreground',
+ destructive:
+ 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+);
+
+function Alert({
+ className,
+ variant,
+ ...props
+}: React.ComponentProps<'div'> & VariantProps) {
+ return (
+
+ );
+}
+
+function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function AlertDescription({
+ className,
+ ...props
+}: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+export { Alert, AlertDescription, AlertTitle };
diff --git a/src/components/ui/base-button.tsx b/src/components/ui/base-button.tsx
new file mode 100644
index 0000000..bab8949
--- /dev/null
+++ b/src/components/ui/base-button.tsx
@@ -0,0 +1,459 @@
+import { mergeProps } from '@base-ui-components/react/merge-props';
+import { useRender } from '@base-ui-components/react/use-render';
+import { cva, type VariantProps } from 'class-variance-authority';
+import type { LucideIcon } from 'lucide-react';
+import { ChevronDown } from 'lucide-react';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+const buttonVariants = cva(
+ 'cursor-pointer group whitespace-nowrap focus-visible:outline-hidden inline-flex items-center justify-center has-data-[arrow=true]:justify-between whitespace-nowrap text-sm font-medium ring-offset-background transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-60 [&_svg]:shrink-0',
+ {
+ variants: {
+ variant: {
+ primary:
+ 'bg-primary text-primary-foreground hover:bg-primary/90 data-[state=open]:bg-primary/90',
+ mono: 'bg-zinc-950 text-white dark:bg-zinc-300 dark:text-black hover:bg-zinc-950/90 dark:hover:bg-zinc-300/90 data-[state=open]:bg-zinc-950/90 dark:data-[state=open]:bg-zinc-300/90',
+ destructive:
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90 data-[state=open]:bg-destructive/90',
+ secondary:
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/90 data-[state=open]:bg-secondary/90',
+ outline:
+ 'bg-background text-accent-foreground border border-input hover:bg-accent data-[state=open]:bg-accent',
+ dashed:
+ 'text-accent-foreground border border-input border-dashed bg-background hover:bg-accent hover:text-accent-foreground data-[state=open]:text-accent-foreground',
+ ghost:
+ 'text-accent-foreground hover:bg-accent hover:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
+ dim: 'text-muted-foreground hover:text-foreground data-[state=open]:text-foreground',
+ foreground: '',
+ inverse: '',
+ },
+ appearance: {
+ default: '',
+ ghost: '',
+ },
+ underline: {
+ solid: '',
+ dashed: '',
+ },
+ underlined: {
+ solid: '',
+ dashed: '',
+ },
+ size: {
+ lg: 'h-10 rounded-md px-4 text-sm gap-1.5 [&_svg:not([class*=size-])]:size-4',
+ md: 'h-8.5 rounded-md px-3 gap-1.5 text-[0.8125rem] leading-(--text-sm--line-height) [&_svg:not([class*=size-])]:size-4',
+ sm: 'h-7 rounded-md px-2.5 gap-1.25 text-xs [&_svg:not([class*=size-])]:size-3.5',
+ icon: 'size-8.5 rounded-md [&_svg:not([class*=size-])]:size-4 shrink-0',
+ },
+ autoHeight: {
+ true: '',
+ false: '',
+ },
+ shape: {
+ default: '',
+ circle: 'rounded-full',
+ },
+ mode: {
+ default:
+ 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
+ icon: 'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
+ link: 'text-primary h-auto p-0 bg-transparent rounded-none hover:bg-transparent data-[state=open]:bg-transparent',
+ input: `
+ justify-start font-normal hover:bg-background [&_svg]:transition-colors [&_svg]:hover:text-foreground data-[state=open]:bg-background
+ focus-visible:border-ring focus-visible:outline-hidden focus-visible:ring-[3px] focus-visible:ring-ring/30
+ [[data-state=open]>&]:border-ring [[data-state=open]>&]:outline-hidden [[data-state=open]>&]:ring-[3px]
+ [[data-state=open]>&]:ring-ring/30
+ aria-invalid:border-destructive/60 aria-invalid:ring-destructive/10 dark:aria-invalid:border-destructive dark:aria-invalid:ring-destructive/20
+ in-data-[invalid=true]:border-destructive/60 in-data-[invalid=true]:ring-destructive/10 dark:in-data-[invalid=true]:border-destructive dark:in-data-[invalid=true]:ring-destructive/20
+ `,
+ },
+ placeholder: {
+ true: 'text-muted-foreground',
+ false: '',
+ },
+ },
+ compoundVariants: [
+ // Icons opacity for default mode
+ {
+ variant: 'ghost',
+ mode: 'default',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+ {
+ variant: 'outline',
+ mode: 'default',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+ {
+ variant: 'dashed',
+ mode: 'default',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+ {
+ variant: 'secondary',
+ mode: 'default',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+
+ // Icons opacity for default mode
+ {
+ variant: 'outline',
+ mode: 'input',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+ {
+ variant: 'outline',
+ mode: 'icon',
+ className:
+ '[&_svg:not([role=img]):not([class*=text-]):not([class*=opacity-])]:opacity-60',
+ },
+
+ // Auto height
+ {
+ size: 'md',
+ autoHeight: true,
+ className: 'h-auto min-h-8.5',
+ },
+ {
+ size: 'sm',
+ autoHeight: true,
+ className: 'h-auto min-h-7',
+ },
+ {
+ size: 'lg',
+ autoHeight: true,
+ className: 'h-auto min-h-10',
+ },
+
+ // Shadow support
+ {
+ variant: 'primary',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'mono',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'secondary',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'outline',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'dashed',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'destructive',
+ mode: 'default',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+
+ // Shadow support
+ {
+ variant: 'primary',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'mono',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'secondary',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'outline',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'dashed',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+ {
+ variant: 'destructive',
+ mode: 'icon',
+ appearance: 'default',
+ className: 'shadow-xs shadow-black/5',
+ },
+
+ // Link
+ {
+ variant: 'primary',
+ mode: 'link',
+ underline: 'solid',
+ className:
+ 'font-medium text-primary hover:text-primary/90 [&_svg:not([role=img]):not([class*=text-])]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-solid',
+ },
+ {
+ variant: 'primary',
+ mode: 'link',
+ underline: 'dashed',
+ className:
+ 'font-medium text-primary hover:text-primary/90 [&_svg]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-dashed decoration-1',
+ },
+ {
+ variant: 'primary',
+ mode: 'link',
+ underlined: 'solid',
+ className:
+ 'font-medium text-primary hover:text-primary/90 [&_svg:not([role=img]):not([class*=text-])]:opacity-60 underline underline-offset-4 decoration-solid',
+ },
+ {
+ variant: 'primary',
+ mode: 'link',
+ underlined: 'dashed',
+ className:
+ 'font-medium text-primary hover:text-primary/90 [&_svg]:opacity-60 underline underline-offset-4 decoration-dashed decoration-1',
+ },
+
+ {
+ variant: 'inverse',
+ mode: 'link',
+ underline: 'solid',
+ className:
+ 'font-medium text-inherit [&_svg:not([role=img]):not([class*=text-])]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-solid',
+ },
+ {
+ variant: 'inverse',
+ mode: 'link',
+ underline: 'dashed',
+ className:
+ 'font-medium text-inherit [&_svg:not([role=img]):not([class*=text-])]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-dashed decoration-1',
+ },
+ {
+ variant: 'inverse',
+ mode: 'link',
+ underlined: 'solid',
+ className:
+ 'font-medium text-inherit [&_svg:not([role=img]):not([class*=text-])]:opacity-60 underline underline-offset-4 decoration-solid',
+ },
+ {
+ variant: 'inverse',
+ mode: 'link',
+ underlined: 'dashed',
+ className:
+ 'font-medium text-inherit [&_svg:not([role=img]):not([class*=text-])]:opacity-60 underline underline-offset-4 decoration-dashed decoration-1',
+ },
+
+ {
+ variant: 'foreground',
+ mode: 'link',
+ underline: 'solid',
+ className:
+ 'font-medium text-foreground [&_svg:not([role=img]):not([class*=text-])]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-solid',
+ },
+ {
+ variant: 'foreground',
+ mode: 'link',
+ underline: 'dashed',
+ className:
+ 'font-medium text-foreground [&_svg:not([role=img]):not([class*=text-])]:opacity-60 hover:underline hover:underline-offset-4 hover:decoration-dashed decoration-1',
+ },
+ {
+ variant: 'foreground',
+ mode: 'link',
+ underlined: 'solid',
+ className:
+ 'font-medium text-foreground [&_svg:not([role=img]):not([class*=text-])]:opacity-60 underline underline-offset-4 decoration-solid',
+ },
+ {
+ variant: 'foreground',
+ mode: 'link',
+ underlined: 'dashed',
+ className:
+ 'font-medium text-foreground [&_svg:not([role=img]):not([class*=text-])]:opacity-60 underline underline-offset-4 decoration-dashed decoration-1',
+ },
+
+ // Ghost
+ {
+ variant: 'primary',
+ appearance: 'ghost',
+ className:
+ 'bg-transparent text-primary/90 hover:bg-primary/5 data-[state=open]:bg-primary/5',
+ },
+ {
+ variant: 'destructive',
+ appearance: 'ghost',
+ className:
+ 'bg-transparent text-destructive/90 hover:bg-destructive/5 data-[state=open]:bg-destructive/5',
+ },
+ {
+ variant: 'ghost',
+ mode: 'icon',
+ className: 'text-muted-foreground',
+ },
+
+ // Size
+ {
+ size: 'sm',
+ mode: 'icon',
+ className: 'w-7 h-7 p-0 [[&_svg:not([class*=size-])]:size-3.5',
+ },
+ {
+ size: 'md',
+ mode: 'icon',
+ className: 'w-8.5 h-8.5 p-0 [&_svg:not([class*=size-])]:size-4',
+ },
+ {
+ size: 'icon',
+ className: 'w-8.5 h-8.5 p-0 [&_svg:not([class*=size-])]:size-4',
+ },
+ {
+ size: 'lg',
+ mode: 'icon',
+ className: 'w-10 h-10 p-0 [&_svg:not([class*=size-])]:size-4',
+ },
+
+ // Input mode
+ {
+ mode: 'input',
+ placeholder: true,
+ variant: 'outline',
+ className: 'font-normal text-muted-foreground',
+ },
+ {
+ mode: 'input',
+ variant: 'outline',
+ size: 'sm',
+ className: 'gap-1.25',
+ },
+ {
+ mode: 'input',
+ variant: 'outline',
+ size: 'md',
+ className: 'gap-1.5',
+ },
+ {
+ mode: 'input',
+ variant: 'outline',
+ size: 'lg',
+ className: 'gap-1.5',
+ },
+ ],
+ defaultVariants: {
+ variant: 'primary',
+ mode: 'default',
+ size: 'md',
+ shape: 'default',
+ appearance: 'default',
+ },
+ },
+);
+
+export type ButtonProps = {
+ selected?: boolean;
+ asChild?: boolean;
+} & useRender.ComponentProps<'button'> &
+ VariantProps;
+
+function Button({
+ render,
+ asChild = false,
+ children,
+ className,
+ selected,
+ variant,
+ shape,
+ appearance,
+ mode,
+ size,
+ autoHeight,
+ underlined,
+ underline,
+ placeholder = false,
+ ...props
+}: ButtonProps) {
+ const defaultProps = {
+ 'data-slot': 'button',
+ className: cn(
+ buttonVariants({
+ variant,
+ size,
+ shape,
+ appearance,
+ mode,
+ autoHeight,
+ placeholder,
+ underlined,
+ underline,
+ className,
+ }),
+ asChild && props.disabled && 'pointer-events-none opacity-50',
+ ),
+ ...(selected && { 'data-state': 'open' as const }),
+ };
+
+ // Determine render element based on asChild prop
+ const renderElement =
+ asChild && React.isValidElement(children)
+ ? (children as React.ReactElement<
+ Record,
+ string | React.JSXElementConstructor
+ >)
+ : render || ;
+
+ // When using asChild, children becomes the element props, otherwise use children normally
+ const finalProps =
+ asChild && React.isValidElement(children)
+ ? mergeProps(defaultProps, props)
+ : mergeProps(defaultProps, { ...props, children });
+
+ const element = useRender({
+ render: renderElement,
+ props: finalProps,
+ });
+
+ return element;
+}
+
+type ButtonArrowProps = {
+ icon?: LucideIcon;
+} & React.SVGProps;
+
+function ButtonArrow({
+ icon: Icon = ChevronDown,
+ className,
+ ...props
+}: ButtonArrowProps) {
+ return (
+
+ );
+}
+
+export { Button, ButtonArrow, buttonVariants };
diff --git a/src/components/ui/base-sheet.tsx b/src/components/ui/base-sheet.tsx
new file mode 100644
index 0000000..b03c0f2
--- /dev/null
+++ b/src/components/ui/base-sheet.tsx
@@ -0,0 +1,176 @@
+import { Dialog as SheetPrimitive } from '@base-ui-components/react/dialog';
+import { XIcon } from 'lucide-react';
+import * as React from 'react';
+
+import { buttonVariants } from '@/components/ui/base-button';
+import { cn } from '@/lib/utils';
+
+function Sheet({ ...props }: React.ComponentProps) {
+ return ;
+}
+
+function SheetTrigger({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function SheetClose({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SheetAction({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SheetPortal({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function SheetBackdrop({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SheetContent({
+ className,
+ children,
+ side = 'right',
+ ...props
+}: React.ComponentProps & {
+ side?: 'top' | 'right' | 'bottom' | 'left';
+}) {
+ return (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+ );
+}
+
+function SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function SheetBody({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function SheetTitle({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SheetDescription({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export {
+ Sheet,
+ SheetAction,
+ SheetBody,
+ SheetClose,
+ SheetContent,
+ SheetDescription,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+};
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..90f392e
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,59 @@
+import { cva, type VariantProps } from 'class-variance-authority';
+import { Slot as SlotPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ {
+ variants: {
+ variant: {
+ default:
+ 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
+ destructive:
+ 'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
+ secondary:
+ 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
+ ghost:
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
+ link: 'text-primary underline-offset-4 hover:underline',
+ },
+ size: {
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
+ icon: 'size-9',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ },
+);
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'button'> &
+ VariantProps & {
+ asChild?: boolean;
+ }) {
+ const Comp = asChild ? SlotPrimitive.Slot : 'button';
+
+ return (
+
+ );
+}
+
+export { Button, buttonVariants };
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
new file mode 100644
index 0000000..55727b5
--- /dev/null
+++ b/src/components/ui/card.tsx
@@ -0,0 +1,92 @@
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Card({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+export {
+ Card,
+ CardAction,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+};
diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx
new file mode 100644
index 0000000..827ce6c
--- /dev/null
+++ b/src/components/ui/dropdown-menu.tsx
@@ -0,0 +1,255 @@
+import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
+import { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function DropdownMenu({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function DropdownMenuPortal({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuTrigger({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+function DropdownMenuGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuItem({
+ className,
+ inset,
+ variant = 'default',
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+ variant?: 'default' | 'destructive';
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuCheckboxItem({
+ className,
+ children,
+ checked,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuRadioGroup({
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuRadioItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function DropdownMenuLabel({
+ className,
+ inset,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+}) {
+ return (
+
+ );
+}
+
+function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function DropdownMenuShortcut({
+ className,
+ ...props
+}: React.ComponentProps<'span'>) {
+ return (
+
+ );
+}
+
+function DropdownMenuSub({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function DropdownMenuSubTrigger({
+ className,
+ inset,
+ children,
+ ...props
+}: React.ComponentProps & {
+ inset?: boolean;
+}) {
+ return (
+
+ {children}
+
+
+ );
+}
+
+function DropdownMenuSubContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuPortal,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
+};
diff --git a/src/components/ui/form.tsx b/src/components/ui/form.tsx
new file mode 100644
index 0000000..99bc151
--- /dev/null
+++ b/src/components/ui/form.tsx
@@ -0,0 +1,155 @@
+import type * as LabelPrimitive from '@radix-ui/react-label';
+import { Slot } from '@radix-ui/react-slot';
+import * as React from 'react';
+
+import { Label } from '@/components/ui/label';
+import { cn } from '@/lib/utils';
+
+type FormFieldContextValue = {
+ name: string;
+ error?: string;
+};
+
+const FormFieldContext = React.createContext(
+ undefined,
+);
+
+function Form({ className, ref, ...props }: React.ComponentProps<'form'>) {
+ return ;
+}
+
+type FormFieldProps = {
+ name: string;
+ error?: string;
+ children: React.ReactNode;
+};
+
+const FormField = ({ name, error, children }: FormFieldProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+const useFormField = () => {
+ const fieldContext = React.useContext(FormFieldContext);
+ const itemContext = React.useContext(FormItemContext);
+
+ if (fieldContext === undefined) {
+ throw new Error('useFormField should be used within ');
+ }
+
+ const { id } = itemContext;
+
+ return {
+ id,
+ name: fieldContext.name,
+ formItemId: `${id}-form-item`,
+ formDescriptionId: `${id}-form-item-description`,
+ formMessageId: `${id}-form-item-message`,
+ error: fieldContext.error,
+ };
+};
+
+type FormItemContextValue = {
+ id: string;
+};
+
+const FormItemContext = React.createContext(
+ {} as FormItemContextValue,
+);
+
+function FormItem({ className, ...props }: React.ComponentProps<'div'>) {
+ const id = React.useId();
+
+ return (
+
+
+
+ );
+}
+
+function FormLabel({
+ className,
+ ...props
+}: React.ComponentProps) {
+ const { error, formItemId } = useFormField();
+
+ return (
+
+ );
+}
+
+function FormControl({ ...props }: React.ComponentProps) {
+ const { error, name, formItemId, formDescriptionId, formMessageId } =
+ useFormField();
+
+ return (
+
+ );
+}
+
+function FormDescription({ className, ...props }: React.ComponentProps<'p'>) {
+ const { formDescriptionId } = useFormField();
+
+ return (
+
+ );
+}
+
+function FormMessage({ className, ...props }: React.ComponentProps<'p'>) {
+ const { error, formMessageId } = useFormField();
+ const body = error ? String(error) : props.children;
+
+ if (!body) {
+ return;
+ }
+
+ return (
+
+ {body}
+
+ );
+}
+
+export {
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+ useFormField,
+};
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..3c1cfca
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
+ return (
+
+ );
+}
+
+export { Input };
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
new file mode 100644
index 0000000..af666c9
--- /dev/null
+++ b/src/components/ui/label.tsx
@@ -0,0 +1,22 @@
+import { Label as LabelPrimitive } from 'radix-ui';
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Label({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export { Label };
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..5f558e7
--- /dev/null
+++ b/src/components/ui/textarea.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
+ return (
+
+ );
+}
+
+export { Textarea };
diff --git a/src/features/authenticate/login-form/login-form-component.test.jsx b/src/features/authenticate/login-form/login-form-component.test.jsx
new file mode 100644
index 0000000..2886f63
--- /dev/null
+++ b/src/features/authenticate/login-form/login-form-component.test.jsx
@@ -0,0 +1,133 @@
+import render from 'riteway/render-component';
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import { LoginForm } from './login-form-component';
+
+const createProps = ({ emailError = '', isSigningIn = false } = {}) => ({
+ emailError,
+ isSigningIn,
+});
+
+describe('LoginForm component', () => {
+ test('basic elements', () => {
+ const props = createProps();
+
+ const $ = render( );
+
+ assert({
+ given: 'any props',
+ should: 'render the title',
+ actual: $('h1').text(),
+ expected: 'Sign in to your account',
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the subtitle',
+ actual: $('p').text(),
+ expected: 'Enter your email to receive a secure sign-in link',
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the email input field',
+ actual: $('input[name="email"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the submit button',
+ actual: $('button[type="submit"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the sign up link',
+ actual: $('a[href="/register"]').length,
+ expected: 1,
+ });
+ });
+
+ test('submit button text', () => {
+ const propsDefault = createProps();
+ const propsLoading = createProps({ isSigningIn: true });
+
+ const $default = render( );
+ const $loading = render( );
+
+ assert({
+ given: 'isSigningIn is false',
+ should: 'show default button text',
+ actual: $default('button[type="submit"]').text(),
+ expected: 'Send sign-in link',
+ });
+
+ assert({
+ given: 'isSigningIn is true',
+ should: 'show loading button text',
+ actual: $loading('button[type="submit"]').text().trim(),
+ expected: 'Sending link...',
+ });
+ });
+
+ test('email error display', () => {
+ const propsWithError = createProps({
+ emailError: 'Invalid email address',
+ });
+ const propsWithoutError = createProps();
+
+ const $withError = render( );
+ const $withoutError = render( );
+
+ assert({
+ given: 'emailError prop is provided',
+ should: 'display the error message',
+ actual: $withError('p:contains("Invalid email address")').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'no emailError prop',
+ should: 'not display any error message',
+ actual: $withoutError('[data-slot="form-message"]').length,
+ expected: 0,
+ });
+ });
+
+ test('form disabled state', () => {
+ const propsDisabled = createProps({ isSigningIn: true });
+ const propsEnabled = createProps({ isSigningIn: false });
+
+ const $disabled = render( );
+ const $enabled = render( );
+
+ assert({
+ given: 'isSigningIn is true',
+ should: 'disable the fieldset',
+ actual: $disabled('fieldset').prop('disabled'),
+ expected: true,
+ });
+
+ assert({
+ given: 'isSigningIn is false',
+ should: 'enable the fieldset',
+ actual: $enabled('fieldset').prop('disabled'),
+ expected: false,
+ });
+ });
+
+ test('sign up link', () => {
+ const props = createProps();
+ const $ = render( );
+
+ assert({
+ given: 'the login form',
+ should: 'contain a link to sign up',
+ actual: $('a:contains("Sign up")').attr('href'),
+ expected: '/register',
+ });
+ });
+});
diff --git a/src/features/authenticate/login-form/login-form-component.tsx b/src/features/authenticate/login-form/login-form-component.tsx
new file mode 100644
index 0000000..12ad99f
--- /dev/null
+++ b/src/features/authenticate/login-form/login-form-component.tsx
@@ -0,0 +1,86 @@
+import { Loader2Icon } from 'lucide-react';
+import Link from 'next/link';
+import type { ComponentProps, FormEvent } from 'react';
+
+import { Button } from '@/components/ui/button';
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
+import { cn } from '@/lib/utils';
+
+type LoginFormProps = {
+ emailError?: string;
+ isSigningIn?: boolean;
+ onSignInClicked?: (data: { email: string }) => void;
+} & ComponentProps<'form'>;
+
+export function LoginForm({
+ className,
+ emailError,
+ isSigningIn,
+ onSignInClicked,
+ ...props
+}: LoginFormProps) {
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault();
+ const formData = new FormData(event.currentTarget);
+ const email = formData.get('email') as string;
+
+ if (onSignInClicked) {
+ onSignInClicked({ email });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/features/authenticate/login-form/login-form-container.js b/src/features/authenticate/login-form/login-form-container.js
new file mode 100644
index 0000000..ab3c7e7
--- /dev/null
+++ b/src/features/authenticate/login-form/login-form-container.js
@@ -0,0 +1,80 @@
+import { useState } from 'react';
+import { connect } from 'react-redux';
+import z from 'zod';
+
+import { showVerificationAwaiting } from '@/features/authenticate/user-authentication-reducer';
+import { createClient } from '@/lib/supabase/component';
+
+import { LoginForm } from './login-form-component';
+
+const schema = z.object({
+ email: z.email('Please enter a valid email address'),
+});
+
+function LoginFormContainer({
+ showVerificationAwaiting: showVerificationAwaitingAction,
+}) {
+ const [emailError, setEmailError] = useState('');
+ const [isSigningIn, setIsSigningIn] = useState(false);
+ const supabase = createClient();
+
+ async function handleSubmit({ email }) {
+ // Reset errors
+ setEmailError('');
+
+ // Validate with schema
+ const validation = schema.safeParse({ email });
+
+ if (!validation.success) {
+ const errorTree = z.treeifyError(validation.error);
+ const emailErrors = errorTree.properties?.email?.errors;
+
+ if (emailErrors?.length) setEmailError(emailErrors[0]);
+ return;
+ }
+
+ // Start signing in process
+ setIsSigningIn(true);
+
+ try {
+ // Call Supabase for existing user login
+ const { error } = await supabase.auth.signInWithOtp({
+ email,
+ options: { shouldCreateUser: false },
+ });
+
+ if (error) {
+ // Handle specific error cases
+ if (error.message?.includes('User not found')) {
+ setEmailError(
+ 'No account found with this email. Would you like to sign up instead?',
+ );
+ } else {
+ setEmailError(error.message || 'An error occurred during sign in');
+ }
+ return;
+ }
+
+ // Success - dispatch action to show verification awaiting form
+ showVerificationAwaitingAction();
+ } finally {
+ setIsSigningIn(false);
+ }
+ }
+
+ return (
+
+ );
+}
+
+const mapStateToProps = undefined;
+
+const mapDispatchToProps = {
+ showVerificationAwaiting,
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(LoginFormContainer);
diff --git a/src/features/authenticate/register-form/register-form-component.test.jsx b/src/features/authenticate/register-form/register-form-component.test.jsx
new file mode 100644
index 0000000..e12c097
--- /dev/null
+++ b/src/features/authenticate/register-form/register-form-component.test.jsx
@@ -0,0 +1,115 @@
+import render from 'riteway/render-component';
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import { RegisterForm } from './register-form-component';
+
+const createProps = ({
+ emailError = '',
+ nameError = '',
+ isSigningUp = false,
+} = {}) => ({ emailError, nameError, isSigningUp });
+
+describe('RegisterForm component', () => {
+ test('basic elements', () => {
+ const props = createProps();
+
+ const $ = render( );
+
+ assert({
+ given: 'any props',
+ should: 'render the title',
+ actual: $('h1').text(),
+ expected: 'Create an account',
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the subtitle',
+ actual: $('p').text(),
+ expected: 'Enter your information to get started',
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the name input field',
+ actual: $('input[name="name"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the email input field',
+ actual: $('input[name="email"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'any props',
+ should: 'render the submit button',
+ actual: $('button[type="submit"]').length,
+ expected: 1,
+ });
+ });
+
+ test('error messages', () => {
+ const props = createProps({
+ nameError: 'Name is required',
+ emailError: 'Invalid email address',
+ });
+
+ const $ = render( );
+
+ assert({
+ given: 'name error prop',
+ should: 'render the name error message',
+ actual: $('[data-slot="form-message"]').eq(0).text(),
+ expected: 'Name is required',
+ });
+
+ assert({
+ given: 'email error prop',
+ should: 'render the email error message',
+ actual: $('[data-slot="form-message"]').eq(1).text(),
+ expected: 'Invalid email address',
+ });
+ });
+
+ test('isSigningUp prop when false', () => {
+ const props = createProps({ isSigningUp: false });
+ const $ = render( );
+
+ assert({
+ given: 'isSigningUp is false',
+ should: 'render "Sign up" button text',
+ actual: $('button[type="submit"]').text(),
+ expected: 'Sign up',
+ });
+
+ assert({
+ given: 'isSigningUp is false',
+ should: 'not disable the form fieldset',
+ actual: $('fieldset').prop('disabled'),
+ expected: false,
+ });
+ });
+
+ test('isSigningUp prop when true', () => {
+ const props = createProps({ isSigningUp: true });
+ const $ = render( );
+
+ assert({
+ given: 'isSigningUp is true',
+ should: 'render "Signing up ..." button text',
+ actual: $('button[type="submit"]').text().includes('Signing up ...'),
+ expected: true,
+ });
+
+ assert({
+ given: 'isSigningUp is true',
+ should: 'disable the form fieldset',
+ actual: $('fieldset').prop('disabled'),
+ expected: true,
+ });
+ });
+});
diff --git a/src/features/authenticate/register-form/register-form-component.tsx b/src/features/authenticate/register-form/register-form-component.tsx
new file mode 100644
index 0000000..96144e8
--- /dev/null
+++ b/src/features/authenticate/register-form/register-form-component.tsx
@@ -0,0 +1,101 @@
+import { Loader2Icon } from 'lucide-react';
+import Link from 'next/link';
+import type { ComponentProps, FormEvent } from 'react';
+
+import { Button } from '@/components/ui/button';
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
+import { cn } from '@/lib/utils';
+
+type RegisterFormProps = {
+ emailError?: string;
+ isSigningUp?: boolean;
+ nameError?: string;
+ onSignUpClicked?: (data: { name: string; email: string }) => void;
+} & ComponentProps<'form'>;
+
+export function RegisterForm({
+ className,
+ emailError,
+ isSigningUp,
+ nameError,
+ onSignUpClicked,
+ ...props
+}: RegisterFormProps) {
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault();
+ const formData = new FormData(event.currentTarget);
+ const name = formData.get('name') as string;
+ const email = formData.get('email') as string;
+
+ if (onSignUpClicked) {
+ onSignUpClicked({ name, email });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/features/authenticate/register-form/register-form-container.js b/src/features/authenticate/register-form/register-form-container.js
new file mode 100644
index 0000000..f208ac1
--- /dev/null
+++ b/src/features/authenticate/register-form/register-form-container.js
@@ -0,0 +1,83 @@
+import { useState } from 'react';
+import { connect } from 'react-redux';
+import z from 'zod';
+
+import { showVerificationAwaiting } from '@/features/authenticate/user-authentication-reducer';
+import { createClient } from '@/lib/supabase/component';
+
+import { RegisterForm } from './register-form-component';
+
+const schema = z.object({
+ name: z.string().min(3, 'Name must be at least 3 characters'),
+ email: z.email('Please enter a valid email address'),
+});
+
+function RegisterFormContainer({
+ showVerificationAwaiting: showVerificationAwaitingAction,
+}) {
+ const [nameError, setNameError] = useState('');
+ const [emailError, setEmailError] = useState('');
+ const [isSigningUp, setIsSigningUp] = useState(false);
+ const supabase = createClient();
+
+ async function handleSubmit({ name, email }) {
+ // Reset errors
+ setNameError('');
+ setEmailError('');
+
+ // Validate with schema
+ const validation = schema.safeParse({ name, email });
+
+ if (!validation.success) {
+ const errorTree = z.treeifyError(validation.error);
+ const nameErrors = errorTree.properties?.name?.errors;
+ const emailErrors = errorTree.properties?.email?.errors;
+
+ if (nameErrors?.length) setNameError(nameErrors[0]);
+ if (emailErrors?.length) setEmailError(emailErrors[0]);
+ return;
+ }
+
+ // Start signing up process
+ setIsSigningUp(true);
+
+ try {
+ // If validation passes, call Supabase
+ const { error } = await supabase.auth.signInWithOtp({
+ email,
+ options: { data: { name }, shouldCreateUser: true },
+ });
+
+ if (error) {
+ // Handle Supabase authentication errors
+ setEmailError(error.message || 'An error occurred during registration');
+ return;
+ }
+
+ // Success - dispatch action to show verification awaiting form
+ showVerificationAwaitingAction();
+ } finally {
+ setIsSigningUp(false);
+ }
+ }
+
+ return (
+
+ );
+}
+
+const mapStateToProps = undefined;
+
+const mapDispatchToProps = {
+ showVerificationAwaiting,
+};
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(RegisterFormContainer);
diff --git a/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.test.jsx b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.test.jsx
new file mode 100644
index 0000000..4fa3302
--- /dev/null
+++ b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.test.jsx
@@ -0,0 +1,189 @@
+import render from 'riteway/render-component';
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import { RegistrationVerificationAwaiting } from './registration-verification-awaiting-component';
+
+const createProps = ({
+ email = 'test@example.com',
+ secondsLeft = 60,
+ isResending = false,
+ isSubmitting = false,
+ onResendClick = () => {},
+} = {}) => ({
+ email,
+ secondsLeft,
+ isResending,
+ isSubmitting,
+ onResendClick,
+});
+
+describe('RegistrationVerificationAwaiting component', () => {
+ test('basic elements', () => {
+ const props = createProps();
+ const $ = render( );
+
+ assert({
+ given: 'default props',
+ should: 'render the card title',
+ actual: $('.text-xl').text(),
+ expected: 'Check your email',
+ });
+
+ assert({
+ given: 'default props',
+ should: 'render the card description',
+ actual: $('[data-slot="card-description"]').text(),
+ expected:
+ "We've sent a secure registration link to your email address. Please check your inbox and click the link to access your account.",
+ });
+
+ assert({
+ given: 'default props with 60 seconds left',
+ should: 'render the countdown message with seconds remaining',
+ actual: $('.text-muted-foreground.text-xs').text(),
+ expected: 'You can request a new registration link in 60 seconds.',
+ });
+
+ assert({
+ given: 'default props',
+ should: 'render the hidden email input with correct value',
+ actual: $('input[name="email"]').val(),
+ expected: 'test@example.com',
+ });
+
+ assert({
+ given: 'default props',
+ should: 'render the submit button with correct text',
+ actual: $('button[type="submit"]').text(),
+ expected: 'Request new registration link',
+ });
+
+ assert({
+ given: 'default props',
+ should: 'render the alert description',
+ actual: $('[data-slot="alert-description"]').text(),
+ expected: 'Remember to check your spam folder.',
+ });
+ });
+
+ test('button states when countdown is active', () => {
+ const props = createProps({ secondsLeft: 30 });
+ const $ = render( );
+
+ assert({
+ given: 'countdown is active (secondsLeft > 0)',
+ should: 'disable the fieldset',
+ actual: $('fieldset').prop('disabled'),
+ expected: true,
+ });
+
+ assert({
+ given: 'countdown is active (secondsLeft > 0)',
+ should: 'make button appear disabled via fieldset',
+ actual: $('fieldset[disabled] button[type="submit"]').length,
+ expected: 1,
+ });
+ });
+
+ test('button states when countdown reaches zero', () => {
+ const props = createProps({ secondsLeft: 0 });
+ const $ = render( );
+
+ assert({
+ given: 'countdown reaches zero',
+ should: 'enable the submit button',
+ actual: $('button[type="submit"]').prop('disabled'),
+ expected: false,
+ });
+
+ assert({
+ given: 'countdown reaches zero',
+ should: 'enable the fieldset',
+ actual: $('fieldset').prop('disabled'),
+ expected: false,
+ });
+ });
+
+ test('loading state when resending', () => {
+ const props = createProps({
+ isResending: true,
+ secondsLeft: 0,
+ });
+ const $ = render( );
+
+ assert({
+ given: 'isResending is true',
+ should: 'show loading text on button',
+ actual: $('button[type="submit"]').text(),
+ expected: 'Sending...',
+ });
+
+ assert({
+ given: 'isResending is true',
+ should: 'disable the fieldset',
+ actual: $('fieldset').prop('disabled'),
+ expected: true,
+ });
+
+ assert({
+ given: 'isResending is true',
+ should: 'render loading icon',
+ actual: $('svg.animate-spin').length,
+ expected: 1,
+ });
+ });
+
+ test('disabled state when submitting', () => {
+ const props = createProps({
+ isSubmitting: true,
+ secondsLeft: 0,
+ });
+ const $ = render( );
+
+ assert({
+ given: 'isSubmitting is true',
+ should: 'disable the fieldset even when countdown is zero',
+ actual: $('fieldset').prop('disabled'),
+ expected: true,
+ });
+ });
+
+ test('countdown message with different secondsLeft values', () => {
+ const propsWithCountdown = createProps({ secondsLeft: 30 });
+ const $withCountdown = render(
+ ,
+ );
+
+ assert({
+ given: '30 seconds left',
+ should: 'show countdown message with 30 seconds',
+ actual: $withCountdown('.text-muted-foreground.text-xs').text(),
+ expected: 'You can request a new registration link in 30 seconds.',
+ });
+
+ const propsAtZero = createProps({ secondsLeft: 0 });
+ const $atZero = render(
+ ,
+ );
+
+ assert({
+ given: '0 seconds left',
+ should: 'show message that new link can be requested',
+ actual: $atZero('.text-muted-foreground.text-xs').text(),
+ expected: 'You can now request a new registration link.',
+ });
+
+ const propsWithOne = createProps({ secondsLeft: 1 });
+ const $withOne = render(
+ ,
+ );
+
+ assert({
+ given: '1 second left',
+ should: 'show countdown message with 1 second',
+ actual: $withOne('.text-muted-foreground.text-xs').text(),
+ expected: 'You can request a new registration link in 1 seconds.',
+ });
+ });
+});
diff --git a/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.tsx b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.tsx
new file mode 100644
index 0000000..c687a1d
--- /dev/null
+++ b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-component.tsx
@@ -0,0 +1,98 @@
+import { Loader2Icon, TriangleAlertIcon } from 'lucide-react';
+import type { ComponentProps, FormEvent } from 'react';
+
+import { Alert, AlertDescription } from '@/components/ui/alert';
+import { Button } from '@/components/ui/button';
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
+
+type RegistrationVerificationAwaitingProps = {
+ email: string;
+ secondsLeft: number;
+ isResending?: boolean;
+ isSubmitting?: boolean;
+ onResendClick?: () => void;
+} & ComponentProps<'div'>;
+
+export function RegistrationVerificationAwaiting({
+ email,
+ secondsLeft,
+ isResending = false,
+ isSubmitting = false,
+ onResendClick,
+ ...props
+}: RegistrationVerificationAwaitingProps) {
+ const waitingToResend = secondsLeft !== 0;
+
+ // Generate countdown message based on secondsLeft
+ const displayCountdownMessage =
+ secondsLeft > 0
+ ? `You can request a new registration link in ${secondsLeft} seconds.`
+ : 'You can now request a new registration link.';
+
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault();
+
+ if (onResendClick) {
+ onResendClick();
+ }
+ };
+
+ return (
+
+
+
+ Check your email
+
+ We've sent a secure registration link to your email address.
+ Please check your inbox and click the link to access your account.
+
+
+
+
+
+
+ {displayCountdownMessage}
+
+
+
+
+
+
+
+ Remember to check your spam folder.
+
+
+
+
+
+
+ );
+}
diff --git a/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-container.js b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-container.js
new file mode 100644
index 0000000..3fcb954
--- /dev/null
+++ b/src/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-container.js
@@ -0,0 +1,24 @@
+import { useCountdown } from '../use-countdown';
+import { RegistrationVerificationAwaiting } from './registration-verification-awaiting-component';
+
+export function RegistrationVerificationAwaitingContainer({
+ email,
+ isResending = false,
+ isSubmitting = false,
+}) {
+ const { secondsLeft, reset } = useCountdown(60);
+
+ const handleResendClick = () => {
+ reset();
+ };
+
+ return (
+
+ );
+}
diff --git a/src/features/authenticate/use-countdown.test.tsx b/src/features/authenticate/use-countdown.test.tsx
new file mode 100644
index 0000000..ecf3c33
--- /dev/null
+++ b/src/features/authenticate/use-countdown.test.tsx
@@ -0,0 +1,248 @@
+import { act, renderHook } from '@testing-library/react';
+import { assert } from 'riteway/vitest';
+import { afterEach, beforeEach, describe, test, vi } from 'vitest';
+
+import { useCountdown } from './use-countdown';
+
+describe('useCountdown()', () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ });
+
+ afterEach(() => {
+ vi.clearAllTimers();
+ vi.useRealTimers();
+ });
+
+ test('initial state', () => {
+ const { result } = renderHook(() => useCountdown(60));
+
+ assert({
+ given: 'an initial time of 60 seconds',
+ should: 'initialize with that value',
+ actual: result.current.secondsLeft,
+ expected: 60,
+ });
+ });
+
+ test('countdown progression', () => {
+ const { result } = renderHook(() => useCountdown(3));
+
+ assert({
+ given: 'an initial time of 3 seconds',
+ should: 'start with 3 seconds',
+ actual: result.current.secondsLeft,
+ expected: 3,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(1000);
+ });
+
+ assert({
+ given: 'one second has passed',
+ should: 'count down to 2 seconds',
+ actual: result.current.secondsLeft,
+ expected: 2,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(1000);
+ });
+
+ assert({
+ given: 'two seconds have passed',
+ should: 'count down to 1 second',
+ actual: result.current.secondsLeft,
+ expected: 1,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(1000);
+ });
+
+ assert({
+ given: 'three seconds have passed',
+ should: 'reach zero and stop',
+ actual: result.current.secondsLeft,
+ expected: 0,
+ });
+ });
+
+ test('stops at zero', () => {
+ const { result } = renderHook(() => useCountdown(2));
+
+ act(() => {
+ vi.advanceTimersByTime(3000);
+ });
+
+ assert({
+ given: 'countdown reaches zero',
+ should: 'stop at zero',
+ actual: result.current.secondsLeft,
+ expected: 0,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(2000);
+ });
+
+ assert({
+ given: 'additional time passes after reaching zero',
+ should: 'remain at zero',
+ actual: result.current.secondsLeft,
+ expected: 0,
+ });
+ });
+
+ test('initial seconds change', () => {
+ const { result, rerender } = renderHook(
+ ({ initialSeconds }) => useCountdown(initialSeconds),
+ { initialProps: { initialSeconds: 5 } },
+ );
+
+ act(() => {
+ vi.advanceTimersByTime(2000);
+ });
+
+ assert({
+ given: 'countdown has progressed for 2 seconds',
+ should: 'show 3 seconds remaining',
+ actual: result.current.secondsLeft,
+ expected: 3,
+ });
+
+ rerender({ initialSeconds: 10 });
+
+ assert({
+ given: 'initial seconds changed to 10',
+ should: 'reset to new initial value',
+ actual: result.current.secondsLeft,
+ expected: 10,
+ });
+ });
+
+ test('zero or negative initial values', () => {
+ const { result: zeroResult } = renderHook(() => useCountdown(0));
+ const { result: negativeResult } = renderHook(() => useCountdown(-5));
+
+ assert({
+ given: 'initial value of zero',
+ should: 'remain at zero',
+ actual: zeroResult.current.secondsLeft,
+ expected: 0,
+ });
+
+ assert({
+ given: 'initial value of negative five',
+ should: 'remain at negative five',
+ actual: negativeResult.current.secondsLeft,
+ expected: -5,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(2000);
+ });
+
+ assert({
+ given: 'time passes with zero initial value',
+ should: 'not change from zero',
+ actual: zeroResult.current.secondsLeft,
+ expected: 0,
+ });
+
+ assert({
+ given: 'time passes with negative initial value',
+ should: 'not change from negative value',
+ actual: negativeResult.current.secondsLeft,
+ expected: -5,
+ });
+ });
+
+ test('cleanup on unmount', () => {
+ const { result, unmount } = renderHook(() => useCountdown(5));
+
+ assert({
+ given: 'hook is mounted with 5 seconds',
+ should: 'start with 5 seconds',
+ actual: result.current.secondsLeft,
+ expected: 5,
+ });
+
+ unmount();
+
+ act(() => {
+ vi.advanceTimersByTime(2000);
+ });
+
+ assert({
+ given: 'hook is unmounted and time passes',
+ should: 'maintain last value before unmount',
+ actual: result.current.secondsLeft,
+ expected: 5,
+ });
+ });
+
+ test('reset function', () => {
+ const { result } = renderHook(() => useCountdown(10));
+
+ act(() => {
+ vi.advanceTimersByTime(3000);
+ });
+
+ assert({
+ given: '3 seconds have passed from initial 10',
+ should: 'show 7 seconds remaining',
+ actual: result.current.secondsLeft,
+ expected: 7,
+ });
+
+ act(() => {
+ result.current.reset();
+ });
+
+ assert({
+ given: 'reset function is called',
+ should: 'return to initial seconds',
+ actual: result.current.secondsLeft,
+ expected: 10,
+ });
+ });
+
+ test('reset after countdown reaches zero', () => {
+ const { result } = renderHook(() => useCountdown(3));
+
+ act(() => {
+ vi.advanceTimersByTime(4000);
+ });
+
+ assert({
+ given: 'countdown has reached zero',
+ should: 'be at zero',
+ actual: result.current.secondsLeft,
+ expected: 0,
+ });
+
+ act(() => {
+ result.current.reset();
+ });
+
+ assert({
+ given: 'reset is called after reaching zero',
+ should: 'restart at initial value',
+ actual: result.current.secondsLeft,
+ expected: 3,
+ });
+
+ act(() => {
+ vi.advanceTimersByTime(1000);
+ });
+
+ assert({
+ given: 'one second passes after reset',
+ should: 'continue counting down',
+ actual: result.current.secondsLeft,
+ expected: 2,
+ });
+ });
+});
diff --git a/src/features/authenticate/use-countdown.ts b/src/features/authenticate/use-countdown.ts
new file mode 100644
index 0000000..1c46e24
--- /dev/null
+++ b/src/features/authenticate/use-countdown.ts
@@ -0,0 +1,68 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+
+/**
+ * A React hook that provides a countdown timer functionality.
+ *
+ * @param initialSeconds - The initial number of seconds for the countdown.
+ *
+ * @returns An object containing:
+ * - `secondsLeft`: The current number of seconds left in the countdown.
+ * - `reset`: A function to reset the countdown to the initial seconds.
+ */
+export function useCountdown(initialSeconds: number) {
+ const [secondsLeft, setSecondsLeft] = useState(initialSeconds);
+ const intervalIdReference = useRef(undefined);
+
+ // Function to start or restart the countdown.
+ const startCountdown = useCallback(() => {
+ // Clear any existing interval.
+ if (intervalIdReference.current) {
+ clearInterval(intervalIdReference.current);
+ intervalIdReference.current = undefined;
+ }
+
+ // Don't start interval if value is 0 or negative.
+ if (secondsLeft <= 0) return;
+
+ intervalIdReference.current = setInterval(() => {
+ setSecondsLeft(previous => {
+ if (previous <= 1) {
+ if (intervalIdReference.current) {
+ clearInterval(intervalIdReference.current);
+ intervalIdReference.current = undefined;
+ }
+ return 0;
+ }
+ return previous - 1;
+ });
+ }, 1000);
+ }, [secondsLeft]);
+
+ // Reset function to set the timer back to initialSeconds.
+ const reset = useCallback(() => {
+ setSecondsLeft(initialSeconds);
+ // We'll start the countdown in the useEffect that watches secondsLeft.
+ }, [initialSeconds]);
+
+ // Effect to handle initialSeconds changes.
+ useEffect(() => {
+ // Reset the countdown when initialSeconds changes.
+ setSecondsLeft(initialSeconds);
+ // We'll start the countdown in the useEffect that watches secondsLeft.
+ }, [initialSeconds]);
+
+ // Effect to start/restart countdown when secondsLeft changes.
+ useEffect(() => {
+ startCountdown();
+
+ // Cleanup interval on unmount or when secondsLeft changes.
+ return () => {
+ if (intervalIdReference.current) {
+ clearInterval(intervalIdReference.current);
+ intervalIdReference.current = undefined;
+ }
+ };
+ }, [secondsLeft, startCountdown]);
+
+ return { secondsLeft, reset };
+}
diff --git a/src/features/authenticate/user-authentication-constants.js b/src/features/authenticate/user-authentication-constants.js
new file mode 100644
index 0000000..d920f45
--- /dev/null
+++ b/src/features/authenticate/user-authentication-constants.js
@@ -0,0 +1,3 @@
+export const registerIntents = {
+ registerWithEmail: 'registerWithEmail',
+};
diff --git a/src/features/authenticate/user-authentication-reducer-old.js b/src/features/authenticate/user-authentication-reducer-old.js
new file mode 100644
index 0000000..a05513b
--- /dev/null
+++ b/src/features/authenticate/user-authentication-reducer-old.js
@@ -0,0 +1,44 @@
+import { pipe, prop } from 'ramda';
+
+export const sliceName = 'userAuthentication';
+
+const initialState = {
+ emailError: '',
+ nameError: '',
+};
+
+export const signUpClicked = ({ name = '', email = '' } = {}) => ({
+ type: 'SIGN_UP_CLICKED',
+ payload: { name, email },
+});
+
+export const signUpFailed = ({ emailError = '', nameError = '' } = {}) => ({
+ type: 'SIGN_UP_FAILED',
+ payload: { emailError, nameError },
+});
+
+export const reducer = (state = initialState, { type, payload } = {}) => {
+ switch (type) {
+ case signUpClicked().type: {
+ return { ...state, nameError: '', emailError: '' };
+ }
+ case signUpFailed().type: {
+ return { ...state, ...payload };
+ }
+ default: {
+ return state;
+ }
+ }
+};
+
+const selectUserAuthenticationSlice = prop(sliceName);
+
+export const selectEmailError = pipe(
+ selectUserAuthenticationSlice,
+ prop('emailError'),
+);
+
+export const selectNameError = pipe(
+ selectUserAuthenticationSlice,
+ prop('nameError'),
+);
diff --git a/src/features/authenticate/user-authentication-reducer-old.test.js.reference b/src/features/authenticate/user-authentication-reducer-old.test.js.reference
new file mode 100644
index 0000000..c1a1db9
--- /dev/null
+++ b/src/features/authenticate/user-authentication-reducer-old.test.js.reference
@@ -0,0 +1,124 @@
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import rootReducer from '../../redux/root-reducer.js';
+import {
+ selectEmailError,
+ selectNameError,
+ signUpClicked,
+ signUpFailed,
+} from './user-authentication-reducer-old.js';
+
+describe('selectEmailError()', () => {
+ test('initial state', () => {
+ const rootState = rootReducer(undefined, {});
+
+ assert({
+ given: 'the application starts',
+ should: 'initialize with no email error',
+ actual: selectEmailError(rootState),
+ expected: '',
+ });
+ });
+
+ test('sign up fails with email error', () => {
+ const state = rootReducer(
+ undefined,
+ signUpFailed({ emailError: 'Invalid email format' }),
+ );
+
+ assert({
+ given: 'sign up fails with only email error',
+ should: 'set email error message',
+ actual: selectEmailError(state),
+ expected: 'Invalid email format',
+ });
+ });
+
+ test('sign up clicked clears errors', () => {
+ const actions = [
+ signUpFailed({ emailError: 'Previous error' }),
+ signUpClicked({ name: 'John Doe', email: 'john@example.com' }),
+ ];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+
+ assert({
+ given: 'sign up is clicked after previous error',
+ should: 'clear email error',
+ actual: selectEmailError(state),
+ expected: '',
+ });
+ });
+
+ test('multiple sign up failures', () => {
+ const actions = [
+ signUpFailed({ emailError: 'First error' }),
+ signUpFailed({ emailError: 'Second error' }),
+ ];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+
+ assert({
+ given: 'multiple sign up failures occur',
+ should: 'update to latest email error',
+ actual: selectEmailError(state),
+ expected: 'Second error',
+ });
+ });
+});
+
+describe('selectNameError()', () => {
+ test('initial state', () => {
+ const rootState = rootReducer(undefined, {});
+
+ assert({
+ given: 'the application starts',
+ should: 'initialize with no name error',
+ actual: selectNameError(rootState),
+ expected: '',
+ });
+ });
+
+ test('sign up fails with name error', () => {
+ const state = rootReducer(
+ undefined,
+ signUpFailed({ nameError: 'Name cannot be empty' }),
+ );
+
+ assert({
+ given: 'sign up fails with only name error',
+ should: 'set name error message',
+ actual: selectNameError(state),
+ expected: 'Name cannot be empty',
+ });
+ });
+
+ test('sign up clicked clears errors', () => {
+ const actions = [
+ signUpFailed({ nameError: 'Previous error' }),
+ signUpClicked({ name: 'John Doe', email: 'john@example.com' }),
+ ];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+
+ assert({
+ given: 'sign up is clicked after previous error',
+ should: 'clear name error',
+ actual: selectNameError(state),
+ expected: '',
+ });
+ });
+
+ test('multiple sign up failures', () => {
+ const actions = [
+ signUpFailed({ nameError: 'First name error' }),
+ signUpFailed({ nameError: 'Second name error' }),
+ ];
+ const state = actions.reduce(rootReducer, rootReducer(undefined, {}));
+
+ assert({
+ given: 'multiple sign up failures occur',
+ should: 'update to latest name error',
+ actual: selectNameError(state),
+ expected: 'Second name error',
+ });
+ });
+});
diff --git a/src/features/authenticate/user-authentication-reducer.js b/src/features/authenticate/user-authentication-reducer.js
new file mode 100644
index 0000000..d8e0916
--- /dev/null
+++ b/src/features/authenticate/user-authentication-reducer.js
@@ -0,0 +1,29 @@
+import { pipe, prop } from 'ramda';
+
+export const sliceName = 'userAuthentication';
+
+const initialState = {
+ isAwaitingVerification: false,
+};
+
+export const showVerificationAwaiting = () => ({
+ type: 'SHOW_VERIFICATION_AWAITING',
+});
+
+export const reducer = (state = initialState, { type } = {}) => {
+ switch (type) {
+ case showVerificationAwaiting().type: {
+ return { ...state, isAwaitingVerification: true };
+ }
+ default: {
+ return state;
+ }
+ }
+};
+
+const selectUserAuthenticationSlice = prop(sliceName);
+
+export const selectIsAwaitingVerification = pipe(
+ selectUserAuthenticationSlice,
+ prop('isAwaitingVerification'),
+);
diff --git a/src/features/authenticate/user-authentication-reducer.test.js b/src/features/authenticate/user-authentication-reducer.test.js
new file mode 100644
index 0000000..056e205
--- /dev/null
+++ b/src/features/authenticate/user-authentication-reducer.test.js
@@ -0,0 +1,32 @@
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import rootReducer from '../../redux/root-reducer.js';
+import {
+ selectIsAwaitingVerification,
+ showVerificationAwaiting,
+} from './user-authentication-reducer.js';
+
+describe('selectIsAwaitingVerification()', () => {
+ test('initial state', () => {
+ const rootState = rootReducer(undefined, {});
+
+ assert({
+ given: 'the application starts',
+ should: 'initialize with verification not awaiting',
+ actual: selectIsAwaitingVerification(rootState),
+ expected: false,
+ });
+ });
+
+ test('show verification awaiting action', () => {
+ const state = rootReducer(undefined, showVerificationAwaiting());
+
+ assert({
+ given: 'show verification awaiting is dispatched',
+ should: 'set awaiting verification to true',
+ actual: selectIsAwaitingVerification(state),
+ expected: true,
+ });
+ });
+});
diff --git a/src/features/errors/not-found-component.jsx b/src/features/errors/not-found-component.jsx
new file mode 100644
index 0000000..3a828e6
--- /dev/null
+++ b/src/features/errors/not-found-component.jsx
@@ -0,0 +1,35 @@
+import Image from 'next/image';
+import Link from 'next/link';
+
+export default function NotFound() {
+ return (
+
+
+
+
+
Error
+
+ Page not found
+
+
+
+ Sorry, we couldn't find the page you're looking for.
+
+
+
+
+ ← Back to home
+
+
+
+
+ );
+}
diff --git a/src/features/errors/not-found-component.test.jsx b/src/features/errors/not-found-component.test.jsx
new file mode 100644
index 0000000..a5db604
--- /dev/null
+++ b/src/features/errors/not-found-component.test.jsx
@@ -0,0 +1,95 @@
+import render from 'riteway/render-component';
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import NotFound from './not-found-component';
+
+describe('NotFound component', () => {
+ test('basic elements', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render the error status text',
+ actual: $('p:contains("Error")').text(),
+ expected: 'Error',
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render the main error heading',
+ actual: $('h1').text(),
+ expected: 'Page not found',
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render the error description',
+ actual: $('p:contains("Sorry, we couldn\'t find the page")').text(),
+ expected: "Sorry, we couldn't find the page you're looking for.",
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render the back to home link',
+ actual: $('a[href="/"]').text(),
+ expected: '← Back to home',
+ });
+ });
+
+ test('image element', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render the not found illustration image',
+ actual: $('img[alt="Error illustration"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'use the correct not found image source',
+ actual: $('img[alt="Error illustration"]').attr('src'),
+ expected: '/images/not-found.png',
+ });
+ });
+
+ test('layout structure', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render within a main element',
+ actual: $('main').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'contain a content wrapper div within main',
+ actual: $('main div').length > 0,
+ expected: true,
+ });
+ });
+
+ test('navigation link', () => {
+ const $ = render( );
+
+ const backLink = $('a[href="/"]');
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'render a link back to home page',
+ actual: backLink.attr('href'),
+ expected: '/',
+ });
+
+ assert({
+ given: 'the NotFound component is rendered',
+ should: 'include arrow character in back link',
+ actual: backLink.text().includes('←'),
+ expected: true,
+ });
+ });
+});
diff --git a/src/features/errors/server-error-component.jsx b/src/features/errors/server-error-component.jsx
new file mode 100644
index 0000000..b2549b2
--- /dev/null
+++ b/src/features/errors/server-error-component.jsx
@@ -0,0 +1,35 @@
+import Image from 'next/image';
+import Link from 'next/link';
+
+export default function ServerError() {
+ return (
+
+
+
+
+
Error
+
+ Something went wrong
+
+
+
+ Sorry, we encountered an unexpected error. Please try again.
+
+
+
+
+ ← Back to home
+
+
+
+
+ );
+}
diff --git a/src/features/errors/server-error-component.test.jsx b/src/features/errors/server-error-component.test.jsx
new file mode 100644
index 0000000..01979a2
--- /dev/null
+++ b/src/features/errors/server-error-component.test.jsx
@@ -0,0 +1,97 @@
+import render from 'riteway/render-component';
+import { assert } from 'riteway/vitest';
+import { describe, test } from 'vitest';
+
+import ServerError from './server-error-component';
+
+describe('ServerError component', () => {
+ test('basic elements', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render the error status text',
+ actual: $('p:contains("Error")').text(),
+ expected: 'Error',
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render the main error heading',
+ actual: $('h1').text(),
+ expected: 'Something went wrong',
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render the error description',
+ actual: $(
+ 'p:contains("Sorry, we encountered an unexpected error")',
+ ).text(),
+ expected: 'Sorry, we encountered an unexpected error. Please try again.',
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render the back to home link',
+ actual: $('a[href="/"]').text(),
+ expected: '← Back to home',
+ });
+ });
+
+ test('image element', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render the error illustration image',
+ actual: $('img[alt="Error illustration"]').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'use the correct error image source',
+ actual: $('img[alt="Error illustration"]').attr('src'),
+ expected: '/images/error.png',
+ });
+ });
+
+ test('layout structure', () => {
+ const $ = render( );
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render within a main element',
+ actual: $('main').length,
+ expected: 1,
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'contain a content wrapper div within main',
+ actual: $('main div').length > 0,
+ expected: true,
+ });
+ });
+
+ test('navigation link', () => {
+ const $ = render( );
+
+ const backLink = $('a[href="/"]');
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'render a link back to home page',
+ actual: backLink.attr('href'),
+ expected: '/',
+ });
+
+ assert({
+ given: 'the ServerError component is rendered',
+ should: 'include arrow character in back link',
+ actual: backLink.text().includes('←'),
+ expected: true,
+ });
+ });
+});
diff --git a/src/features/landing/landing-page.jsx b/src/features/landing/landing-page.jsx
index fedc1ad..42cf327 100644
--- a/src/features/landing/landing-page.jsx
+++ b/src/features/landing/landing-page.jsx
@@ -1,115 +1,261 @@
-import { Geist, Geist_Mono } from 'next/font/google';
+import { GalleryVerticalEnd, Menu, X } from 'lucide-react';
import Image from 'next/image';
+import Link from 'next/link';
-const geistSans = Geist({
- variable: '--font-geist-sans',
- subsets: ['latin'],
-});
+import {
+ Sheet,
+ SheetBody,
+ SheetClose,
+ SheetContent,
+ SheetTrigger,
+} from '@/components/ui/base-sheet';
-const geistMono = Geist_Mono({
- variable: '--font-geist-mono',
- subsets: ['latin'],
-});
+const navigation = [
+ { name: 'Features', href: '#' },
+ { name: 'Courses', href: '#' },
+ { name: 'AI Mentor', href: '#' },
+ { name: 'About', href: '#' },
+];
export function LandingPage() {
return (
-
-
-
-
-
- Get started by editing{' '}
-
- src/pages/index.js
-
- .
-
-
- Save and see your changes instantly.
-
-
-
);
}
diff --git a/src/features/landing/landing-page.test.jsx b/src/features/landing/landing-page.test.jsx
index f396cb9..8730002 100644
--- a/src/features/landing/landing-page.test.jsx
+++ b/src/features/landing/landing-page.test.jsx
@@ -5,57 +5,97 @@ import { describe, test } from 'vitest';
import { LandingPage } from './landing-page.jsx';
describe('LandingPage component', () => {
- test('renders Next.js logo', () => {
+ test('renders Sparkly logo and brand name', () => {
const $ = render( );
- const nextLogo = $('img[alt="Next.js logo"]');
+ const sparklyText = $('span:contains("Sparkly")');
assert({
given: 'the LandingPage component is rendered',
- should: 'display the Next.js logo',
- actual: nextLogo.length,
+ should: 'display the Sparkly brand name',
+ actual: sparklyText.length > 0,
+ expected: true,
+ });
+ });
+
+ test('renders main headline', () => {
+ const $ = render( );
+
+ const headline = $('h1:contains("Ignite Learning, Inspire Creation")');
+
+ assert({
+ given: 'the LandingPage component is rendered',
+ should: 'display the main headline with the company motto',
+ actual: headline.length,
expected: 1,
});
});
- test('renders "Get started" text', () => {
+ test('renders AI mentorship description', () => {
const $ = render( );
- const getStartedText = $('li:contains("Get started by editing")');
+ const description = $('p:contains("AI-powered mentorship")');
assert({
given: 'the LandingPage component is rendered',
- should: 'display the get started instructions',
- actual: getStartedText.length,
+ should: 'describe the AI-powered learning experience',
+ actual: description.length,
expected: 1,
});
});
- test('renders deployment button', () => {
+ test('renders start learning button', () => {
const $ = render( );
- const deployButton = $('a:contains("Deploy now")');
+ const startLearningButton = $('a:contains("Start Learning Free")');
assert({
given: 'the LandingPage component is rendered',
- should: 'display a deploy now button that links to Vercel',
- actual: deployButton.attr('href').includes('vercel.com'),
- expected: true,
+ should: 'display a start learning button that links to registration',
+ actual: startLearningButton.attr('href'),
+ expected: '/register',
+ });
+ });
+
+ test('renders navigation menu items', () => {
+ const $ = render( );
+
+ const featuresLink = $('a:contains("Features")');
+ const coursesLink = $('a:contains("Courses")');
+ const aiMentorLink = $('a:contains("AI Mentor")');
+ const aboutLink = $('a:contains("About")');
+
+ assert({
+ given: 'the LandingPage component is rendered',
+ should: 'display all navigation menu items',
+ actual:
+ featuresLink.length +
+ coursesLink.length +
+ aiMentorLink.length +
+ aboutLink.length,
+ expected: 4, // 4 navigation items (mobile menu may not be visible in test)
});
});
- test('renders footer links', () => {
+ test('renders image gallery', () => {
const $ = render( );
- const learnLink = $('a:contains("Learn")');
- const examplesLink = $('a:contains("Examples")');
- const nextjsLink = $('a:contains("Go to nextjs.org →")');
+ const sparklyImage = $('img[alt="Sparkly app interface"]');
+ const bookImage = $('img[alt="Book cover"]');
+ const ericImage = $('img[alt="Eric profile"]');
+ const janImage = $('img[alt="Jan profile"]');
+ const sparkly2Image = $('img[alt="Sparkly app interface 2"]');
assert({
given: 'the LandingPage component is rendered',
- should: 'display all three footer navigation links',
- actual: learnLink.length + examplesLink.length + nextjsLink.length,
- expected: 3,
+ should: 'display all five images in the gallery',
+ actual:
+ sparklyImage.length +
+ bookImage.length +
+ ericImage.length +
+ janImage.length +
+ sparkly2Image.length,
+ expected: 5,
});
});
});
diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts
new file mode 100644
index 0000000..a90b968
--- /dev/null
+++ b/src/lib/prisma.ts
@@ -0,0 +1,12 @@
+import { PrismaClient } from '@prisma/client';
+
+// Prevent multiple instances of Prisma Client in development
+const globalForPrisma = globalThis as unknown as {
+ prisma: PrismaClient;
+};
+
+export const prisma = globalForPrisma.prisma ?? new PrismaClient();
+
+if (process.env.NODE_ENV !== 'production') {
+ globalForPrisma.prisma = prisma;
+}
diff --git a/src/lib/supabase/api.ts b/src/lib/supabase/api.ts
new file mode 100644
index 0000000..fc3bdcb
--- /dev/null
+++ b/src/lib/supabase/api.ts
@@ -0,0 +1,32 @@
+import { createServerClient, serializeCookieHeader } from '@supabase/ssr';
+import { type NextApiRequest, type NextApiResponse } from 'next';
+
+export default function createClient(
+ request: NextApiRequest,
+ response: NextApiResponse,
+) {
+ const supabase = createServerClient(
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
+ process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
+ {
+ cookies: {
+ getAll() {
+ return Object.keys(request.cookies).map(name => ({
+ name,
+ value: request.cookies[name] || '',
+ }));
+ },
+ setAll(cookiesToSet) {
+ response.setHeader(
+ 'Set-Cookie',
+ cookiesToSet.map(({ name, value, options }) =>
+ serializeCookieHeader(name, value, options),
+ ),
+ );
+ },
+ },
+ },
+ );
+
+ return supabase;
+}
diff --git a/src/lib/supabase/component.ts b/src/lib/supabase/component.ts
new file mode 100644
index 0000000..f80181e
--- /dev/null
+++ b/src/lib/supabase/component.ts
@@ -0,0 +1,10 @@
+import { createBrowserClient } from '@supabase/ssr';
+
+export function createClient() {
+ const supabase = createBrowserClient(
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
+ process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
+ );
+
+ return supabase;
+}
diff --git a/src/lib/supabase/server-side-props.ts b/src/lib/supabase/server-side-props.ts
new file mode 100644
index 0000000..b1e10bc
--- /dev/null
+++ b/src/lib/supabase/server-side-props.ts
@@ -0,0 +1,29 @@
+import { createServerClient, serializeCookieHeader } from '@supabase/ssr';
+import { type GetServerSidePropsContext } from 'next';
+
+export function createClient({ req, res }: GetServerSidePropsContext) {
+ const supabase = createServerClient(
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
+ process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
+ {
+ cookies: {
+ getAll() {
+ return Object.keys(req.cookies).map(name => ({
+ name,
+ value: req.cookies[name] || '',
+ }));
+ },
+ setAll(cookiesToSet) {
+ res.setHeader(
+ 'Set-Cookie',
+ cookiesToSet.map(({ name, value, options }) =>
+ serializeCookieHeader(name, value, options),
+ ),
+ );
+ },
+ },
+ },
+ );
+
+ return supabase;
+}
diff --git a/src/lib/supabase/static-props.ts b/src/lib/supabase/static-props.ts
new file mode 100644
index 0000000..98460e8
--- /dev/null
+++ b/src/lib/supabase/static-props.ts
@@ -0,0 +1,10 @@
+import { createClient as createClientPrimitive } from '@supabase/supabase-js';
+
+export function createClient() {
+ const supabase = createClientPrimitive(
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
+ process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
+ );
+
+ return supabase;
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..dd7e8d5
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,12 @@
+import { type ClassValue, clsx } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+/**
+ * Merges Tailwind class names, resolving any conflicts.
+ *
+ * @param inputs - An array of class names to merge.
+ * @returns A string of merged and optimized class names.
+ */
+export function cn(...inputs: ClassValue[]): string {
+ return twMerge(clsx(inputs));
+}
diff --git a/src/pages/404.js b/src/pages/404.js
new file mode 100644
index 0000000..500ea22
--- /dev/null
+++ b/src/pages/404.js
@@ -0,0 +1 @@
+export { default } from '../features/errors/not-found-component';
diff --git a/src/pages/_app.js b/src/pages/_app.js
index 98dd5f3..a88d8e9 100644
--- a/src/pages/_app.js
+++ b/src/pages/_app.js
@@ -1,5 +1,21 @@
import '@/styles/globals.css';
+import { Provider } from 'react-redux';
+
+import { ThemeProvider } from '@/components/theme-provider';
+import { store } from '@/redux/store';
+
export default function App({ Component, pageProps }) {
- return ;
+ return (
+
+
+
+
+
+ );
}
diff --git a/src/pages/_error.js b/src/pages/_error.js
new file mode 100644
index 0000000..5f083aa
--- /dev/null
+++ b/src/pages/_error.js
@@ -0,0 +1 @@
+export { default } from '../features/errors/server-error-component';
diff --git a/src/pages/api/auth/confirm.ts b/src/pages/api/auth/confirm.ts
new file mode 100644
index 0000000..3825a62
--- /dev/null
+++ b/src/pages/api/auth/confirm.ts
@@ -0,0 +1,40 @@
+import { type EmailOtpType } from '@supabase/supabase-js';
+import type { NextApiRequest, NextApiResponse } from 'next';
+
+import createClient from '@/lib/supabase/api';
+
+function stringOrFirstString(item: string | string[] | undefined) {
+ return Array.isArray(item) ? item[0] : item;
+}
+
+export default async function handler(
+ request: NextApiRequest,
+ response: NextApiResponse,
+) {
+ if (request.method !== 'GET') {
+ response.status(405).appendHeader('Allow', 'GET').end();
+ return;
+ }
+
+ const queryParams = request.query;
+ const token_hash = stringOrFirstString(queryParams.token_hash);
+ const type = stringOrFirstString(queryParams.type);
+
+ let next = '/error';
+
+ if (token_hash && type) {
+ const supabase = createClient(request, response);
+ const { error } = await supabase.auth.verifyOtp({
+ type: type as EmailOtpType,
+ token_hash,
+ });
+
+ if (error) {
+ console.error(error);
+ } else {
+ next = stringOrFirstString(queryParams.next) || '/';
+ }
+ }
+
+ response.redirect(next);
+}
diff --git a/src/pages/error.js b/src/pages/error.js
new file mode 100644
index 0000000..007e55b
--- /dev/null
+++ b/src/pages/error.js
@@ -0,0 +1 @@
+export { default } from './_error';
diff --git a/src/pages/home.js b/src/pages/home.js
new file mode 100644
index 0000000..4a57e37
--- /dev/null
+++ b/src/pages/home.js
@@ -0,0 +1,97 @@
+import { LogOut } from 'lucide-react';
+import { useRouter } from 'next/router';
+import { useState } from 'react';
+
+import { Button } from '@/components/ui/button';
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
+import { createClient } from '@/lib/supabase/component';
+import { createClient as createServerClient } from '@/lib/supabase/server-side-props';
+
+export default function HomePage({ user }) {
+ const router = useRouter();
+ const [isLoggingOut, setIsLoggingOut] = useState(false);
+ const supabase = createClient();
+
+ const handleLogout = async () => {
+ setIsLoggingOut(true);
+
+ try {
+ const { error } = await supabase.auth.signOut();
+
+ if (error) {
+ console.error('Error logging out:', error);
+ return;
+ }
+
+ // Redirect to landing page after successful logout
+ router.push('/');
+ } catch (error) {
+ console.error('Unexpected error during logout:', error);
+ } finally {
+ setIsLoggingOut(false);
+ }
+ };
+
+ return (
+
+
+
+ Welcome to Sparkly
+
+
+ Hello, {user.email || user.user_metadata?.name || 'user'}!
+ You're now part of the AI-powered learning revolution
+
+
+
+
+
+ Get ready to ignite your learning journey with personalized AI
+ mentorship. Dive into courses that adapt to your pace and help you
+ master new skills faster than ever before.
+
+
+
+
+
+
+ {isLoggingOut ? 'Logging out...' : 'Logout'}
+
+
+
+
+ );
+}
+
+export async function getServerSideProps(context) {
+ const supabase = createServerClient(context);
+
+ const { data, error } = await supabase.auth.getUser();
+
+ if (error || !data?.user) {
+ return {
+ redirect: {
+ destination: '/',
+ permanent: false,
+ },
+ };
+ }
+
+ return {
+ props: {
+ user: data.user,
+ },
+ };
+}
diff --git a/src/pages/index.js b/src/pages/index.js
index cc38ade..cb12474 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -1,5 +1,26 @@
-import { LandingPage } from '@/features/features/landing/landing-page';
+import { LandingPage } from '@/features/landing/landing-page';
+import { createClient } from '@/lib/supabase/server-side-props';
export default function LandingRoute() {
return ;
}
+
+export async function getServerSideProps(context) {
+ const supabase = createClient(context);
+
+ const { data, error } = await supabase.auth.getUser();
+
+ // If user is already authenticated, redirect to home
+ if (!error && data?.user) {
+ return {
+ redirect: {
+ destination: '/home',
+ permanent: false,
+ },
+ };
+ }
+
+ return {
+ props: {},
+ };
+}
diff --git a/src/pages/login.js b/src/pages/login.js
new file mode 100644
index 0000000..2714d47
--- /dev/null
+++ b/src/pages/login.js
@@ -0,0 +1,101 @@
+import { GalleryVerticalEnd } from 'lucide-react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { connect } from 'react-redux';
+
+import LoginForm from '@/features/authenticate/login-form/login-form-container';
+import { RegistrationVerificationAwaitingContainer } from '@/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-container';
+import { selectIsAwaitingVerification } from '@/features/authenticate/user-authentication-reducer';
+import { createClient } from '@/lib/supabase/server-side-props';
+
+function LoginPage({ isAwaitingVerification }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {isAwaitingVerification ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+ );
+}
+
+const mapStateToProps = state => ({
+ isAwaitingVerification: selectIsAwaitingVerification(state),
+});
+
+export default connect(mapStateToProps)(LoginPage);
+
+export async function getServerSideProps(context) {
+ const supabase = createClient(context);
+
+ const { data, error } = await supabase.auth.getUser();
+
+ // If user is already authenticated, redirect to home
+ if (!error && data?.user) {
+ return {
+ redirect: {
+ destination: '/home',
+ permanent: false,
+ },
+ };
+ }
+
+ return {
+ props: {},
+ };
+}
diff --git a/src/pages/register.js b/src/pages/register.js
new file mode 100644
index 0000000..0b6d683
--- /dev/null
+++ b/src/pages/register.js
@@ -0,0 +1,101 @@
+import { GalleryVerticalEnd } from 'lucide-react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { connect } from 'react-redux';
+
+import RegisterForm from '@/features/authenticate/register-form/register-form-container';
+import { RegistrationVerificationAwaitingContainer } from '@/features/authenticate/registration-verification-awaiting/registration-verification-awaiting-container';
+import { selectIsAwaitingVerification } from '@/features/authenticate/user-authentication-reducer';
+import { createClient } from '@/lib/supabase/server-side-props';
+
+function RegisterPage({ isAwaitingVerification }) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {isAwaitingVerification ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+
+
+
+ );
+}
+
+const mapStateToProps = state => ({
+ isAwaitingVerification: selectIsAwaitingVerification(state),
+});
+
+export default connect(mapStateToProps)(RegisterPage);
+
+export async function getServerSideProps(context) {
+ const supabase = createClient(context);
+
+ const { data, error } = await supabase.auth.getUser();
+
+ // If user is already authenticated, redirect to home
+ if (!error && data?.user) {
+ return {
+ redirect: {
+ destination: '/home',
+ permanent: false,
+ },
+ };
+ }
+
+ return {
+ props: {},
+ };
+}
diff --git a/src/redux/root-reducer.js b/src/redux/root-reducer.js
new file mode 100644
index 0000000..ebfef4e
--- /dev/null
+++ b/src/redux/root-reducer.js
@@ -0,0 +1,12 @@
+import { combineReducers } from '@reduxjs/toolkit';
+
+import {
+ reducer as userAuthenticationReducer,
+ sliceName as userAuthenticationSliceName,
+} from '@/features/authenticate/user-authentication-reducer';
+
+const rootReducer = combineReducers({
+ [userAuthenticationSliceName]: userAuthenticationReducer,
+});
+
+export default rootReducer;
diff --git a/src/redux/root-saga.js b/src/redux/root-saga.js
new file mode 100644
index 0000000..7fd9475
--- /dev/null
+++ b/src/redux/root-saga.js
@@ -0,0 +1,9 @@
+import { all, call } from 'redux-saga/effects';
+
+function* helloWorldSaga() {
+ yield console.log('hello world');
+}
+
+export default function* rootSaga() {
+ yield all([call(helloWorldSaga)]);
+}
diff --git a/src/redux/store.js b/src/redux/store.js
new file mode 100644
index 0000000..7d5e6c7
--- /dev/null
+++ b/src/redux/store.js
@@ -0,0 +1,17 @@
+import { configureStore } from '@reduxjs/toolkit';
+import createSagaMiddleware from 'redux-saga';
+
+import rootReducer from './root-reducer';
+import rootSaga from './root-saga';
+
+const sagaMiddleware = createSagaMiddleware();
+
+export const store = configureStore({
+ reducer: rootReducer,
+ middleware: getDefaultMiddleware => [
+ ...getDefaultMiddleware({ thunk: false }),
+ sagaMiddleware,
+ ],
+});
+
+sagaMiddleware.run(rootSaga);
diff --git a/src/styles/globals.css b/src/styles/globals.css
index a2dc41e..d979459 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -1,8 +1,41 @@
-@import "tailwindcss";
+@import 'tailwindcss';
+@import 'tw-animate-css';
+
+@custom-variant dark (&:is(.dark *));
:root {
- --background: #ffffff;
- --foreground: #171717;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.141 0.005 285.823);
+ --radius: 0.625rem;
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.141 0.005 285.823);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.141 0.005 285.823);
+ --primary: oklch(0.6 0.13 163);
+ --primary-foreground: oklch(0.982 0.018 155.826);
+ --secondary: oklch(0.967 0.001 286.375);
+ --secondary-foreground: oklch(0.21 0.006 285.885);
+ --muted: oklch(0.967 0.001 286.375);
+ --muted-foreground: oklch(0.552 0.016 285.938);
+ --accent: oklch(0.967 0.001 286.375);
+ --accent-foreground: oklch(0.21 0.006 285.885);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.92 0.004 286.32);
+ --input: oklch(0.92 0.004 286.32);
+ --ring: oklch(0.6 0.13 163);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
+ --sidebar-primary: oklch(0.6 0.13 163);
+ --sidebar-primary-foreground: oklch(0.982 0.018 155.826);
+ --sidebar-accent: oklch(0.967 0.001 286.375);
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
+ --sidebar-border: oklch(0.92 0.004 286.32);
+ --sidebar-ring: oklch(0.6 0.13 163);
}
@theme inline {
@@ -10,6 +43,39 @@
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
+ --color-sidebar-ring: var(--sidebar-ring);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar: var(--sidebar);
+ --color-chart-5: var(--chart-5);
+ --color-chart-4: var(--chart-4);
+ --color-chart-3: var(--chart-3);
+ --color-chart-2: var(--chart-2);
+ --color-chart-1: var(--chart-1);
+ --color-ring: var(--ring);
+ --color-input: var(--input);
+ --color-border: var(--border);
+ --color-destructive: var(--destructive);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-accent: var(--accent);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-muted: var(--muted);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-secondary: var(--secondary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-primary: var(--primary);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-popover: var(--popover);
+ --color-card-foreground: var(--card-foreground);
+ --color-card: var(--card);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
}
@media (prefers-color-scheme: dark) {
@@ -24,3 +90,47 @@ body {
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}
+
+.dark {
+ --background: oklch(0.141 0.005 285.823);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.21 0.006 285.885);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.21 0.006 285.885);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.7 0.15 162);
+ /* --primary-foreground: oklch(0.393 0.095 152.535); */
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.274 0.006 286.033);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.274 0.006 286.033);
+ --muted-foreground: oklch(0.705 0.015 286.067);
+ --accent: oklch(0.274 0.006 286.033);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.527 0.154 150.069);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.7 0.15 162);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.21 0.006 285.885);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.7 0.15 162);
+ --sidebar-primary-foreground: oklch(0.393 0.095 152.535);
+ --sidebar-accent: oklch(0.274 0.006 286.033);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.527 0.154 150.069);
+}
+
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/src/tests/setup-browser-test-environment.jsx b/src/tests/setup-browser-test-environment.jsx
index 0cda0e2..c71fce6 100644
--- a/src/tests/setup-browser-test-environment.jsx
+++ b/src/tests/setup-browser-test-environment.jsx
@@ -10,6 +10,8 @@ vi.mock('next/font/google', () => ({
}));
vi.mock('next/image', () => ({
- // eslint-disable-next-line @next/next/no-img-element
- default: props => ,
+ default: ({ priority: _priority, fill: _fill, ...props }) => (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ ),
}));
diff --git a/tsconfig.json b/tsconfig.json
index 4887295..33423ef 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,6 +23,13 @@
"@/*": ["./src/*"]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ "**/*.js",
+ "**/*.jsx",
+ ".next/types/**/*.ts"
+ ],
"exclude": ["node_modules"]
}
diff --git a/vitest.config.js b/vitest.config.js
index 0fe449c..0723991 100644
--- a/vitest.config.js
+++ b/vitest.config.js
@@ -9,7 +9,7 @@ const rootConfig = defineConfig({
const testConfig = defineConfig({
test: {
- workspace: [
+ projects: [
{
...rootConfig,
test: { include: ['src/**/*.test.{js,ts}'], name: 'unit-tests' },