mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-03-01 12:22:02 +00:00
Compare commits
7 Commits
v5.0.0-bet
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27d14d6b21 | ||
|
|
0354c9a122 | ||
|
|
4bed73d0fb | ||
|
|
d0e39c6149 | ||
|
|
89da4028bb | ||
|
|
c8462f1bdf | ||
|
|
cd168cd435 |
@@ -1,24 +1,25 @@
|
||||
# Contributing
|
||||
|
||||
Contributing is relatively easy, you just need to follow the steps below and you will be up and running with a development server in less than five minutes.
|
||||
Contributing to Tinyauth is straightforward. Follow the steps below to set up a development server.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Bun
|
||||
- Golang 1.24.0+
|
||||
- Golang v1.24.0 or later
|
||||
- Git
|
||||
- Docker
|
||||
- Make
|
||||
|
||||
## Cloning the repository
|
||||
## Cloning the Repository
|
||||
|
||||
You firstly need to clone the repository with:
|
||||
Start by cloning the repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/steveiliop56/tinyauth
|
||||
cd tinyauth
|
||||
```
|
||||
|
||||
## Initialize submodules
|
||||
## Initialize Submodules
|
||||
|
||||
The project uses Git submodules for some dependencies, so you need to initialize them with:
|
||||
|
||||
@@ -27,50 +28,58 @@ git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
## Install requirements
|
||||
## Apply patches
|
||||
|
||||
Although you will not need the requirements in your machine since the development will happen in Docker, I still recommend to install them because this way you will not have import errors. To install the Go requirements run:
|
||||
Some of the dependencies must be patched in order to work correctly with the project, you can apply the patches by running:
|
||||
|
||||
```sh
|
||||
go mod download
|
||||
git apply --directory paerser/ patches/nested_maps.diff
|
||||
```
|
||||
|
||||
You also need to download the frontend dependencies, this can be done like so:
|
||||
## Installing Requirements
|
||||
|
||||
While development occurs within Docker, installing the requirements locally is recommended to avoid import errors. Install the Go dependencies:
|
||||
|
||||
```sh
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
Frontend dependencies can be installed as follows:
|
||||
|
||||
```sh
|
||||
cd frontend/
|
||||
bun install
|
||||
```
|
||||
|
||||
## Apply patches
|
||||
## Create the `.env` file
|
||||
|
||||
Some of the dependencies need to be patched in order to work correctly with the project, you can apply the patches by running:
|
||||
Configuration requires an environment file. Copy the `.env.example` file to `.env` and adjust the environment variables as needed.
|
||||
|
||||
```sh
|
||||
git apply --directory paerser/ patches/nested_maps.diff
|
||||
```
|
||||
## Development Workflow
|
||||
|
||||
## Create your `.env` file
|
||||
|
||||
In order to configure the app you need to create an environment file, this can be done by copying the `.env.example` file to `.env` and modifying the environment variables to suit your needs.
|
||||
|
||||
## Developing
|
||||
|
||||
I have designed the development workflow to be entirely in Docker, this is because it will directly work with Traefik and you will not need to do any building in your host machine. The recommended development setup is to have a subdomain pointing to your machine like this:
|
||||
The development workflow is designed to run entirely within Docker, ensuring compatibility with Traefik and eliminating the need for local builds. A recommended setup involves pointing a subdomain to the local machine:
|
||||
|
||||
```
|
||||
*.dev.example.com -> 127.0.0.1
|
||||
dev.example.com -> 127.0.0.1
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> You can use [sslip.io](https://sslip.io) as a domain if you don't have one to develop with.
|
||||
> [!NOTE]
|
||||
> A domain from [sslip.io](https://sslip.io) can be used if a custom domain is
|
||||
unavailable. For example, set the Tinyauth domain to `tinyauth.127.0.0.1.sslip.io` and the whoami domain to `whoami.127.0.0.1.sslip.io`.
|
||||
|
||||
Then you can just make sure the domains are correct in the development Docker compose file and run:
|
||||
Ensure the domains are correctly configured in the development Docker Compose file, then start the development environment:
|
||||
|
||||
```sh
|
||||
docker compose -f docker-compose.dev.yml up --build
|
||||
make dev
|
||||
```
|
||||
|
||||
In case you need to build the binary locally, you can run:
|
||||
|
||||
```sh
|
||||
make binary
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> I recommend copying the example `docker-compose.dev.yml` into a `docker-compose.test.yml` file, so as you don't accidentally commit any sensitive information.
|
||||
> Copying the example `docker-compose.dev.yml` file to `docker-compose.test.yml`
|
||||
is recommended to prevent accidental commits of sensitive information. The make recipe will automatically use `docker-compose.test.yml` as well as `docker-compose.test.prod.yml` (for the `make prod` recipe) if it exists.
|
||||
|
||||
@@ -21,6 +21,9 @@ Tinyauth is a simple authentication middleware that adds a simple login screen o
|
||||
> [!WARNING]
|
||||
> Tinyauth is in active development and configuration may change often. Please make sure to carefully read the release notes before updating.
|
||||
|
||||
> [!NOTE]
|
||||
> This is the main development branch. For the latest stable release, see the [documentation](https://tinyauth.app) or the latest stable tag.
|
||||
|
||||
## Getting Started
|
||||
|
||||
You can easily get started with Tinyauth by following the guide in the [documentation](https://tinyauth.app/docs/getting-started). There is also an available [docker compose](./docker-compose.example.yml) file that has Traefik, Whoami and Tinyauth to demonstrate its capabilities.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 MiB After Width: | Height: | Size: 3.6 MiB |
@@ -22,6 +22,7 @@
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.575.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-hook-form": "^7.71.2",
|
||||
@@ -36,7 +37,7 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tanstack/eslint-plugin-query": "^5.91.4",
|
||||
"@types/node": "^25.3.1",
|
||||
"@types/node": "^25.3.2",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
@@ -196,14 +197,32 @@
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="],
|
||||
|
||||
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
|
||||
|
||||
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
|
||||
|
||||
"@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="],
|
||||
|
||||
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
|
||||
|
||||
"@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
|
||||
|
||||
"@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
|
||||
|
||||
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
|
||||
|
||||
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
|
||||
|
||||
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
|
||||
|
||||
"@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="],
|
||||
|
||||
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
|
||||
|
||||
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
|
||||
|
||||
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
|
||||
@@ -214,12 +233,26 @@
|
||||
|
||||
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
|
||||
|
||||
"@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="],
|
||||
|
||||
"@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="],
|
||||
|
||||
"@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
|
||||
|
||||
"@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
|
||||
|
||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
"@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.16", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA=="],
|
||||
|
||||
"@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="],
|
||||
|
||||
"@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="],
|
||||
|
||||
"@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="],
|
||||
|
||||
"@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="],
|
||||
|
||||
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
|
||||
@@ -228,14 +261,36 @@
|
||||
|
||||
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
|
||||
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
|
||||
|
||||
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
|
||||
|
||||
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
|
||||
|
||||
"@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
|
||||
|
||||
"@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
|
||||
|
||||
"@radix-ui/react-slider": ["@radix-ui/react-slider@1.3.6", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw=="],
|
||||
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
|
||||
|
||||
"@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
|
||||
|
||||
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
|
||||
|
||||
"@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="],
|
||||
|
||||
"@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="],
|
||||
|
||||
"@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="],
|
||||
|
||||
"@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="],
|
||||
|
||||
"@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
|
||||
|
||||
"@radix-ui/react-use-callback-ref": ["@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" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
|
||||
|
||||
"@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
|
||||
@@ -244,6 +299,8 @@
|
||||
|
||||
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
|
||||
|
||||
"@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.0", "", { "dependencies": { "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA=="],
|
||||
|
||||
"@radix-ui/react-use-layout-effect": ["@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" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
|
||||
|
||||
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
|
||||
@@ -360,7 +417,7 @@
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
|
||||
"@types/node": ["@types/node@25.3.1", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-hj9YIJimBCipHVfHKRMnvmHg+wfhKc0o4mTtXh9pKBjC8TLJzz0nzGmLi5UJsYAUgSvXFHgb0V2oY10DUFtImw=="],
|
||||
"@types/node": ["@types/node@25.3.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q=="],
|
||||
|
||||
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
||||
|
||||
@@ -778,6 +835,8 @@
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"radix-ui": ["radix-ui@1.4.3", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="],
|
||||
|
||||
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
|
||||
|
||||
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
|
||||
@@ -934,18 +993,30 @@
|
||||
|
||||
"@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-form/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
|
||||
|
||||
"@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
|
||||
|
||||
"@radix-ui/react-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||
|
||||
"@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||
|
||||
"@tailwindcss/node/lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
|
||||
@@ -1014,6 +1085,12 @@
|
||||
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="],
|
||||
|
||||
"radix-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "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" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.56.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", "@typescript-eslint/typescript-estree": "8.56.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA=="],
|
||||
|
||||
"@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"input-otp": "^1.4.2",
|
||||
"lucide-react": "^0.575.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-hook-form": "^7.71.2",
|
||||
@@ -42,7 +43,7 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tanstack/eslint-plugin-query": "^5.91.4",
|
||||
"@types/node": "^25.3.1",
|
||||
"@types/node": "^25.3.2",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
|
||||
@@ -10,17 +10,17 @@ import {
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "../ui/form";
|
||||
import { Button } from "../ui/button";
|
||||
import { loginSchema, LoginSchema } from "@/schemas/login-schema";
|
||||
import z from "zod";
|
||||
|
||||
interface Props {
|
||||
onSubmit: (data: LoginSchema) => void;
|
||||
loading?: boolean;
|
||||
formId?: string;
|
||||
}
|
||||
|
||||
export const LoginForm = (props: Props) => {
|
||||
const { onSubmit, loading } = props;
|
||||
const { onSubmit, loading, formId } = props;
|
||||
const { t } = useTranslation();
|
||||
|
||||
z.config({
|
||||
@@ -34,7 +34,7 @@ export const LoginForm = (props: Props) => {
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<form id={formId} onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
@@ -57,7 +57,7 @@ export const LoginForm = (props: Props) => {
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem className="mb-4 gap-0">
|
||||
<FormItem className="gap-0">
|
||||
<div className="relative mb-1">
|
||||
<FormLabel className="mb-2">{t("loginPassword")}</FormLabel>
|
||||
<FormControl>
|
||||
@@ -71,7 +71,7 @@ export const LoginForm = (props: Props) => {
|
||||
</FormControl>
|
||||
<a
|
||||
href="/forgot-password"
|
||||
className="text-muted-foreground text-sm absolute right-0 bottom-[2.565rem]" // 2.565 is *just* perfect
|
||||
className="text-muted-foreground hover:text-muted-foreground/80 text-sm absolute right-0 bottom-[2.565rem]" // 2.565 is *just* perfect
|
||||
>
|
||||
{t("forgotPasswordTitle")}
|
||||
</a>
|
||||
@@ -80,9 +80,6 @@ export const LoginForm = (props: Props) => {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button className="w-full" type="submit" loading={loading}>
|
||||
{t("loginSubmit")}
|
||||
</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
Card,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../ui/card";
|
||||
import { Button } from "../ui/button";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "react-router";
|
||||
|
||||
interface Props {
|
||||
@@ -21,36 +21,39 @@ export const DomainWarning = (props: Props) => {
|
||||
const { search } = useLocation();
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const redirectUri = searchParams.get("redirect_uri");
|
||||
|
||||
return (
|
||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||
<Card role="alert" aria-live="assertive">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("domainWarningTitle")}</CardTitle>
|
||||
<CardDescription>
|
||||
<Trans
|
||||
t={t}
|
||||
i18nKey="domainWarningSubtitle"
|
||||
values={{ appUrl, currentUrl }}
|
||||
components={{ code: <code /> }}
|
||||
shouldUnescape={true}
|
||||
/>
|
||||
</CardDescription>
|
||||
<CardTitle className="text-xl">{t("domainWarningTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||
<Button onClick={onClick} variant="warning">
|
||||
{t("ignoreTitle")}
|
||||
</Button>
|
||||
<CardContent className="flex flex-col gap-3 text-sm mb-1.25">
|
||||
<p className="text-muted-foreground">{t("domainWarningSubtitle")}</p>
|
||||
<pre>
|
||||
<span className="text-muted-foreground">
|
||||
{t("domainWarningExpected")}
|
||||
<span className="text-primary">{appUrl}</span>
|
||||
</span>
|
||||
</pre>
|
||||
<pre>
|
||||
<span className="text-muted-foreground">
|
||||
{t("domainWarningCurrent")}
|
||||
<span className="text-primary">{currentUrl}</span>
|
||||
</span>
|
||||
</pre>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-col items-stretch gap-3">
|
||||
<Button
|
||||
onClick={() =>
|
||||
window.location.assign(
|
||||
`${appUrl}/login?redirect_uri=${encodeURIComponent(redirectUri || "")}`,
|
||||
)
|
||||
window.location.assign(`${appUrl}/login?${searchParams.toString()}`)
|
||||
}
|
||||
variant="outline"
|
||||
>
|
||||
{t("goToCorrectDomainTitle")}
|
||||
</Button>
|
||||
<Button onClick={onClick} variant="warning">
|
||||
{t("ignoreTitle")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -14,18 +14,18 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative flex flex-col justify-center items-center min-h-svh"
|
||||
className="flex flex-col justify-center items-center min-h-svh px-4"
|
||||
style={{
|
||||
backgroundImage: `url(${backgroundImage})`,
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
<div className="absolute top-5 right-5 flex flex-row gap-2">
|
||||
<div className="absolute top-4 right-4 flex flex-row gap-2">
|
||||
<ThemeToggle />
|
||||
<LanguageSelector />
|
||||
</div>
|
||||
{children}
|
||||
<div className="max-w-sm md:min-w-sm min-w-xs">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
<div
|
||||
data-slot="card"
|
||||
className={cn(
|
||||
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||
"bg-card text-card-foreground flex flex-col gap-3 rounded-xl border py-6 shadow-sm",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@@ -20,7 +20,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
<div
|
||||
data-slot="card-header"
|
||||
className={cn(
|
||||
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@@ -75,7 +75,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
return (
|
||||
<div
|
||||
data-slot="card-footer"
|
||||
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
||||
className={cn("flex items-center px-6 [.border-t]:pt-6 mt-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
55
frontend/src/components/ui/tooltip.tsx
Normal file
55
frontend/src/components/ui/tooltip.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import * as React from "react"
|
||||
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function TooltipProvider({
|
||||
delayDuration = 0,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
||||
return (
|
||||
<TooltipPrimitive.Provider
|
||||
data-slot="tooltip-provider"
|
||||
delayDuration={delayDuration}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function Tooltip({
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
||||
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
||||
}
|
||||
|
||||
function TooltipTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
||||
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
||||
}
|
||||
|
||||
function TooltipContent({
|
||||
className,
|
||||
sideOffset = 0,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
||||
return (
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
data-slot="tooltip-content"
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
||||
@@ -160,7 +160,7 @@ code {
|
||||
}
|
||||
|
||||
pre {
|
||||
@apply bg-accent border border-border rounded-md p-2 whitespace-break-spaces;
|
||||
@apply bg-accent border border-border rounded-md p-2 whitespace-break-spaces break-all;
|
||||
}
|
||||
|
||||
.lead {
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "تجاهل",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Neplatný údaj",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Ungültige Eingabe",
|
||||
"domainWarningTitle": "Ungültige Domain",
|
||||
"domainWarningSubtitle": "Diese Instanz ist so konfiguriert, dass sie von <code>{{appUrl}}</code> aufgerufen werden kann, aber <code>{{currentUrl}}</code> wird verwendet. Wenn Sie fortfahren, können Probleme bei der Authentifizierung auftreten.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignorieren",
|
||||
"goToCorrectDomainTitle": "Zur korrekten Domain gehen",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"loginTitle": "Καλώς ήρθατε, συνδεθείτε με",
|
||||
"loginTitleSimple": "Καλώς ορίσατε, παρακαλώ συνδεθείτε",
|
||||
"loginTitleSimple": "Καλώς ήρθατε, παρακαλώ συνδεθείτε",
|
||||
"loginDivider": "Ή",
|
||||
"loginUsername": "Όνομα Χρήστη",
|
||||
"loginPassword": "Κωδικός",
|
||||
"loginPassword": "Κωδικόs πρόσβασης",
|
||||
"loginSubmit": "Είσοδος",
|
||||
"loginFailTitle": "Αποτυχία σύνδεσης",
|
||||
"loginFailSubtitle": "Παρακαλώ ελέγξτε το όνομα χρήστη και τον κωδικό πρόσβασης",
|
||||
@@ -19,7 +19,7 @@
|
||||
"loginOauthAutoRedirectButton": "Ανακατεύθυνση τώρα",
|
||||
"continueTitle": "Συνέχεια",
|
||||
"continueRedirectingTitle": "Ανακατεύθυνση...",
|
||||
"continueRedirectingSubtitle": "Θα πρέπει να μεταφερθείτε σύντομα στην εφαρμογή σας",
|
||||
"continueRedirectingSubtitle": "Θα μεταφερθείτε σύντομα στην εφαρμογή σας",
|
||||
"continueRedirectManually": "Χειροκίνητη ανακατεύθυνση",
|
||||
"continueInsecureRedirectTitle": "Μη ασφαλής ανακατεύθυνση",
|
||||
"continueInsecureRedirectSubtitle": "Προσπαθείτε να ανακατευθύνετε από <code>https</code> σε <code>http</code> το οποίο δεν είναι ασφαλές. Είστε σίγουροι ότι θέλετε να συνεχίσετε;",
|
||||
@@ -41,7 +41,7 @@
|
||||
"totpSuccessSubtitle": "Ανακατεύθυνση στην εφαρμογή σας",
|
||||
"totpTitle": "Εισάγετε τον κωδικό TOTP",
|
||||
"totpSubtitle": "Παρακαλώ εισάγετε τον κωδικό από την εφαρμογή ελέγχου ταυτότητας.",
|
||||
"unauthorizedTitle": "Μη εξουσιοδοτημένο",
|
||||
"unauthorizedTitle": "Σφάλμα μη εξουσιοδότησης",
|
||||
"unauthorizedResourceSubtitle": "Ο χρήστης με όνομα χρήστη <code>{{username}}</code> δεν έχει άδεια πρόσβασης στον πόρο <code>{{resource}}</code>.",
|
||||
"unauthorizedLoginSubtitle": "Ο χρήστης με όνομα χρήστη <code>{{username}}</code> δεν είναι εξουσιοδοτημένος να συνδεθεί.",
|
||||
"unauthorizedGroupsSubtitle": "Ο χρήστης με όνομα χρήστη <code>{{username}}</code> δεν είναι στις ομάδες που απαιτούνται από τον πόρο <code>{{resource}}</code>.",
|
||||
@@ -57,7 +57,9 @@
|
||||
"fieldRequired": "Αυτό το πεδίο είναι υποχρεωτικό",
|
||||
"invalidInput": "Μη έγκυρη καταχώρηση",
|
||||
"domainWarningTitle": "Μη έγκυρο domain",
|
||||
"domainWarningSubtitle": "Αυτή η εφαρμογή έχει ρυθμιστεί για πρόσβαση από <code>{{appUrl}}</code>, αλλά <code>{{currentUrl}}</code> χρησιμοποιείται. Αν συνεχίσετε, μπορεί να αντιμετωπίσετε προβλήματα με την ταυτοποίηση.",
|
||||
"domainWarningSubtitle": "Έχετε επισκεφθεί αυτή την εφαρμογή από λανθασμένο domain. Αν προχωρήσετε, ενδέχεται να αντιμετωπίσετε προβλήματα με τον έλεγχο ταυτότητας.",
|
||||
"domainWarningCurrent": "Τρέχον:",
|
||||
"domainWarningExpected": "Αναμένεται:",
|
||||
"ignoreTitle": "Παράβλεψη",
|
||||
"goToCorrectDomainTitle": "Μεταβείτε στο σωστό domain",
|
||||
"authorizeTitle": "Εξουσιοδότηση",
|
||||
@@ -72,7 +74,7 @@
|
||||
"authorizeErrorMissingParams": "Οι παρακάτω απαραίτητες πληροφορίες λείπουν από το αίτημά σας: {{missingParams}}",
|
||||
"openidScopeName": "Σύνδεση OpenID",
|
||||
"openidScopeDescription": "Επιτρέπει στην εφαρμογή την πρόσβαση στις πληροφορίες σύνδεσης OpenID.",
|
||||
"emailScopeName": "Διεύθυνση ηλεκτρονικού ταχυδρομείου",
|
||||
"emailScopeName": "Ηλεκτρονικό ταχυδρομείο",
|
||||
"emailScopeDescription": "Επιτρέπει στην εφαρμογή να έχει πρόσβαση στη διεύθυνση ηλεκτρονικού ταχυδρομείου σας.",
|
||||
"profileScopeName": "Προφίλ",
|
||||
"profileScopeDescription": "Επιτρέπει στην εφαρμογή να έχει πρόσβαση στις πληροφορίες του προφίλ σας.",
|
||||
|
||||
@@ -57,7 +57,9 @@
|
||||
"fieldRequired": "This field is required",
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningSubtitle": "You are accessing this instance from an incorrect domain. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -57,7 +57,9 @@
|
||||
"fieldRequired": "This field is required",
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningSubtitle": "You are accessing this instance from an incorrect domain. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Virheellinen syöte",
|
||||
"domainWarningTitle": "Virheellinen verkkotunnus",
|
||||
"domainWarningSubtitle": "Tämä instanssi on määritelty käyttämään osoitetta <code>{{appUrl}}</code>, mutta nykyinen osoite on <code>{{currentUrl}}</code>. Jos jatkat, saatat törmätä ongelmiin autentikoinnissa.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Jätä huomiotta",
|
||||
"goToCorrectDomainTitle": "Siirry oikeaan verkkotunnukseen",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Saisie non valide",
|
||||
"domainWarningTitle": "Domaine invalide",
|
||||
"domainWarningSubtitle": "Cette instance est configurée pour être accédée depuis <code>{{appUrl}}</code>, mais <code>{{currentUrl}}</code> est utilisé. Si vous continuez, vous pourriez rencontrer des problèmes d'authentification.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignorer",
|
||||
"goToCorrectDomainTitle": "Aller au bon domaine",
|
||||
"authorizeTitle": "Autoriser",
|
||||
@@ -71,7 +73,7 @@
|
||||
"authorizeErrorClientInfo": "Une erreur est survenue lors du chargement des informations du client. Veuillez réessayer plus tard.",
|
||||
"authorizeErrorMissingParams": "Les paramètres suivants sont manquants : {{missingParams}}",
|
||||
"openidScopeName": "Connexion OpenID",
|
||||
"openidScopeDescription": "Allows the app to access your OpenID Connect information.",
|
||||
"openidScopeDescription": "Autorise l'application à accéder à vos informations \"OpenID Connect\".",
|
||||
"emailScopeName": "Email",
|
||||
"emailScopeDescription": "Autorise l'application à accéder à votre adresse e-mail.",
|
||||
"profileScopeName": "Profil",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Input non valido",
|
||||
"domainWarningTitle": "Dominio non valido",
|
||||
"domainWarningSubtitle": "Questa istanza è configurata per essere accessibile da <code>{{appUrl}}</code>, ma la stai visitando da <code>{{currentUrl}}</code>. Se procedi, potresti incorrere in problemi di autenticazione.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignora",
|
||||
"goToCorrectDomainTitle": "Vai al dominio corretto",
|
||||
"authorizeTitle": "Autorizza",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Ongeldige invoer",
|
||||
"domainWarningTitle": "Ongeldig domein",
|
||||
"domainWarningSubtitle": "Deze instantie is geconfigureerd voor toegang tot <code>{{appUrl}}</code>, maar <code>{{currentUrl}}</code> wordt gebruikt. Als je doorgaat, kun je problemen ondervinden met authenticatie.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Negeren",
|
||||
"goToCorrectDomainTitle": "Ga naar het juiste domein",
|
||||
"authorizeTitle": "Autoriseren",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Nieprawidłowe dane wejściowe",
|
||||
"domainWarningTitle": "Nieprawidłowa domena",
|
||||
"domainWarningSubtitle": "Ta instancja jest skonfigurowana do uzyskania dostępu z <code>{{appUrl}}</code>, ale <code>{{currentUrl}}</code> jest w użyciu. Jeśli będziesz kontynuować, mogą wystąpić problemy z uwierzytelnianiem.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Zignoruj",
|
||||
"goToCorrectDomainTitle": "Przejdź do prawidłowej domeny",
|
||||
"authorizeTitle": "Autoryzuj",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Entrada Inválida",
|
||||
"domainWarningTitle": "Domínio inválido",
|
||||
"domainWarningSubtitle": "Esta instância está configurada para ser acessada de <code>{{appUrl}}</code>, mas <code>{{currentUrl}}</code> está sendo usado. Se você continuar, você pode encontrar problemas com a autenticação.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignorar",
|
||||
"goToCorrectDomainTitle": "Ir para o domínio correto",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Entrada inválida",
|
||||
"domainWarningTitle": "Domínio inválido",
|
||||
"domainWarningSubtitle": "Esta instância está configurada para ser acedida a partir de <code>{{appUrl}}</code>, mas está a ser usado <code>{{currentUrl}}</code>. Se continuares, poderás ter problemas de autenticação.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignorar",
|
||||
"goToCorrectDomainTitle": "Ir para o domínio correto",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Недопустимый ввод",
|
||||
"domainWarningTitle": "Неверный домен",
|
||||
"domainWarningSubtitle": "Этот экземпляр настроен на доступ к нему из <code>{{appUrl}}</code>, но <code>{{currentUrl}}</code> в настоящее время используется. Если вы продолжите, то могут возникнуть проблемы с авторизацией.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Игнорировать",
|
||||
"goToCorrectDomainTitle": "Перейти к правильному домену",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Неисправан унос",
|
||||
"domainWarningTitle": "Неисправан домен",
|
||||
"domainWarningSubtitle": "Ова инстанца је подешена да јој се приступа са <code>{{appUrl}}</code>, али се користи <code>{{currentUrl}}</code>. Ако наставите, можете искусити проблеме са аутентификацијом.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Игнориши",
|
||||
"goToCorrectDomainTitle": "Иди на исправан домен",
|
||||
"authorizeTitle": "Ауторизуј",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Geçersiz girdi",
|
||||
"domainWarningTitle": "Geçersiz alan adı",
|
||||
"domainWarningSubtitle": "Bu örnek, <code>{{appUrl}}</code> adresinden erişilecek şekilde yapılandırılmıştır, ancak <code>{{currentUrl}}</code> kullanılmaktadır. Devam ederseniz, kimlik doğrulama ile ilgili sorunlarla karşılaşabilirsiniz.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Yoksay",
|
||||
"goToCorrectDomainTitle": "Doğru alana gidin",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -51,31 +51,33 @@
|
||||
"forgotPasswordTitle": "Забули пароль?",
|
||||
"failedToFetchProvidersTitle": "Не вдалося завантажити провайдерів автентифікації. Будь ласка, перевірте вашу конфігурацію.",
|
||||
"errorTitle": "Виникла помилка",
|
||||
"errorSubtitleInfo": "The following error occurred while processing your request:",
|
||||
"errorSubtitleInfo": "Під час обробки запиту сталась помилка:",
|
||||
"errorSubtitle": "An error occurred while trying to perform this action. Please check the console for more information.",
|
||||
"forgotPasswordMessage": "Ви можете скинути пароль, змінивши змінну середовища \"USERS\".",
|
||||
"fieldRequired": "Це поле обов'язкове для заповнення",
|
||||
"invalidInput": "Невірне введення",
|
||||
"domainWarningTitle": "Невірний домен",
|
||||
"domainWarningSubtitle": "Даний ресурс налаштований для доступу з <code>{{appUrl}}</code>, але використовується <code>{{currentUrl}}</code>. Якщо ви продовжите, можуть виникнути проблеми з автентифікацією.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ігнорувати",
|
||||
"goToCorrectDomainTitle": "Перейти за коректним доменом",
|
||||
"authorizeTitle": "Authorize",
|
||||
"authorizeCardTitle": "Continue to {{app}}?",
|
||||
"authorizeSubtitle": "Would you like to continue to this app? Please carefully review the permissions requested by the app.",
|
||||
"authorizeSubtitleOAuth": "Would you like to continue to this app?",
|
||||
"authorizeLoadingTitle": "Loading...",
|
||||
"authorizeLoadingSubtitle": "Please wait while we load the client information.",
|
||||
"authorizeSuccessTitle": "Authorized",
|
||||
"authorizeSuccessSubtitle": "You will be redirected to the app in a few seconds.",
|
||||
"authorizeErrorClientInfo": "An error occurred while loading the client information. Please try again later.",
|
||||
"authorizeErrorMissingParams": "The following parameters are missing: {{missingParams}}",
|
||||
"authorizeTitle": "Авторизуватись",
|
||||
"authorizeCardTitle": "Перейти до {{app}}?",
|
||||
"authorizeSubtitle": "Чи хочете ви продовжити роботу з цим додатком? Будь ласка, уважно перегляньте дозволи, які вимагає додаток.",
|
||||
"authorizeSubtitleOAuth": "Бажаєте продовжити роботу з цим додатком?",
|
||||
"authorizeLoadingTitle": "Завантаження...",
|
||||
"authorizeLoadingSubtitle": "Будь ласка, зачекайте, поки ми завантажуємо клієнтську інформацію.",
|
||||
"authorizeSuccessTitle": "Авторизовано",
|
||||
"authorizeSuccessSubtitle": "Вас буде перенаправлено до програми за декілька секунд.",
|
||||
"authorizeErrorClientInfo": "Під час завантаження даних клієнта сталася помилка. Будь ласка, спробуйте ще раз пізніше.",
|
||||
"authorizeErrorMissingParams": "Відсутні наступні параметри: {{missingParams}}",
|
||||
"openidScopeName": "OpenID Connect",
|
||||
"openidScopeDescription": "Allows the app to access your OpenID Connect information.",
|
||||
"emailScopeName": "Email",
|
||||
"emailScopeDescription": "Allows the app to access your email address.",
|
||||
"profileScopeName": "Profile",
|
||||
"profileScopeDescription": "Allows the app to access your profile information.",
|
||||
"groupsScopeName": "Groups",
|
||||
"groupsScopeDescription": "Allows the app to access your group information."
|
||||
"openidScopeDescription": "Дозволяє програмі отримувати доступ до вашої інформації OpenID Connect.",
|
||||
"emailScopeName": "Електронна пошта",
|
||||
"emailScopeDescription": "Дозволяє програмі отримувати доступ до вашої адреси електронної пошти.",
|
||||
"profileScopeName": "Профіль",
|
||||
"profileScopeDescription": "Дозволяє програмі отримувати доступ до інформації вашого профілю.",
|
||||
"groupsScopeName": "Групи",
|
||||
"groupsScopeDescription": "Дозволяє програмі отримувати доступ до інформації про групу."
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "Invalid input",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "This instance is configured to be accessed from <code>{{appUrl}}</code>, but <code>{{currentUrl}}</code> is being used. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "无效的输入",
|
||||
"domainWarningTitle": "无效域名",
|
||||
"domainWarningSubtitle": "当前实例配置的访问地址为 <code>{{appUrl}}</code>,但您正在使用 <code>{{currentUrl}}</code>。若继续操作,可能会遇到身份验证问题。",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "忽略",
|
||||
"goToCorrectDomainTitle": "转到正确的域名",
|
||||
"authorizeTitle": "授权",
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
"invalidInput": "無效的輸入",
|
||||
"domainWarningTitle": "無效的網域",
|
||||
"domainWarningSubtitle": "此服務設定為透過 <code>{{appUrl}}</code> 存取,但目前使用的是 <code>{{currentUrl}}</code>。若繼續操作,可能會遇到驗證問題。",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "忽略",
|
||||
"goToCorrectDomainTitle": "前往正確域名",
|
||||
"authorizeTitle": "授權",
|
||||
|
||||
@@ -18,6 +18,7 @@ import { UserContextProvider } from "./context/user-context.tsx";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { ThemeProvider } from "./components/providers/theme-provider.tsx";
|
||||
import { AuthorizePage } from "./pages/authorize-page.tsx";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@@ -26,28 +27,33 @@ createRoot(document.getElementById("root")!).render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AppContextProvider>
|
||||
<UserContextProvider>
|
||||
<ThemeProvider defaultTheme="system" storageKey="tinyauth-theme">
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route element={<Layout />} errorElement={<ErrorPage />}>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/authorize" element={<AuthorizePage />} />
|
||||
<Route path="/logout" element={<LogoutPage />} />
|
||||
<Route path="/continue" element={<ContinuePage />} />
|
||||
<Route path="/totp" element={<TotpPage />} />
|
||||
<Route
|
||||
path="/forgot-password"
|
||||
element={<ForgotPasswordPage />}
|
||||
/>
|
||||
<Route path="/unauthorized" element={<UnauthorizedPage />} />
|
||||
<Route path="/error" element={<ErrorPage />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
<TooltipProvider>
|
||||
<ThemeProvider defaultTheme="system" storageKey="tinyauth-theme">
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route element={<Layout />} errorElement={<ErrorPage />}>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/authorize" element={<AuthorizePage />} />
|
||||
<Route path="/logout" element={<LogoutPage />} />
|
||||
<Route path="/continue" element={<ContinuePage />} />
|
||||
<Route path="/totp" element={<TotpPage />} />
|
||||
<Route
|
||||
path="/forgot-password"
|
||||
element={<ForgotPasswordPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/unauthorized"
|
||||
element={<UnauthorizedPage />}
|
||||
/>
|
||||
<Route path="/error" element={<ErrorPage />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
</TooltipProvider>
|
||||
</UserContextProvider>
|
||||
</AppContextProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
@@ -18,6 +18,11 @@ import { useOIDCParams } from "@/lib/hooks/oidc";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TFunction } from "i18next";
|
||||
import { Mail, Shield, User, Users } from "lucide-react";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
|
||||
type Scope = {
|
||||
id: string;
|
||||
@@ -27,7 +32,7 @@ type Scope = {
|
||||
};
|
||||
|
||||
const scopeMapIconProps = {
|
||||
className: "stroke-card stroke-2.5",
|
||||
className: "stroke-muted-foreground stroke-[1.75] h-4",
|
||||
};
|
||||
|
||||
const createScopeMap = (t: TFunction<"translation", undefined>): Scope[] => {
|
||||
@@ -124,13 +129,15 @@ export const AuthorizePage = () => {
|
||||
|
||||
if (getClientInfo.isLoading) {
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<Card className="gap-0">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
<CardTitle className="text-xl">
|
||||
{t("authorizeLoadingTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>{t("authorizeLoadingSubtitle")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardDescription>{t("authorizeLoadingSubtitle")}</CardDescription>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -145,41 +152,46 @@ export const AuthorizePage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm mx-4">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
{t("authorizeCardTitle", {
|
||||
app: getClientInfo.data?.name || "Unknown",
|
||||
})}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{scopes.includes("openid")
|
||||
? t("authorizeSubtitle")
|
||||
: t("authorizeSubtitleOAuth")}
|
||||
</CardDescription>
|
||||
<Card>
|
||||
<CardHeader className="mb-2">
|
||||
<div className="flex flex-col gap-3 items-center justify-center text-center">
|
||||
<div className="bg-accent-foreground text-muted text-xl font-bold font-sans rounded-lg px-4 py-3">
|
||||
{getClientInfo.data?.name.slice(0, 1)}
|
||||
</div>
|
||||
<CardTitle className="text-xl">
|
||||
{t("authorizeCardTitle", {
|
||||
app: getClientInfo.data?.name || "Unknown",
|
||||
})}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm max-w-sm">
|
||||
{scopes.includes("openid")
|
||||
? t("authorizeSubtitle")
|
||||
: t("authorizeSubtitleOAuth")}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</CardHeader>
|
||||
{scopes.includes("openid") && (
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{scopes.map((id) => {
|
||||
const scope = scopeMap.find((s) => s.id === id);
|
||||
if (!scope) return null;
|
||||
return (
|
||||
<div key={scope.id} className="flex flex-row items-center gap-3">
|
||||
<div className="p-2 flex flex-col items-center justify-center bg-card-foreground rounded-md">
|
||||
{scope.icon}
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<div className="text-md">{scope.name}</div>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{scope.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
)}
|
||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||
<CardContent className="mb-2">
|
||||
{scopes.includes("openid") && (
|
||||
<div className="flex flex-wrap gap-2 items-center justify-center">
|
||||
{scopes.map((id) => {
|
||||
const scope = scopeMap.find((s) => s.id === id);
|
||||
if (!scope) return null;
|
||||
return (
|
||||
<Tooltip key={scope.id}>
|
||||
<TooltipTrigger className="flex flex-row justify-center items-center gap-1 rounded-full bg-secondary font-light pl-2 pr-4 py-1 border-border border">
|
||||
<div>{scope.icon}</div>
|
||||
<div className="text-sm text-accent-foreground">
|
||||
{scope.name}
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{scope.description}</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-col items-stretch gap-3">
|
||||
<Button
|
||||
onClick={() => authorizeMutation.mutate()}
|
||||
loading={authorizeMutation.isPending}
|
||||
|
||||
@@ -93,9 +93,9 @@ export const ContinuePage = () => {
|
||||
|
||||
if (showUntrustedWarning) {
|
||||
return (
|
||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
<Card role="alert" aria-live="assertive">
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">
|
||||
{t("continueUntrustedRedirectTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -110,7 +110,7 @@ export const ContinuePage = () => {
|
||||
/>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||
<CardFooter className="flex flex-col items-stretch gap-3">
|
||||
<Button
|
||||
onClick={handleRedirect}
|
||||
loading={isLoading}
|
||||
@@ -132,9 +132,9 @@ export const ContinuePage = () => {
|
||||
|
||||
if (showInsecureWarning) {
|
||||
return (
|
||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
<Card role="alert" aria-live="assertive">
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">
|
||||
{t("continueInsecureRedirectTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -147,7 +147,7 @@ export const ContinuePage = () => {
|
||||
/>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||
<CardFooter className="flex flex-col items-stretch gap-3">
|
||||
<Button
|
||||
onClick={handleRedirect}
|
||||
loading={isLoading}
|
||||
@@ -168,16 +168,16 @@ export const ContinuePage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">
|
||||
{t("continueRedirectingTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>{t("continueRedirectingSubtitle")}</CardDescription>
|
||||
</CardHeader>
|
||||
{showRedirectButton && (
|
||||
<CardFooter className="flex flex-col items-stretch">
|
||||
<Button onClick={handleRedirect}>
|
||||
<CardFooter>
|
||||
<Button className="w-full" onClick={handleRedirect}>
|
||||
{t("continueRedirectManually")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
|
||||
@@ -14,10 +14,10 @@ export const ErrorPage = () => {
|
||||
const error = searchParams.get("error") ?? "";
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("errorTitle")}</CardTitle>
|
||||
<CardDescription className="flex flex-col gap-1.5">
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">{t("errorTitle")}</CardTitle>
|
||||
<CardDescription className="flex flex-col gap-3">
|
||||
{error ? (
|
||||
<>
|
||||
<p>{t("errorSubtitleInfo")}</p>
|
||||
|
||||
@@ -1,25 +1,47 @@
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAppContext } from "@/context/app-context";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Markdown from "react-markdown";
|
||||
import { useNavigate } from "react-router";
|
||||
|
||||
export const ForgotPasswordPage = () => {
|
||||
const { forgotPasswordMessage } = useAppContext();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("forgotPasswordTitle")}</CardTitle>
|
||||
<CardDescription>
|
||||
<Markdown>{forgotPasswordMessage !== "" ? forgotPasswordMessage : t('forgotPasswordMessage')}</Markdown>
|
||||
</CardDescription>
|
||||
<CardTitle className="text-xl">{t("forgotPasswordTitle")}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardDescription>
|
||||
<Markdown>
|
||||
{forgotPasswordMessage !== ""
|
||||
? forgotPasswordMessage
|
||||
: t("forgotPasswordMessage")}
|
||||
</Markdown>
|
||||
</CardDescription>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button
|
||||
className="w-full"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
navigate("/login");
|
||||
}}
|
||||
>
|
||||
{t("notFoundButton")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useOIDCParams } from "@/lib/hooks/oidc";
|
||||
import { LoginSchema } from "@/schemas/login-schema";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios, { AxiosError } from "axios";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useId, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
@@ -48,6 +48,8 @@ export const LoginPage = () => {
|
||||
const redirectTimer = useRef<number | null>(null);
|
||||
const redirectButtonTimer = useRef<number | null>(null);
|
||||
|
||||
const formId = useId();
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const {
|
||||
values: props,
|
||||
@@ -187,9 +189,9 @@ export const LoginPage = () => {
|
||||
|
||||
if (isOauthAutoRedirect) {
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">
|
||||
<CardTitle className="text-xl">
|
||||
{t("loginOauthAutoRedirectTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
@@ -218,9 +220,9 @@ export const LoginPage = () => {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-center text-3xl">{title}</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-center text-xl">{title}</CardTitle>
|
||||
{providers.length > 0 && (
|
||||
<CardDescription className="text-center">
|
||||
{oauthProviders.length !== 0
|
||||
@@ -231,7 +233,7 @@ export const LoginPage = () => {
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-4">
|
||||
{oauthProviders.length !== 0 && (
|
||||
<div className="flex flex-col gap-2 items-center justify-center">
|
||||
<div className="flex flex-col gap-2.5 items-center justify-center">
|
||||
{oauthProviders.map((provider) => (
|
||||
<OAuthButton
|
||||
key={provider.id}
|
||||
@@ -252,6 +254,7 @@ export const LoginPage = () => {
|
||||
<LoginForm
|
||||
onSubmit={(values) => loginMutate(values)}
|
||||
loading={loginIsPending || oauthIsPending}
|
||||
formId={formId}
|
||||
/>
|
||||
)}
|
||||
{providers.length == 0 && (
|
||||
@@ -260,6 +263,18 @@ export const LoginPage = () => {
|
||||
</p>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
{userAuthConfigured && (
|
||||
<Button
|
||||
className="w-full"
|
||||
type="submit"
|
||||
form={formId}
|
||||
loading={loginIsPending || oauthIsPending}
|
||||
>
|
||||
{t("loginSubmit")}
|
||||
</Button>
|
||||
)}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -52,9 +52,9 @@ export const LogoutPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("logoutTitle")}</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">{t("logoutTitle")}</CardTitle>
|
||||
<CardDescription>
|
||||
{provider !== "local" && provider !== "ldap" ? (
|
||||
<Trans
|
||||
@@ -84,8 +84,10 @@ export const LogoutPage = () => {
|
||||
)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch">
|
||||
<CardFooter>
|
||||
<Button
|
||||
className="w-full"
|
||||
variant="outline"
|
||||
loading={logoutMutation.isPending}
|
||||
onClick={() => logoutMutation.mutate()}
|
||||
>
|
||||
|
||||
@@ -21,13 +21,20 @@ export const NotFoundPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("notFoundTitle")}</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">{t("notFoundTitle")}</CardTitle>
|
||||
<CardDescription>{t("notFoundSubtitle")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch">
|
||||
<Button onClick={handleRedirect} loading={loading}>{t("notFoundButton")}</Button>
|
||||
<CardFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={handleRedirect}
|
||||
loading={loading}
|
||||
>
|
||||
{t("notFoundButton")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -72,9 +72,9 @@ export const TotpPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("totpTitle")}</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">{t("totpTitle")}</CardTitle>
|
||||
<CardDescription>{t("totpSubtitle")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col items-center">
|
||||
@@ -83,8 +83,13 @@ export const TotpPage = () => {
|
||||
onSubmit={(values) => totpMutation.mutate(values)}
|
||||
/>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-col items-stretch">
|
||||
<Button form={formId} type="submit" loading={totpMutation.isPending}>
|
||||
<CardFooter>
|
||||
<Button
|
||||
className="w-full"
|
||||
form={formId}
|
||||
type="submit"
|
||||
loading={totpMutation.isPending}
|
||||
>
|
||||
{t("continueTitle")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
|
||||
@@ -47,9 +47,9 @@ export const UnauthorizedPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="min-w-xs sm:min-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-3xl">{t("unauthorizedTitle")}</CardTitle>
|
||||
<Card>
|
||||
<CardHeader className="gap-1.5">
|
||||
<CardTitle className="text-xl">{t("unauthorizedTitle")}</CardTitle>
|
||||
<CardDescription>
|
||||
<Trans
|
||||
i18nKey={i18nKey}
|
||||
@@ -65,8 +65,13 @@ export const UnauthorizedPage = () => {
|
||||
/>
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter className="flex flex-col items-stretch">
|
||||
<Button onClick={handleRedirect} loading={loading}>
|
||||
<CardFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={handleRedirect}
|
||||
loading={loading}
|
||||
>
|
||||
{t("unauthorizedButton")}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
|
||||
Reference in New Issue
Block a user