diff --git a/.gitignore b/.gitignore
index 16330c8..ca63257 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@ node_modules
config.json
# generated multisrc .ts files
-src/plugins/*/*\[*\]*.ts
+plugins/*/*\[*\]*.ts
# ignore dist stuffs
.js
diff --git a/components.json b/components.json
new file mode 100644
index 0000000..2b0833f
--- /dev/null
+++ b/components.json
@@ -0,0 +1,22 @@
+{
+ "$schema": "https://ui.shadcn.com/schema.json",
+ "style": "new-york",
+ "rsc": false,
+ "tsx": true,
+ "tailwind": {
+ "config": "",
+ "css": "src/index.css",
+ "baseColor": "neutral",
+ "cssVariables": true,
+ "prefix": ""
+ },
+ "iconLibrary": "lucide",
+ "aliases": {
+ "components": "@/components",
+ "utils": "@/lib/utils",
+ "ui": "@/components/ui",
+ "lib": "@/lib",
+ "hooks": "@/hooks"
+ },
+ "registries": {}
+}
diff --git a/docs/docs.md b/docs/docs.md
index f74699f..e9469a0 100644
--- a/docs/docs.md
+++ b/docs/docs.md
@@ -11,7 +11,7 @@
Most of the Plugin/Novel type definitions accessed using the `Plugin` namespace imported via
```ts
-import { Plugin } from "@typings/plugin";
+import { Plugin } from '@/types/plugin';
```
### PluginBase
@@ -349,23 +349,24 @@ It is an object representing information how to store/access the novel
You can use the default `Cover not available` cover by importing
```ts
-import { defaultCover } from "@libs/defaultCover";
+import { defaultCover } from '@libs/defaultCover';
```
---
### SourceNovel
-| Field | Type | Required | Desciption |
-| ----- | ------ | -------- | ---------- |
-| url | string | yes | |
-| name | string | no | string |
-|cover|`string`|no||
-|genres|`string`|no||
-|summary|`string`|no||
-|author|`string`|no||
-|artist|`string`|no||
-|status|[NovelStatus] or `string`|no||
+| Field | Type | Required | Desciption |
+| ------- | ------------------------- | -------- | ---------- |
+| url | string | yes | |
+| name | string | no | string |
+| cover | `string` | no | |
+| genres | `string` | no | |
+| summary | `string` | no | |
+| author | `string` | no | |
+| artist | `string` | no | |
+| status | [NovelStatus] or `string` | no | |
+
chapters?: ChapterItem[];
---
@@ -379,7 +380,7 @@ import { defaultCover } from "@libs/defaultCover";
`Filters` and `FilterTypes` are not in the `Plugin` namespace and are from `@libs/filterInputs` file:
```ts
-import { FilterTypes, Filters } from "@libs/filterInputs";
+import { FilterTypes, Filters } from '@libs/filterInputs';
```
There are 2 main objects when using filters:
@@ -418,11 +419,11 @@ options.filters.order
filters = {
genre: {
type: FilterTypes.CheckboxGroup,
- label: "Genres",
+ label: 'Genres',
value: [],
options: [
- { label: "Isekai", value: "isekai" },
- { label: "Romance", value: "romans" },
+ { label: 'Isekai', value: 'isekai' },
+ { label: 'Romance', value: 'romans' },
],
},
} satisfies Filters;
@@ -445,12 +446,12 @@ Types of filters supported
```ts
options: [
{
- label: "default", // in-app label
- value: "", // in-code value
+ label: 'default', // in-app label
+ value: '', // in-code value
},
{
- label: "Value ABC",
- value: "abc",
+ label: 'Value ABC',
+ value: 'abc',
},
];
```
@@ -460,12 +461,12 @@ options: [
```ts
options: [
{
- label: "Value ABC", // in-app label
- value: "abc", // in-code value
+ label: 'Value ABC', // in-app label
+ value: 'abc', // in-code value
},
{
- label: "Value DEF",
- value: "def",
+ label: 'Value DEF',
+ value: 'def',
},
];
```
diff --git a/docs/plugin-template.ts b/docs/plugin-template.ts
index 81ee904..1d762d8 100644
--- a/docs/plugin-template.ts
+++ b/docs/plugin-template.ts
@@ -1,11 +1,11 @@
-import { fetchApi, fetchProto, fetchText } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchProto, fetchText } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
// import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
-// import { storage, localStorage, sessionStorage } from '@libs/storage';
+// import { storage, localStorage, sessionStorage } from '@/lib/storage';
// import { encode, decode } from 'urlencode';
// import dayjs from 'dayjs';
// import { Parser } from 'htmlparser2';
diff --git a/eslint.config.js b/eslint.config.js
index 1393852..0ecca52 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -129,10 +129,15 @@ export default tseslint.config(
...tseslint.configs.stylistic,
prettierConfig,
{
- ignores: ['.js', 'docs', 'proxy_server.js'],
+ ignores: [
+ '.js',
+ 'docs',
+ 'proxy_server.js',
+ 'plugins/*/*\\[*\\]*.ts', // Files with square brackets in their names
+ ],
},
{
- files: ['./src/plugins/*/*.ts', './scripts/multisrc/*/template.ts'],
+ files: ['./plugins/*/*.ts', './plugins/multisrc/*/template.ts'],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
@@ -150,7 +155,7 @@ export default tseslint.config(
},
{
files: ['**/*.{ts,tsx,mts,cts,js}'],
- ignores: ['./src/plugins/*/*.ts', './scripts/multisrc/*/template.ts'],
+ ignores: ['./plugins/*/*.ts', './plugins/multisrc/*/template.ts'],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'warn',
diff --git a/index.html b/index.html
index 52f3fcc..dc76d98 100644
--- a/index.html
+++ b/index.html
@@ -2,9 +2,10 @@
-
+
Plugin testing
+
diff --git a/package-lock.json b/package-lock.json
index 7a55d44..f4479c1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,23 @@
"version": "3.0.0",
"license": "MIT",
"dependencies": {
+ "@fontsource/geist-mono": "^5.2.7",
+ "@fontsource/geist-sans": "^5.2.5",
+ "@radix-ui/react-checkbox": "^1.3.3",
+ "@radix-ui/react-dialog": "^1.1.5",
+ "@radix-ui/react-label": "^2.1.7",
+ "@radix-ui/react-select": "^2.2.6",
+ "@radix-ui/react-slot": "^1.2.3",
+ "@radix-ui/react-switch": "^1.1.4",
+ "@radix-ui/react-tabs": "^1.1.13",
+ "@radix-ui/react-tooltip": "^1.2.8",
+ "@tailwindcss/vite": "^4.1.14",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.546.0",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.3.1",
+ "tailwindcss": "^4.1.14",
"terser": "^5.36.0",
"typescript": "^5.7.2"
},
@@ -23,6 +40,7 @@
"@types/eslint__js": "^8.42.3",
"@types/eslint-config-prettier": "^6.11.3",
"@types/http-proxy": "^1.17.16",
+ "@types/node": "^24.8.1",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react-window": "^1.8.8",
@@ -46,6 +64,7 @@
"react-window": "^1.8.10",
"sanitize-html": "^2.13.1",
"serve": "^14.2.4",
+ "tw-animate-css": "^1.4.0",
"typescript-eslint": "^7.14.1",
"urlencode": "^2.0.0",
"vite": "^6.3.2",
@@ -196,6 +215,16 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
+ "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
@@ -254,6 +283,7 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz",
"integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -297,6 +327,7 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz",
"integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -349,7 +380,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -366,7 +396,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -383,7 +412,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -400,7 +428,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -417,7 +444,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -434,7 +460,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -451,7 +476,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -468,7 +492,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -485,7 +508,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -502,7 +524,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -519,7 +540,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -536,7 +556,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -553,7 +572,6 @@
"cpu": [
"mips64el"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -570,7 +588,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -587,7 +604,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -604,7 +620,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -621,7 +636,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -638,7 +652,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -655,7 +668,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -672,7 +684,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -689,7 +700,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -706,7 +716,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -723,7 +732,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -740,7 +748,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -757,7 +764,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -850,6 +856,62 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
+ "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
+ "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.7.3",
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "node_modules/@floating-ui/react-dom": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
+ "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.7.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
+ "license": "MIT"
+ },
+ "node_modules/@fontsource/geist-mono": {
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/@fontsource/geist-mono/-/geist-mono-5.2.7.tgz",
+ "integrity": "sha512-xVPVFISJg/K0VVd+aQN0Y7X/sw9hUcJPyDWFJ5GpyU3bHELhoRsJkPSRSHXW32mOi0xZCUQDOaPj1sqIFJ1FGg==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
+ "node_modules/@fontsource/geist-sans": {
+ "version": "5.2.5",
+ "resolved": "https://registry.npmjs.org/@fontsource/geist-sans/-/geist-sans-5.2.5.tgz",
+ "integrity": "sha512-anllOHyJbElRs9fV15TeDRqAeb1IKm4bSknPl6ZMoyPTx1BBy7logudcUwpNjmQLkzn4Q0JGQLRCUKJYoyST6A==",
+ "license": "OFL-1.1",
+ "funding": {
+ "url": "https://github.com/sponsors/ayuhito"
+ }
+ },
"node_modules/@fontsource/roboto": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.1.0.tgz",
@@ -891,6 +953,18 @@
"deprecated": "Use @eslint/object-schema instead",
"dev": true
},
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -904,6 +978,16 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
@@ -930,9 +1014,9 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
@@ -985,6 +1069,7 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz",
"integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.26.0",
"@mui/core-downloads-tracker": "^6.1.9",
@@ -1283,6 +1368,739 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
"dev": true
},
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
+ "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+ "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-checkbox": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz",
+ "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
+ "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
+ "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
+ "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz",
+ "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
+ "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/react-dom": "^2.0.0",
+ "@radix-ui/react-arrow": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-rect": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1",
+ "@radix-ui/rect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
+ "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
+ "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-select": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
+ "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-focus-guards": "1.1.3",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-visually-hidden": "1.2.3",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-switch": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz",
+ "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-previous": "1.1.1",
+ "@radix-ui/react-use-size": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tabs": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
+ "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.11",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-tooltip": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
+ "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.11",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.8",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.5",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-visually-hidden": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-previous": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+ "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+ "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/rect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
+ "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+ "license": "MIT"
+ },
"node_modules/@reduxjs/toolkit": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.4.0.tgz",
@@ -1373,7 +2191,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1387,7 +2204,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1401,7 +2217,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1415,7 +2230,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1429,7 +2243,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1443,7 +2256,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1457,7 +2269,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1471,7 +2282,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1485,7 +2295,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1499,7 +2308,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1513,7 +2321,6 @@
"cpu": [
"loong64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1527,7 +2334,6 @@
"cpu": [
"ppc64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1541,7 +2347,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1555,7 +2360,6 @@
"cpu": [
"riscv64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1569,7 +2373,6 @@
"cpu": [
"s390x"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1583,7 +2386,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1597,7 +2399,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1611,7 +2412,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1625,7 +2425,6 @@
"cpu": [
"ia32"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1639,7 +2438,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1872,6 +2670,268 @@
"@swc/counter": "^0.1.3"
}
},
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
+ "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.4",
+ "enhanced-resolve": "^5.18.3",
+ "jiti": "^2.6.0",
+ "lightningcss": "1.30.1",
+ "magic-string": "^0.30.19",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.14"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz",
+ "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.4",
+ "tar": "^7.5.1"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-x64": "4.1.14",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.14",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.14",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.14",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.14"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz",
+ "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz",
+ "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz",
+ "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz",
+ "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz",
+ "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz",
+ "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz",
+ "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz",
+ "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz",
+ "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz",
+ "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.5.0",
+ "@emnapi/runtime": "^1.5.0",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.0.5",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz",
+ "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz",
+ "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz",
+ "integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.1.14",
+ "@tailwindcss/oxide": "4.1.14",
+ "tailwindcss": "4.1.14"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7"
+ }
+ },
"node_modules/@types/eslint": {
"version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -1901,7 +2961,6 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/@types/http-proxy": {
@@ -1920,12 +2979,13 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.11.19",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
- "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
- "dev": true,
+ "version": "24.8.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz",
+ "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==",
+ "devOptional": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~5.26.4"
+ "undici-types": "~7.14.0"
}
},
"node_modules/@types/parse-json": {
@@ -1938,13 +2998,14 @@
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/react": {
"version": "18.2.66",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.66.tgz",
"integrity": "sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==",
- "dev": true,
+ "devOptional": true,
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -1955,7 +3016,8 @@
"version": "18.2.22",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz",
"integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==",
- "dev": true,
+ "devOptional": true,
+ "peer": true,
"dependencies": {
"@types/react": "*"
}
@@ -1982,7 +3044,7 @@
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/use-sync-external-store": {
"version": "0.0.3",
@@ -2028,6 +3090,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
"dev": true,
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
@@ -2243,6 +3306,7 @@
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2414,6 +3478,18 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -2973,6 +4049,15 @@
"url": "https://github.com/sponsors/fb55"
}
},
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -2984,6 +4069,18 @@
"safe-buffer": "^5.0.1"
}
},
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
"node_modules/cli-boxes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
@@ -3168,7 +4265,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
- "dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -3458,7 +4555,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true
+ "devOptional": true
},
"node_modules/dayjs": {
"version": "1.11.13",
@@ -3556,6 +4653,21 @@
"minimalistic-assert": "^1.0.0"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
"node_modules/diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -3727,6 +4839,19 @@
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
}
},
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+ "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -3788,7 +4913,6 @@
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",
"integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==",
- "dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -3842,6 +4966,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -4299,7 +5424,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -4351,6 +5475,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/get-stream": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
@@ -4441,6 +5574,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
"node_modules/graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
@@ -4998,11 +6137,19 @@
"node": ">=10"
}
},
+ "node_modules/jiti": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/js-yaml": {
"version": "4.1.0",
@@ -5074,6 +6221,234 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -5223,7 +6598,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
@@ -5231,14 +6605,22 @@
"loose-envify": "cli.js"
}
},
+ "node_modules/lucide-react": {
+ "version": "0.546.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.546.0.tgz",
+ "integrity": "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/magic-string": {
- "version": "0.30.12",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
- "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==",
- "dev": true,
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"license": "MIT",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
+ "@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/md5.js": {
@@ -5403,6 +6785,27 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -5414,7 +6817,6 @@
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5868,7 +7270,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -5922,7 +7323,6 @@
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -6175,7 +7575,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "dev": true,
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -6187,7 +7587,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
- "dev": true,
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -6207,6 +7607,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
@@ -6225,6 +7626,75 @@
}
}
},
+ "node_modules/react-remove-scroll": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
+ "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -6290,7 +7760,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -6460,7 +7931,6 @@
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "1.0.7"
@@ -6583,16 +8053,16 @@
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "dev": true,
"dependencies": {
"loose-envify": "^1.1.0"
}
},
"node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -6819,6 +8289,16 @@
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
+ "node_modules/sonner": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
+ "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -6832,7 +8312,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -6986,6 +8465,51 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
+ "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
+ "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
+ "license": "ISC",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/terser": {
"version": "5.36.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
@@ -7031,7 +8555,6 @@
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.4.4",
@@ -7048,7 +8571,6 @@
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
- "dev": true,
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
@@ -7063,8 +8585,8 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
- "dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -7097,6 +8619,12 @@
"typescript": ">=4.2.0"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/tty-browserify": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
@@ -7104,6 +8632,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/tw-animate-css": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
+ "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Wombosvideo"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -7120,6 +8658,7 @@
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7165,10 +8704,11 @@
}
},
"node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
+ "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
+ "devOptional": true,
+ "license": "MIT"
},
"node_modules/update-check": {
"version": "1.5.4",
@@ -7220,6 +8760,49 @@
"iconv-lite": "~0.6.3"
}
},
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
@@ -7264,8 +8847,8 @@
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
- "dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -7356,7 +8939,6 @@
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
- "dev": true,
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
@@ -7371,8 +8953,8 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
- "dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -7527,11 +9109,20 @@
"node": ">=0.4"
}
},
+ "node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -7691,6 +9282,15 @@
"@babel/helper-validator-identifier": "^7.25.9"
}
},
+ "@emnapi/runtime": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
+ "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
+ "optional": true,
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ },
"@emotion/babel-plugin": {
"version": "11.13.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
@@ -7749,6 +9349,7 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz",
"integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==",
"dev": true,
+ "peer": true,
"requires": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -7784,6 +9385,7 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz",
"integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==",
"dev": true,
+ "peer": true,
"requires": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -7822,175 +9424,150 @@
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz",
"integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==",
- "dev": true,
"optional": true
},
"@esbuild/android-arm": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz",
"integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==",
- "dev": true,
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz",
"integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==",
- "dev": true,
"optional": true
},
"@esbuild/android-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz",
"integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==",
- "dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz",
"integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==",
- "dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz",
"integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==",
- "dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz",
"integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==",
- "dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz",
"integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==",
- "dev": true,
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz",
"integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==",
- "dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz",
"integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==",
- "dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz",
"integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==",
- "dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz",
"integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==",
- "dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz",
"integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==",
- "dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz",
"integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==",
- "dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz",
"integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==",
- "dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz",
"integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==",
- "dev": true,
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz",
"integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==",
- "dev": true,
"optional": true
},
"@esbuild/netbsd-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz",
"integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==",
- "dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz",
"integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==",
- "dev": true,
"optional": true
},
"@esbuild/openbsd-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz",
"integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==",
- "dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz",
"integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==",
- "dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz",
"integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==",
- "dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz",
"integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==",
- "dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz",
"integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==",
- "dev": true,
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz",
"integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==",
- "dev": true,
"optional": true
},
"@eslint-community/eslint-utils": {
@@ -8048,6 +9625,46 @@
"integrity": "sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==",
"dev": true
},
+ "@floating-ui/core": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
+ "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
+ "requires": {
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "@floating-ui/dom": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz",
+ "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
+ "requires": {
+ "@floating-ui/core": "^1.7.3",
+ "@floating-ui/utils": "^0.2.10"
+ }
+ },
+ "@floating-ui/react-dom": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz",
+ "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==",
+ "requires": {
+ "@floating-ui/dom": "^1.7.4"
+ }
+ },
+ "@floating-ui/utils": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
+ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
+ },
+ "@fontsource/geist-mono": {
+ "version": "5.2.7",
+ "resolved": "https://registry.npmjs.org/@fontsource/geist-mono/-/geist-mono-5.2.7.tgz",
+ "integrity": "sha512-xVPVFISJg/K0VVd+aQN0Y7X/sw9hUcJPyDWFJ5GpyU3bHELhoRsJkPSRSHXW32mOi0xZCUQDOaPj1sqIFJ1FGg=="
+ },
+ "@fontsource/geist-sans": {
+ "version": "5.2.5",
+ "resolved": "https://registry.npmjs.org/@fontsource/geist-sans/-/geist-sans-5.2.5.tgz",
+ "integrity": "sha512-anllOHyJbElRs9fV15TeDRqAeb1IKm4bSknPl6ZMoyPTx1BBy7logudcUwpNjmQLkzn4Q0JGQLRCUKJYoyST6A=="
+ },
"@fontsource/roboto": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.1.0.tgz",
@@ -8077,6 +9694,14 @@
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
+ "@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "requires": {
+ "minipass": "^7.0.4"
+ }
+ },
"@jridgewell/gen-mapping": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
@@ -8087,6 +9712,15 @@
"@jridgewell/trace-mapping": "^0.3.24"
}
},
+ "@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "requires": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
"@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
@@ -8107,9 +9741,9 @@
}
},
"@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.25",
@@ -8140,6 +9774,7 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz",
"integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==",
"dev": true,
+ "peer": true,
"requires": {
"@babel/runtime": "^7.26.0",
"@mui/core-downloads-tracker": "^6.1.9",
@@ -8313,6 +9948,348 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
"dev": true
},
+ "@radix-ui/number": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
+ "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="
+ },
+ "@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="
+ },
+ "@radix-ui/react-arrow": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+ "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+ "requires": {
+ "@radix-ui/react-primitive": "2.1.3"
+ }
+ },
+ "@radix-ui/react-checkbox": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz",
+ "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "requires": {}
+ },
+ "@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "requires": {}
+ },
+ "@radix-ui/react-dialog": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
+ "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "requires": {}
+ },
+ "@radix-ui/react-dismissable-layer": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
+ "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-focus-guards": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
+ "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+ "requires": {}
+ },
+ "@radix-ui/react-focus-scope": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+ "requires": {
+ "@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-id": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+ "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "requires": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-label": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz",
+ "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==",
+ "requires": {
+ "@radix-ui/react-primitive": "2.1.3"
+ }
+ },
+ "@radix-ui/react-popper": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
+ "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-portal": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
+ "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+ "requires": {
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-presence": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
+ "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+ "requires": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "requires": {
+ "@radix-ui/react-slot": "1.2.3"
+ }
+ },
+ "@radix-ui/react-roving-focus": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
+ "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-select": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz",
+ "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "requires": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ }
+ },
+ "@radix-ui/react-switch": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz",
+ "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-tabs": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz",
+ "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-tooltip": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
+ "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
+ "requires": {
+ "@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"
+ }
+ },
+ "@radix-ui/react-use-callback-ref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "requires": {}
+ },
+ "@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "requires": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "requires": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "requires": {
+ "@radix-ui/react-use-callback-ref": "1.1.1"
+ }
+ },
+ "@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "requires": {}
+ },
+ "@radix-ui/react-use-previous": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+ "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+ "requires": {}
+ },
+ "@radix-ui/react-use-rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+ "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+ "requires": {
+ "@radix-ui/rect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "requires": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ }
+ },
+ "@radix-ui/react-visually-hidden": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
+ "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
+ "requires": {
+ "@radix-ui/react-primitive": "2.1.3"
+ }
+ },
+ "@radix-ui/rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="
+ },
"@reduxjs/toolkit": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.4.0.tgz",
@@ -8359,140 +10336,120 @@
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
"integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
- "dev": true,
"optional": true
},
"@rollup/rollup-android-arm64": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
"integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
- "dev": true,
"optional": true
},
"@rollup/rollup-darwin-arm64": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
"integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
- "dev": true,
"optional": true
},
"@rollup/rollup-darwin-x64": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
"integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
- "dev": true,
"optional": true
},
"@rollup/rollup-freebsd-arm64": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
"integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
- "dev": true,
"optional": true
},
"@rollup/rollup-freebsd-x64": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
"integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
"integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-arm-musleabihf": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
"integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
"integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-arm64-musl": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
"integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
"integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
"integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
"integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-riscv64-musl": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
"integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-s390x-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
"integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-gnu": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
"integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
- "dev": true,
"optional": true
},
"@rollup/rollup-linux-x64-musl": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
"integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
- "dev": true,
"optional": true
},
"@rollup/rollup-win32-arm64-msvc": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
"integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
- "dev": true,
"optional": true
},
"@rollup/rollup-win32-ia32-msvc": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
"integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
- "dev": true,
"optional": true
},
"@rollup/rollup-win32-x64-msvc": {
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
"integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
- "dev": true,
"optional": true
},
"@swc/core": {
@@ -8600,6 +10557,131 @@
"@swc/counter": "^0.1.3"
}
},
+ "@tailwindcss/node": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
+ "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==",
+ "requires": {
+ "@jridgewell/remapping": "^2.3.4",
+ "enhanced-resolve": "^5.18.3",
+ "jiti": "^2.6.0",
+ "lightningcss": "1.30.1",
+ "magic-string": "^0.30.19",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.14"
+ }
+ },
+ "@tailwindcss/oxide": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz",
+ "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==",
+ "requires": {
+ "@tailwindcss/oxide-android-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.14",
+ "@tailwindcss/oxide-darwin-x64": "4.1.14",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.14",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.14",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.14",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.14",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.14",
+ "detect-libc": "^2.0.4",
+ "tar": "^7.5.1"
+ }
+ },
+ "@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz",
+ "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz",
+ "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz",
+ "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz",
+ "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz",
+ "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz",
+ "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz",
+ "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz",
+ "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz",
+ "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz",
+ "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==",
+ "optional": true,
+ "requires": {
+ "@emnapi/core": "^1.5.0",
+ "@emnapi/runtime": "^1.5.0",
+ "@emnapi/wasi-threads": "^1.1.0",
+ "@napi-rs/wasm-runtime": "^1.0.5",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz",
+ "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==",
+ "optional": true
+ },
+ "@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz",
+ "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==",
+ "optional": true
+ },
+ "@tailwindcss/vite": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz",
+ "integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==",
+ "requires": {
+ "@tailwindcss/node": "4.1.14",
+ "@tailwindcss/oxide": "4.1.14",
+ "tailwindcss": "4.1.14"
+ }
+ },
"@types/eslint": {
"version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -8628,8 +10710,7 @@
"@types/estree": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
- "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
- "dev": true
+ "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="
},
"@types/http-proxy": {
"version": "1.17.16",
@@ -8647,12 +10728,12 @@
"dev": true
},
"@types/node": {
- "version": "20.11.19",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz",
- "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==",
- "dev": true,
+ "version": "24.8.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.8.1.tgz",
+ "integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==",
+ "devOptional": true,
"requires": {
- "undici-types": "~5.26.4"
+ "undici-types": "~7.14.0"
}
},
"@types/parse-json": {
@@ -8665,13 +10746,14 @@
"version": "15.7.13",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
"integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==",
- "dev": true
+ "devOptional": true
},
"@types/react": {
"version": "18.2.66",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.66.tgz",
"integrity": "sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==",
- "dev": true,
+ "devOptional": true,
+ "peer": true,
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -8682,7 +10764,8 @@
"version": "18.2.22",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz",
"integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==",
- "dev": true,
+ "devOptional": true,
+ "peer": true,
"requires": {
"@types/react": "*"
}
@@ -8709,7 +10792,7 @@
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==",
- "dev": true
+ "devOptional": true
},
"@types/use-sync-external-store": {
"version": "0.0.3",
@@ -8739,6 +10822,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
"dev": true,
+ "peer": true,
"requires": {
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
@@ -8867,7 +10951,8 @@
"acorn": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
- "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw=="
+ "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
+ "peer": true
},
"acorn-jsx": {
"version": "5.3.2",
@@ -8976,6 +11061,14 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
+ "aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -9388,6 +11481,11 @@
"domutils": "^3.0.1"
}
},
+ "chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="
+ },
"cipher-base": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
@@ -9398,6 +11496,14 @@
"safe-buffer": "^5.0.1"
}
},
+ "class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "requires": {
+ "clsx": "^2.1.1"
+ }
+ },
"cli-boxes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz",
@@ -9510,8 +11616,7 @@
"clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
- "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
- "dev": true
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="
},
"color-convert": {
"version": "2.0.1",
@@ -9749,7 +11854,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true
+ "devOptional": true
},
"dayjs": {
"version": "1.11.13",
@@ -9816,6 +11921,16 @@
"minimalistic-assert": "^1.0.0"
}
},
+ "detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="
+ },
+ "detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
+ },
"diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -9951,6 +12066,15 @@
"whatwg-encoding": "^3.1.1"
}
},
+ "enhanced-resolve": {
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+ "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "requires": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ }
+ },
"entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -9991,7 +12115,6 @@
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",
"integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==",
- "dev": true,
"requires": {
"@esbuild/aix-ppc64": "0.25.3",
"@esbuild/android-arm": "0.25.3",
@@ -10031,6 +12154,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dev": true,
+ "peer": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -10365,7 +12489,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
"optional": true
},
"function-bind": {
@@ -10393,6 +12516,11 @@
"hasown": "^2.0.0"
}
},
+ "get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="
+ },
"get-stream": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
@@ -10451,6 +12579,11 @@
"get-intrinsic": "^1.1.3"
}
},
+ "graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
"graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
@@ -10816,11 +12949,15 @@
"integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==",
"dev": true
},
+ "jiti": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-yaml": {
"version": "4.1.0",
@@ -10880,6 +13017,84 @@
"type-check": "~0.4.0"
}
},
+ "lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "requires": {
+ "detect-libc": "^2.0.3",
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "optional": true
+ },
+ "lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "optional": true
+ },
+ "lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "optional": true
+ },
+ "lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "optional": true
+ },
+ "lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "optional": true
+ },
+ "lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "optional": true
+ },
+ "lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "optional": true
+ },
+ "lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "optional": true
+ },
+ "lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "optional": true
+ },
+ "lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "optional": true
+ },
"lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -10983,18 +13198,22 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
+ "lucide-react": {
+ "version": "0.546.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.546.0.tgz",
+ "integrity": "sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==",
+ "requires": {}
+ },
"magic-string": {
- "version": "0.30.12",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz",
- "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==",
- "dev": true,
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"requires": {
- "@jridgewell/sourcemap-codec": "^1.5.0"
+ "@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"md5.js": {
@@ -11116,6 +13335,19 @@
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true
},
+ "minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="
+ },
+ "minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "requires": {
+ "minipass": "^7.1.2"
+ }
+ },
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -11125,8 +13357,7 @@
"nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
- "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
- "dev": true
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="
},
"natural-compare": {
"version": "1.4.0",
@@ -11450,8 +13681,7 @@
"picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
- "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"picomatch": {
"version": "2.3.1",
@@ -11484,7 +13714,6 @@
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
- "dev": true,
"requires": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
@@ -11661,7 +13890,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "dev": true,
+ "peer": true,
"requires": {
"loose-envify": "^1.1.0"
}
@@ -11670,7 +13899,7 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
- "dev": true,
+ "peer": true,
"requires": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -11687,11 +13916,42 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz",
"integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==",
"dev": true,
+ "peer": true,
"requires": {
"@types/use-sync-external-store": "^0.0.3",
"use-sync-external-store": "^1.0.0"
}
},
+ "react-remove-scroll": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
+ "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
+ "requires": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ }
+ },
+ "react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "requires": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ }
+ },
+ "react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "requires": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ }
+ },
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -11736,7 +13996,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "dev": true
+ "dev": true,
+ "peer": true
},
"redux-thunk": {
"version": "3.1.0",
@@ -11861,7 +14122,6 @@
"version": "4.40.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
- "dev": true,
"requires": {
"@rollup/rollup-android-arm-eabi": "4.40.0",
"@rollup/rollup-android-arm64": "4.40.0",
@@ -11940,15 +14200,14 @@
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "dev": true,
"requires": {
"loose-envify": "^1.1.0"
}
},
"semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"dev": true
},
"serve": {
@@ -12107,6 +14366,12 @@
"is-fullwidth-code-point": "^4.0.0"
}
},
+ "sonner": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
+ "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
+ "requires": {}
+ },
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -12116,8 +14381,7 @@
"source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
- "dev": true
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
},
"source-map-support": {
"version": "0.5.21",
@@ -12225,6 +14489,33 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
+ "tailwind-merge": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g=="
+ },
+ "tailwindcss": {
+ "version": "4.1.14",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
+ "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA=="
+ },
+ "tapable": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
+ "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="
+ },
+ "tar": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz",
+ "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==",
+ "requires": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ }
+ },
"terser": {
"version": "5.36.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
@@ -12262,7 +14553,6 @@
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
"integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
- "dev": true,
"requires": {
"fdir": "^6.4.4",
"picomatch": "^4.0.2"
@@ -12272,14 +14562,13 @@
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
- "dev": true,
"requires": {}
},
"picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
- "dev": true
+ "peer": true
}
}
},
@@ -12299,12 +14588,23 @@
"dev": true,
"requires": {}
},
+ "tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="
+ },
"tty-browserify": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
"integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
"dev": true
},
+ "tw-animate-css": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz",
+ "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==",
+ "dev": true
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -12317,7 +14617,8 @@
"typescript": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
- "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg=="
+ "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
+ "peer": true
},
"typescript-eslint": {
"version": "7.14.1",
@@ -12337,10 +14638,10 @@
"dev": true
},
"undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
+ "version": "7.14.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
+ "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
+ "devOptional": true
},
"update-check": {
"version": "1.5.4",
@@ -12388,6 +14689,23 @@
"iconv-lite": "~0.6.3"
}
},
+ "use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
+ "use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "requires": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ }
+ },
"use-sync-external-store": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
@@ -12424,7 +14742,7 @@
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
- "dev": true,
+ "peer": true,
"requires": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -12439,14 +14757,13 @@
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
"integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
- "dev": true,
"requires": {}
},
"picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
- "dev": true
+ "peer": true
}
}
},
@@ -12560,11 +14877,16 @@
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true
},
+ "yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="
+ },
"yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
- "dev": true
+ "devOptional": true
},
"yocto-queue": {
"version": "0.1.0",
diff --git a/package.json b/package.json
index b10bdcb..aa63d14 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,8 @@
"clean:multisrc": "find . -type f -wholename \"*plugins*\\[*\\]*.[t,j]s\" -delete",
"clean:multisrc:windows": "powershell -Command \"Get-ChildItem -Recurse -Include \\\"*].ts\\\",\\\"*].js\\\" | Where-Object { $_.FullName -like \\\"*plugins*\\\" } | Remove-Item\"",
"dev": "vite",
- "dev:start": "node scripts/generate-plugin-index.js && vite",
- "build:multisrc": "node ./scripts/multisrc/generate-multisrc-plugins.js",
+ "dev:start": "node ./plugins/multisrc/generate-multisrc-plugins.js && node scripts/generate-plugin-index.js && vite",
+ "build:multisrc": "node ./plugins/multisrc/generate-multisrc-plugins.js",
"build:compile": "npx tsc --project tsconfig.production.json",
"build:manifest": "node ./scripts/build-plugin-manifest.js",
"build:manifest:dev": "node --env-file=.env ./scripts/build-plugin-manifest.js",
@@ -27,6 +27,23 @@
"author": "LNReader",
"license": "MIT",
"dependencies": {
+ "@fontsource/geist-mono": "^5.2.7",
+ "@fontsource/geist-sans": "^5.2.5",
+ "@radix-ui/react-checkbox": "^1.3.3",
+ "@radix-ui/react-dialog": "^1.1.5",
+ "@radix-ui/react-label": "^2.1.7",
+ "@radix-ui/react-select": "^2.2.6",
+ "@radix-ui/react-slot": "^1.2.3",
+ "@radix-ui/react-switch": "^1.1.4",
+ "@radix-ui/react-tabs": "^1.1.13",
+ "@radix-ui/react-tooltip": "^1.2.8",
+ "@tailwindcss/vite": "^4.1.14",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.546.0",
+ "sonner": "^2.0.7",
+ "tailwind-merge": "^3.3.1",
+ "tailwindcss": "^4.1.14",
"terser": "^5.36.0",
"typescript": "^5.7.2"
},
@@ -41,6 +58,7 @@
"@types/eslint__js": "^8.42.3",
"@types/eslint-config-prettier": "^6.11.3",
"@types/http-proxy": "^1.17.16",
+ "@types/node": "^24.8.1",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react-window": "^1.8.8",
@@ -64,6 +82,7 @@
"react-window": "^1.8.10",
"sanitize-html": "^2.13.1",
"serve": "^14.2.4",
+ "tw-animate-css": "^1.4.0",
"typescript-eslint": "^7.14.1",
"urlencode": "^2.0.0",
"vite": "^6.3.2",
diff --git a/src/plugins/arabic/.gitkeep b/plugins/arabic/.gitkeep
similarity index 100%
rename from src/plugins/arabic/.gitkeep
rename to plugins/arabic/.gitkeep
diff --git a/src/plugins/arabic/dilartube.ts b/plugins/arabic/dilartube.ts
similarity index 97%
rename from src/plugins/arabic/dilartube.ts
rename to plugins/arabic/dilartube.ts
index 4f230ca..b190fba 100644
--- a/src/plugins/arabic/dilartube.ts
+++ b/plugins/arabic/dilartube.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
@@ -80,8 +80,8 @@ class dilartube implements Plugin.PluginBase {
async parseNovel(novelUrl: string): Promise {
const chapterItems: Plugin.ChapterItem[] = [];
- let fullUrl = this.site + 'api/' + novelUrl;
- let chapterUrl = this.site + 'api/' + novelUrl + '/releases';
+ const fullUrl = this.site + 'api/' + novelUrl;
+ const chapterUrl = this.site + 'api/' + novelUrl + '/releases';
const manga = await fetchApi(fullUrl).then(r => r.json());
const chapters = await fetchApi(chapterUrl).then(r => r.json());
const mangaData = manga.mangaData;
@@ -199,21 +199,21 @@ class dilartube implements Plugin.PluginBase {
export default new dilartube();
-interface Category {
+type Category = {
id: number;
name: string;
icon: string | null;
manga_id: number;
-}
+};
-interface Type {
+type Type = {
id: number;
name: string;
reading_direction: string;
title: string;
-}
+};
-interface Manga {
+type Manga = {
id: number;
title: string;
summary: string;
@@ -249,8 +249,8 @@ interface Manga {
artists: any[];
categories: Category[];
type: Type;
-}
-interface Release {
+};
+type Release = {
id: number;
manga_id: number;
created_at: string;
@@ -272,11 +272,11 @@ interface Release {
team_paypal: string | null;
has_rev_link: boolean;
manga: Manga;
-}
-interface ApiResponse {
+};
+type ApiResponse = {
releases: Release[];
data: searchManga[];
-}
+};
type MangaCategory = {
id: number;
name: string;
@@ -384,7 +384,7 @@ type ChapterRelease = {
team_name: string;
has_rev_link: boolean;
};
-interface searchManga {
+type searchManga = {
filter: any;
id: number;
title: string;
@@ -421,4 +421,4 @@ interface searchManga {
artists: any[];
categories: Category[];
type: Type;
-}
+};
diff --git a/src/plugins/arabic/rewayatclub.ts b/plugins/arabic/rewayatclub.ts
similarity index 97%
rename from src/plugins/arabic/rewayatclub.ts
rename to plugins/arabic/rewayatclub.ts
index cfe68d1..3f4983b 100644
--- a/src/plugins/arabic/rewayatclub.ts
+++ b/plugins/arabic/rewayatclub.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
@@ -141,7 +141,7 @@ class RewayatClub implements Plugin.PagePlugin {
};
}
async parseChapter(chapterUrl: string): Promise {
- let link = this.site + 'api/chapters/' + chapterUrl.slice(6);
+ const link = this.site + 'api/chapters/' + chapterUrl.slice(6);
const result = await fetchApi(link).then(r => r.json());
let chapterText = result.content
.flat()
@@ -211,7 +211,7 @@ class RewayatClub implements Plugin.PagePlugin {
export default new RewayatClub();
-interface NovelEntry {
+type NovelEntry = {
arabic: string;
english: string;
about: string;
@@ -234,14 +234,14 @@ interface NovelEntry {
poster_url: string;
original: boolean;
};
-}
-interface NovelData {
+};
+type NovelData = {
count?: number;
next?: string;
previous?: string;
results: NovelEntry[];
-}
-interface ChapterEntry {
+};
+type ChapterEntry = {
number: number;
title: string;
date: string;
@@ -254,11 +254,11 @@ interface ChapterEntry {
id: number;
};
read: any[];
-}
+};
-interface ChapterData {
+type ChapterData = {
count: number;
next: string;
previous: string;
results: ChapterEntry[];
-}
+};
diff --git a/src/plugins/arabic/sunovels.ts b/plugins/arabic/sunovels.ts
similarity index 99%
rename from src/plugins/arabic/sunovels.ts
rename to plugins/arabic/sunovels.ts
index 89f7682..abdbc3e 100644
--- a/src/plugins/arabic/sunovels.ts
+++ b/plugins/arabic/sunovels.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
@@ -22,7 +22,7 @@ class Sunovels implements Plugin.PagePlugin {
imageUrlList.push(...imageUrlMatched);
}
});
- let counter: number = 0;
+ let counter = 0;
loadedCheerio('.list-item').each((idx, ele) => {
loadedCheerio(ele)
.find('a')
@@ -150,7 +150,7 @@ class Sunovels implements Plugin.PagePlugin {
const pageUrl = firstUrl + '?activeTab=chapters&page=' + pageCorrected;
const body = await fetchApi(pageUrl).then(r => r.text());
const loadedCheerio = parseHTML(body);
- let dataJson: {
+ const dataJson: {
pages_count: string;
chapters: ChapterEntry[];
} = { pages_count: '', chapters: [] };
@@ -298,9 +298,9 @@ class Sunovels implements Plugin.PagePlugin {
export default new Sunovels();
-interface ChapterEntry {
+type ChapterEntry = {
chapterName: string;
chapterUrl: string;
releaseTime: string;
chapterNumber: string | number;
-}
+};
diff --git a/src/plugins/chinese/69shu.ts b/plugins/chinese/69shu.ts
similarity index 99%
rename from src/plugins/chinese/69shu.ts
rename to plugins/chinese/69shu.ts
index bfe073c..f708c6d 100644
--- a/src/plugins/chinese/69shu.ts
+++ b/plugins/chinese/69shu.ts
@@ -1,7 +1,7 @@
import { load as parseHTML } from 'cheerio';
-import { fetchText } from '@libs/fetch';
+import { fetchText } from '@/lib/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
class Shu69 implements Plugin.PluginBase {
diff --git a/src/plugins/chinese/69xinshu.ts b/plugins/chinese/69xinshu.ts
similarity index 98%
rename from src/plugins/chinese/69xinshu.ts
rename to plugins/chinese/69xinshu.ts
index 5f8c800..a730c86 100644
--- a/src/plugins/chinese/69xinshu.ts
+++ b/plugins/chinese/69xinshu.ts
@@ -1,7 +1,7 @@
import { load as parseHTML } from 'cheerio';
-import { fetchText } from '@libs/fetch';
+import { fetchText } from '@/lib/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { encode } from 'urlencode';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/chinese/Quanben.ts b/plugins/chinese/Quanben.ts
similarity index 98%
rename from src/plugins/chinese/Quanben.ts
rename to plugins/chinese/Quanben.ts
index 062cccc..fced16d 100644
--- a/src/plugins/chinese/Quanben.ts
+++ b/plugins/chinese/Quanben.ts
@@ -1,6 +1,6 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { fetchApi, fetchFile } from '@libs/fetch';
+import { fetchApi, fetchFile } from '@/lib/fetch';
import { NovelStatus } from '@libs/novelStatus';
import { load as parseHTML } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
@@ -207,7 +207,7 @@ class QuanbenPlugin implements Plugin.PluginBase {
const chapterListHtml = await chapterListResult.text();
const $ = parseHTML(chapterListHtml);
- let chapters: Plugin.ChapterItem[] = [];
+ const chapters: Plugin.ChapterItem[] = [];
// Extract standard novel name from AMP path for chapter path storage
const standardNovelPathMatch = novelPath.match(/(\/n\/[^\/]+\/)/);
if (!standardNovelPathMatch || !standardNovelPathMatch[1]) {
@@ -385,7 +385,7 @@ class QuanbenPlugin implements Plugin.PluginBase {
const novelName = nameLink.text().trim();
const novelHref = nameLink.attr('href');
- let novelCover = img.attr('src') || img.attr('data-src');
+ const novelCover = img.attr('src') || img.attr('data-src');
if (novelHref && novelName) {
const absoluteUrl = makeAbsolute(novelHref, this.site);
diff --git a/src/plugins/chinese/ixdzs8.ts b/plugins/chinese/ixdzs8.ts
similarity index 97%
rename from src/plugins/chinese/ixdzs8.ts
rename to plugins/chinese/ixdzs8.ts
index 672a2f3..c2fa13f 100644
--- a/src/plugins/chinese/ixdzs8.ts
+++ b/plugins/chinese/ixdzs8.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
-import { fetchApi, fetchFile } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchFile } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
@@ -39,7 +39,7 @@ class ixdzs8Plugin implements Plugin.PluginBase {
};
async popularNovels(pageNo: number): Promise {
- let url = `${this.site}hot/?page=${pageNo}`;
+ const url = `${this.site}hot/?page=${pageNo}`;
const result = await fetchApi(url);
if (!result.ok) return [];
@@ -146,7 +146,7 @@ class ixdzs8Plugin implements Plugin.PluginBase {
const bookId = String(bid);
// POST request to fetch chapter list JSON
- let url = `${this.site}novel/clist/`;
+ const url = `${this.site}novel/clist/`;
const res = await fetch(url, {
method: 'POST',
headers: {
diff --git a/src/plugins/chinese/linovel.ts b/plugins/chinese/linovel.ts
similarity index 98%
rename from src/plugins/chinese/linovel.ts
rename to plugins/chinese/linovel.ts
index d95bfa9..6ec96d7 100644
--- a/src/plugins/chinese/linovel.ts
+++ b/plugins/chinese/linovel.ts
@@ -1,5 +1,5 @@
-import { fetchText } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchText } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as parseHTML } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/chinese/linovelib.ts b/plugins/chinese/linovelib.ts
similarity index 99%
rename from src/plugins/chinese/linovelib.ts
rename to plugins/chinese/linovelib.ts
index cc40a72..0f26aa9 100644
--- a/src/plugins/chinese/linovelib.ts
+++ b/plugins/chinese/linovelib.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
-import { fetchText } from '@libs/fetch';
+import { fetchText } from '@/lib/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
class Linovelib implements Plugin.PluginBase {
diff --git a/src/plugins/chinese/linovelib_tw.ts b/plugins/chinese/linovelib_tw.ts
similarity index 99%
rename from src/plugins/chinese/linovelib_tw.ts
rename to plugins/chinese/linovelib_tw.ts
index b40f2b7..5f8d0b0 100644
--- a/src/plugins/chinese/linovelib_tw.ts
+++ b/plugins/chinese/linovelib_tw.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
-import { fetchText } from '@libs/fetch';
+import { fetchText } from '@/lib/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
class Linovelib_tw implements Plugin.PluginBase {
diff --git a/src/plugins/chinese/novel543.ts b/plugins/chinese/novel543.ts
similarity index 99%
rename from src/plugins/chinese/novel543.ts
rename to plugins/chinese/novel543.ts
index 8bd5c86..cd4733a 100644
--- a/src/plugins/chinese/novel543.ts
+++ b/plugins/chinese/novel543.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
-import { fetchApi, fetchFile } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchFile } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/english/NovelOnline.ts b/plugins/english/NovelOnline.ts
similarity index 99%
rename from src/plugins/english/NovelOnline.ts
rename to plugins/english/NovelOnline.ts
index e557a39..e038fec 100644
--- a/src/plugins/english/NovelOnline.ts
+++ b/plugins/english/NovelOnline.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class NovelsOnline implements Plugin.PluginBase {
diff --git a/src/plugins/english/StorySeedling.ts b/plugins/english/StorySeedling.ts
similarity index 99%
rename from src/plugins/english/StorySeedling.ts
rename to plugins/english/StorySeedling.ts
index 94f9b7d..b1a904b 100644
--- a/src/plugins/english/StorySeedling.ts
+++ b/plugins/english/StorySeedling.ts
@@ -1,5 +1,5 @@
import { CheerioAPI, load } from 'cheerio';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/english/ao3.ts b/plugins/english/ao3.ts
similarity index 99%
rename from src/plugins/english/ao3.ts
rename to plugins/english/ao3.ts
index 8069d16..63266d0 100644
--- a/src/plugins/english/ao3.ts
+++ b/plugins/english/ao3.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
@@ -172,7 +172,7 @@ class ArchiveOfOurOwn implements Plugin.PluginBase {
const releaseTime = releaseTimeText
? new Date(releaseTimeText).toISOString()
: '';
- let dateCounter: number = 0;
+ let dateCounter = 0;
if (loadedCheerio('#chapter_index select').length > 0) {
loadedCheerio('#chapter_index select').each((i, selectEl) => {
loadedCheerio(selectEl)
diff --git a/src/plugins/english/bestlightnovel.ts b/plugins/english/bestlightnovel.ts
similarity index 99%
rename from src/plugins/english/bestlightnovel.ts
rename to plugins/english/bestlightnovel.ts
index 952303a..2eda9b9 100644
--- a/src/plugins/english/bestlightnovel.ts
+++ b/plugins/english/bestlightnovel.ts
@@ -1,5 +1,5 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/english/chrysanthemumgarden.ts b/plugins/english/chrysanthemumgarden.ts
similarity index 96%
rename from src/plugins/english/chrysanthemumgarden.ts
rename to plugins/english/chrysanthemumgarden.ts
index 75c017c..587c56f 100644
--- a/src/plugins/english/chrysanthemumgarden.ts
+++ b/plugins/english/chrysanthemumgarden.ts
@@ -1,5 +1,5 @@
-import { fetchApi, fetchProto, fetchText } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchProto, fetchText } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
@@ -144,13 +144,13 @@ class Chrysanthemumgarden implements Plugin.PluginBase {
export default new Chrysanthemumgarden();
-interface ChrysanthemumGardenNovel {
+type ChrysanthemumGardenNovel = {
name: string;
link: string;
-}
+};
-interface ChrysanthemumGardenNovelItem {
+type ChrysanthemumGardenNovelItem = {
name: string;
path: string;
cover: string;
-}
+};
diff --git a/src/plugins/english/divinedaolibrary.ts b/plugins/english/divinedaolibrary.ts
similarity index 99%
rename from src/plugins/english/divinedaolibrary.ts
rename to plugins/english/divinedaolibrary.ts
index d7867ef..1c6b251 100644
--- a/src/plugins/english/divinedaolibrary.ts
+++ b/plugins/english/divinedaolibrary.ts
@@ -1,7 +1,7 @@
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes, FilterValueWithType } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
//TODO: this looks similar to fictioneer source? maybe use multisrc someday
diff --git a/src/plugins/english/dreambigtl.ts b/plugins/english/dreambigtl.ts
similarity index 99%
rename from src/plugins/english/dreambigtl.ts
rename to plugins/english/dreambigtl.ts
index dd86fae..3f0661e 100644
--- a/src/plugins/english/dreambigtl.ts
+++ b/plugins/english/dreambigtl.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class DreamBigTL implements Plugin.PluginBase {
id = 'dreambigtl';
diff --git a/src/plugins/english/earlynovel.ts b/plugins/english/earlynovel.ts
similarity index 99%
rename from src/plugins/english/earlynovel.ts
rename to plugins/english/earlynovel.ts
index c3be3e0..4600067 100644
--- a/src/plugins/english/earlynovel.ts
+++ b/plugins/english/earlynovel.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class EarlyNovelPlugin implements Plugin.PagePlugin {
id = 'earlynovel';
diff --git a/src/plugins/english/faqwikius.ts b/plugins/english/faqwikius.ts
similarity index 99%
rename from src/plugins/english/faqwikius.ts
rename to plugins/english/faqwikius.ts
index 0764dd3..da88315 100644
--- a/src/plugins/english/faqwikius.ts
+++ b/plugins/english/faqwikius.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { fetchApi } from '@libs/fetch';
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/english/fenrirrealm.ts b/plugins/english/fenrirrealm.ts
similarity index 98%
rename from src/plugins/english/fenrirrealm.ts
rename to plugins/english/fenrirrealm.ts
index df68fe5..674fcdf 100644
--- a/src/plugins/english/fenrirrealm.ts
+++ b/plugins/english/fenrirrealm.ts
@@ -1,8 +1,8 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as loadCheerio } from 'cheerio';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { storage } from '@libs/storage';
+import { storage } from '@/lib/storage';
import { defaultCover } from '@libs/defaultCover';
class FenrirRealmPlugin implements Plugin.PluginBase {
diff --git a/src/plugins/english/fictionzone.ts b/plugins/english/fictionzone.ts
similarity index 96%
rename from src/plugins/english/fictionzone.ts
rename to plugins/english/fictionzone.ts
index 572df30..30290df 100644
--- a/src/plugins/english/fictionzone.ts
+++ b/plugins/english/fictionzone.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
@@ -17,7 +17,7 @@ class FictionZonePlugin implements Plugin.PagePlugin {
//flag indicates whether access to LocalStorage, SesesionStorage is required.
webStorageUtilized?: boolean;
- cachedNovelIds: Map = new Map();
+ cachedNovelIds = new Map();
async popularNovels(
pageNo: number,
@@ -79,10 +79,10 @@ class FictionZonePlugin implements Plugin.PagePlugin {
if (status === 'Ongoing') novel.status = NovelStatus.Ongoing;
novel.summary = loadedCheerio('#synopsis > div.content').text();
- let nuxtData = loadedCheerio('script#__NUXT_DATA__').html();
- let parsed = JSON.parse(nuxtData!);
+ const nuxtData = loadedCheerio('script#__NUXT_DATA__').html();
+ const parsed = JSON.parse(nuxtData!);
let last = null;
- for (let a of parsed) {
+ for (const a of parsed) {
if (typeof a === 'string' && a.startsWith('novel_covers/')) break;
last = a;
}
diff --git a/src/plugins/english/foxteller.ts b/plugins/english/foxteller.ts
similarity index 99%
rename from src/plugins/english/foxteller.ts
rename to plugins/english/foxteller.ts
index 907d5a7..81fa120 100644
--- a/src/plugins/english/foxteller.ts
+++ b/plugins/english/foxteller.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Parser } from 'htmlparser2';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/english/genesis.ts b/plugins/english/genesis.ts
similarity index 99%
rename from src/plugins/english/genesis.ts
rename to plugins/english/genesis.ts
index 0c7ae98..28dfc60 100644
--- a/src/plugins/english/genesis.ts
+++ b/plugins/english/genesis.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
/**
* Example for novel API:
diff --git a/src/plugins/english/inkitt.ts b/plugins/english/inkitt.ts
similarity index 96%
rename from src/plugins/english/inkitt.ts
rename to plugins/english/inkitt.ts
index 10d0265..e3019d5 100644
--- a/src/plugins/english/inkitt.ts
+++ b/plugins/english/inkitt.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
@@ -57,9 +57,9 @@ class InkittPlugin implements Plugin.PluginBase {
}
async parseNovel(novelPath: string): Promise {
- let req = await fetchApi(this.site + `/stories/${novelPath}`);
- let text = await req.text();
- let loadedCheerio = loadCheerio(text);
+ const req = await fetchApi(this.site + `/stories/${novelPath}`);
+ const text = await req.text();
+ const loadedCheerio = loadCheerio(text);
const novel: Plugin.SourceNovel = {
path: novelPath,
diff --git a/src/plugins/english/kdtnovels.ts b/plugins/english/kdtnovels.ts
similarity index 99%
rename from src/plugins/english/kdtnovels.ts
rename to plugins/english/kdtnovels.ts
index d4b328e..cbd340f 100644
--- a/src/plugins/english/kdtnovels.ts
+++ b/plugins/english/kdtnovels.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/english/lightnovelpub.ts b/plugins/english/lightnovelpub.ts
similarity index 99%
rename from src/plugins/english/lightnovelpub.ts
rename to plugins/english/lightnovelpub.ts
index e77fd3c..e2eacc9 100644
--- a/src/plugins/english/lightnovelpub.ts
+++ b/plugins/english/lightnovelpub.ts
@@ -1,6 +1,6 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs';
diff --git a/src/plugins/english/lightnoveltranslation.ts b/plugins/english/lightnoveltranslation.ts
similarity index 92%
rename from src/plugins/english/lightnoveltranslation.ts
rename to plugins/english/lightnoveltranslation.ts
index d9db992..b9debfa 100644
--- a/src/plugins/english/lightnoveltranslation.ts
+++ b/plugins/english/lightnoveltranslation.ts
@@ -1,11 +1,11 @@
-import { fetchApi, fetchProto, fetchText } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchProto, fetchText } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
// import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
-// import { storage, localStorage, sessionStorage } from '@libs/storage';
+// import { storage, localStorage, sessionStorage } from '@/lib/storage';
// import { encode, decode } from 'urlencode';
// import dayjs from 'dayjs';
import { Parser } from 'htmlparser2';
@@ -41,8 +41,8 @@ class LNTPlugin implements Plugin.PluginBase {
const baseUrl = this.site;
const novels: Plugin.NovelItem[] = [];
loadedCheerio('div.read_list-story-item').each((i, el) => {
- let tempNovel = {} as Plugin.NovelItem;
- let img = loadedCheerio(el)
+ const tempNovel = {} as Plugin.NovelItem;
+ const img = loadedCheerio(el)
.find('.item_thumb')
.find('img')
.first()
@@ -53,7 +53,7 @@ class LNTPlugin implements Plugin.PluginBase {
.first()
.attr('href');
path = path ? path.slice(baseUrl.length) : '';
- let title = loadedCheerio(el)
+ const title = loadedCheerio(el)
.find('.item_thumb')
.find('a')
.first()
@@ -67,7 +67,7 @@ class LNTPlugin implements Plugin.PluginBase {
return novels;
}
async parseNovel(novelPath: string): Promise {
- let url = this.site + novelPath;
+ const url = this.site + novelPath;
const body = await fetchApi(url);
const html = await body.text().then(r => r.replace(/>\s+<'));
@@ -161,7 +161,7 @@ class LNTPlugin implements Plugin.PluginBase {
const formData = new FormData();
formData.append('field-search', searchTerm);
- let results = await fetchApi(searchUrl, {
+ const results = await fetchApi(searchUrl, {
method: 'POST',
body: formData,
});
@@ -170,8 +170,8 @@ class LNTPlugin implements Plugin.PluginBase {
const loadedCheerio = loadCheerio(body);
const novels: Plugin.NovelItem[] = [];
loadedCheerio('div.read_list-story-item').each((i, el) => {
- let tempNovel = {} as Plugin.NovelItem;
- let img = loadedCheerio(el)
+ const tempNovel = {} as Plugin.NovelItem;
+ const img = loadedCheerio(el)
.find('.item_thumb')
.find('img')
.first()
@@ -182,7 +182,7 @@ class LNTPlugin implements Plugin.PluginBase {
.first()
.attr('href');
path = path ? path.slice(this.site.length) : '';
- let title = loadedCheerio(el)
+ const title = loadedCheerio(el)
.find('.item_thumb')
.find('a')
.first()
diff --git a/src/plugins/english/lnmtl.ts b/plugins/english/lnmtl.ts
similarity index 99%
rename from src/plugins/english/lnmtl.ts
rename to plugins/english/lnmtl.ts
index 752d7b3..7798947 100644
--- a/src/plugins/english/lnmtl.ts
+++ b/plugins/english/lnmtl.ts
@@ -1,7 +1,7 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class LnMTLPlugin implements Plugin.PagePlugin {
id = 'lnmtl';
diff --git a/src/plugins/english/mtlreader.ts b/plugins/english/mtlreader.ts
similarity index 98%
rename from src/plugins/english/mtlreader.ts
rename to plugins/english/mtlreader.ts
index 3b96939..e24a045 100644
--- a/src/plugins/english/mtlreader.ts
+++ b/plugins/english/mtlreader.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class MTLReader implements Plugin.PluginBase {
id = 'mtlreader';
diff --git a/src/plugins/english/mvlempyr.ts b/plugins/english/mvlempyr.ts
similarity index 99%
rename from src/plugins/english/mvlempyr.ts
rename to plugins/english/mvlempyr.ts
index 2d07ac2..eb8fe8b 100644
--- a/src/plugins/english/mvlempyr.ts
+++ b/plugins/english/mvlempyr.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { Parser } from 'htmlparser2';
@@ -87,7 +87,7 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
}
convertNovelId(e: bigint) {
- let t = 1999999997n;
+ const t = 1999999997n;
let u = 1n,
c = 7n % t,
d = e;
diff --git a/src/plugins/english/novelbuddy.ts b/plugins/english/novelbuddy.ts
similarity index 99%
rename from src/plugins/english/novelbuddy.ts
rename to plugins/english/novelbuddy.ts
index 4e3374a..9796714 100644
--- a/src/plugins/english/novelbuddy.ts
+++ b/plugins/english/novelbuddy.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class NovelBuddy implements Plugin.PluginBase {
diff --git a/src/plugins/english/novelfire.ts b/plugins/english/novelfire.ts
similarity index 99%
rename from src/plugins/english/novelfire.ts
rename to plugins/english/novelfire.ts
index 45c93ac..b297ff8 100644
--- a/src/plugins/english/novelfire.ts
+++ b/plugins/english/novelfire.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters, FilterTypes } from '@libs/filterInputs';
diff --git a/src/plugins/english/novelhall.ts b/plugins/english/novelhall.ts
similarity index 98%
rename from src/plugins/english/novelhall.ts
rename to plugins/english/novelhall.ts
index be286a3..155d767 100644
--- a/src/plugins/english/novelhall.ts
+++ b/plugins/english/novelhall.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
class NovelHall implements Plugin.PluginBase {
diff --git a/src/plugins/english/novelight.ts b/plugins/english/novelight.ts
similarity index 98%
rename from src/plugins/english/novelight.ts
rename to plugins/english/novelight.ts
index 3095ac9..707656b 100644
--- a/src/plugins/english/novelight.ts
+++ b/plugins/english/novelight.ts
@@ -1,9 +1,9 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import dayjs from 'dayjs';
-import { storage } from '@libs/storage';
+import { storage } from '@/lib/storage';
import { NovelStatus } from '@libs/novelStatus';
class Novelight implements Plugin.PagePlugin {
diff --git a/src/plugins/english/novelupdates.ts b/plugins/english/novelupdates.ts
similarity index 99%
rename from src/plugins/english/novelupdates.ts
rename to plugins/english/novelupdates.ts
index e59d803..60ba55a 100644
--- a/src/plugins/english/novelupdates.ts
+++ b/plugins/english/novelupdates.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class NovelUpdates implements Plugin.PluginBase {
id = 'novelupdates';
@@ -273,7 +273,7 @@ class NovelUpdates implements Plugin.PluginBase {
);
}
- let chapterTitle = pageData.props.chapter.title;
+ const chapterTitle = pageData.props.chapter.title;
let chapterContent = pageData.props.chapter.content;
// Clean up content (remove inline styles/scripts if needed)
diff --git a/src/plugins/english/pawread.ts b/plugins/english/pawread.ts
similarity index 99%
rename from src/plugins/english/pawread.ts
rename to plugins/english/pawread.ts
index 18d9bdd..cde78be 100644
--- a/src/plugins/english/pawread.ts
+++ b/plugins/english/pawread.ts
@@ -1,6 +1,6 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class PawRead implements Plugin.PluginBase {
diff --git a/src/plugins/english/rainofsnow.ts b/plugins/english/rainofsnow.ts
similarity index 99%
rename from src/plugins/english/rainofsnow.ts
rename to plugins/english/rainofsnow.ts
index 67bcff7..255c7a7 100644
--- a/src/plugins/english/rainofsnow.ts
+++ b/plugins/english/rainofsnow.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/english/readfrom.ts b/plugins/english/readfrom.ts
similarity index 90%
rename from src/plugins/english/readfrom.ts
rename to plugins/english/readfrom.ts
index 8a1ee99..e20d367 100644
--- a/src/plugins/english/readfrom.ts
+++ b/plugins/english/readfrom.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { CheerioAPI, load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
@@ -30,11 +30,11 @@ class ReadFromPlugin implements Plugin.PluginBase {
genres: string;
author: string;
})[] {
- let ret = loadedCheerio(
+ const ret = loadedCheerio(
(isSearch ? 'div.text' : '#dle-content') + ' > article.box',
)
.map((i, el) => {
- let summary = loadedCheerio(el).find(
+ const summary = loadedCheerio(el).find(
isSearch ? 'div.text5' : 'div.text3',
)[0];
loadedCheerio(summary).find('.coll-ellipsis').remove();
@@ -83,18 +83,18 @@ class ReadFromPlugin implements Plugin.PluginBase {
filters,
}: Plugin.PopularNovelsOptions,
) {
- let type = showLatestNovels ? 'last_added_books' : 'allbooks';
- let res = await fetchApi(
+ const type = showLatestNovels ? 'last_added_books' : 'allbooks';
+ const res = await fetchApi(
'https://readfrom.net/' + type + '/page/' + pageNo + '/',
);
- let text = await res.text();
+ const text = await res.text();
return this.parseNovels(loadCheerio(text));
}
async parseNovel(novelPath: string): Promise {
- let data = await fetchApi('https://readfrom.net/' + novelPath);
- let text = await data.text();
- let loadedCheerio = loadCheerio(text);
+ const data = await fetchApi('https://readfrom.net/' + novelPath);
+ const text = await data.text();
+ const loadedCheerio = loadCheerio(text);
const novel: Plugin.SourceNovel = {
path: novelPath,
@@ -142,12 +142,12 @@ class ReadFromPlugin implements Plugin.PluginBase {
novel.author = moreNovelInfo.author;
}
- let seriesElm = loadedCheerio('center > b:has(a)').filter((i, el) =>
+ const seriesElm = loadedCheerio('center > b:has(a)').filter((i, el) =>
loadedCheerio(el).find('a').attr('href')!.startsWith('/series.html'),
)[0];
if (seriesElm) {
- let seriesText = loadedCheerio(seriesElm).text().trim();
+ const seriesText = loadedCheerio(seriesElm).text().trim();
novel.summary = seriesText + '\n\n' + novel.summary;
}
@@ -198,11 +198,11 @@ class ReadFromPlugin implements Plugin.PluginBase {
async searchNovels(searchTerm: string, pageNo: number) {
if (pageNo !== 1) return [];
- let res = await fetchApi(
+ const res = await fetchApi(
'https://readfrom.net/build_in_search/?q=' +
encodeURIComponent(searchTerm),
);
- let text = await res.text();
+ const text = await res.text();
return this.parseNovels(loadCheerio(text), true);
}
diff --git a/src/plugins/english/readlitenovel.ts b/plugins/english/readlitenovel.ts
similarity index 99%
rename from src/plugins/english/readlitenovel.ts
rename to plugins/english/readlitenovel.ts
index ec3a2dc..546d03d 100644
--- a/src/plugins/english/readlitenovel.ts
+++ b/plugins/english/readlitenovel.ts
@@ -1,7 +1,7 @@
import { load as parseHTML } from 'cheerio';
import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs';
diff --git a/src/plugins/english/reaperscans.ts b/plugins/english/reaperscans.ts
similarity index 97%
rename from src/plugins/english/reaperscans.ts
rename to plugins/english/reaperscans.ts
index 158f3b4..c7a6ae2 100644
--- a/src/plugins/english/reaperscans.ts
+++ b/plugins/english/reaperscans.ts
@@ -1,10 +1,10 @@
import { fetchApi } from '@libs/fetch';
-import type { Plugin } from '@typings/plugin';
+import type { Plugin } from '@/types/plugin';
const API_BASE = 'https://api.reaperscans.com';
const MEDIA_BASE = 'https://media.reaperscans.com/file/4SRBHm/';
-interface ApiResponse {
+type ApiResponse = {
data: T;
meta: {
total: number;
@@ -12,13 +12,13 @@ interface ApiResponse {
current_page: number;
last_page: number;
};
-}
+};
-interface ReaperNovel {
+type ReaperNovel = {
title: string;
thumbnail: string;
series_slug: string;
-}
+};
class ReaperScans implements Plugin.PluginBase {
id = 'reaperscans.com';
diff --git a/src/plugins/english/relibrary.ts b/plugins/english/relibrary.ts
similarity index 99%
rename from src/plugins/english/relibrary.ts
rename to plugins/english/relibrary.ts
index 0f67558..0f0685c 100644
--- a/src/plugins/english/relibrary.ts
+++ b/plugins/english/relibrary.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
@@ -290,7 +290,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
.startsWith('status')
) {
loadedCheerio(el).find('strong').remove();
- let status = loadedCheerio(el).text().toLowerCase().trim();
+ const status = loadedCheerio(el).text().toLowerCase().trim();
if (status.includes('on-going')) {
novel.status = NovelStatus.Ongoing;
} else if (status.includes('completed')) {
diff --git a/src/plugins/english/royalroad.ts b/plugins/english/royalroad.ts
similarity index 99%
rename from src/plugins/english/royalroad.ts
rename to plugins/english/royalroad.ts
index a2fff0f..caeb806 100644
--- a/src/plugins/english/royalroad.ts
+++ b/plugins/english/royalroad.ts
@@ -1,6 +1,6 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
diff --git a/src/plugins/english/scribblehub.ts b/plugins/english/scribblehub.ts
similarity index 99%
rename from src/plugins/english/scribblehub.ts
rename to plugins/english/scribblehub.ts
index d62e3c7..6f9d6b5 100644
--- a/src/plugins/english/scribblehub.ts
+++ b/plugins/english/scribblehub.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import dayjs from 'dayjs';
class ScribbleHubPlugin implements Plugin.PluginBase {
diff --git a/src/plugins/english/vynovel.ts b/plugins/english/vynovel.ts
similarity index 99%
rename from src/plugins/english/vynovel.ts
rename to plugins/english/vynovel.ts
index 7ff8726..be88ca4 100644
--- a/src/plugins/english/vynovel.ts
+++ b/plugins/english/vynovel.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/english/webnovel.ts b/plugins/english/webnovel.ts
similarity index 97%
rename from src/plugins/english/webnovel.ts
rename to plugins/english/webnovel.ts
index aac4257..40efc78 100644
--- a/src/plugins/english/webnovel.ts
+++ b/plugins/english/webnovel.ts
@@ -1,8 +1,8 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
-import { storage } from '@libs/storage';
+import { Plugin } from '@/types/plugin';
+import { storage } from '@/lib/storage';
class Webnovel implements Plugin.PluginBase {
id = 'webnovel';
@@ -138,9 +138,9 @@ class Webnovel implements Plugin.PluginBase {
const chapters: Plugin.ChapterItem[] = [];
loadedCheerio('.volume-item').each((i_v_, ele_v) => {
- let originalVolumeName = loadedCheerio(ele_v).first().text().trim();
- let volumeNameMatch = originalVolumeName.match(/Volume\s(\d+)/);
- let volumeName = volumeNameMatch
+ const originalVolumeName = loadedCheerio(ele_v).first().text().trim();
+ const volumeNameMatch = originalVolumeName.match(/Volume\s(\d+)/);
+ const volumeName = volumeNameMatch
? `Volume ${volumeNameMatch[1]}`
: 'Unknown Volume';
diff --git a/src/plugins/english/wtrlab.ts b/plugins/english/wtrlab.ts
similarity index 99%
rename from src/plugins/english/wtrlab.ts
rename to plugins/english/wtrlab.ts
index eb6801a..84f4ce9 100644
--- a/src/plugins/english/wtrlab.ts
+++ b/plugins/english/wtrlab.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { fetchApi } from '@libs/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { load as parseHTML } from 'cheerio';
diff --git a/src/plugins/english/wuxiaworld.ts b/plugins/english/wuxiaworld.ts
similarity index 99%
rename from src/plugins/english/wuxiaworld.ts
rename to plugins/english/wuxiaworld.ts
index 8d9af80..88840f6 100644
--- a/src/plugins/english/wuxiaworld.ts
+++ b/plugins/english/wuxiaworld.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
-import { fetchApi, fetchProto } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchApi, fetchProto } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/french/chireads.ts b/plugins/french/chireads.ts
similarity index 99%
rename from src/plugins/french/chireads.ts
rename to plugins/french/chireads.ts
index 57c3e65..1d08fea 100644
--- a/src/plugins/french/chireads.ts
+++ b/plugins/french/chireads.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/french/harkeneliwood.ts b/plugins/french/harkeneliwood.ts
similarity index 99%
rename from src/plugins/french/harkeneliwood.ts
rename to plugins/french/harkeneliwood.ts
index 280178b..6631e3a 100644
--- a/src/plugins/french/harkeneliwood.ts
+++ b/plugins/french/harkeneliwood.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
import dayjs from 'dayjs';
diff --git a/src/plugins/french/kisswood.ts b/plugins/french/kisswood.ts
similarity index 99%
rename from src/plugins/french/kisswood.ts
rename to plugins/french/kisswood.ts
index 27f6837..7d18c2a 100644
--- a/src/plugins/french/kisswood.ts
+++ b/plugins/french/kisswood.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/french/noveldeglace.ts b/plugins/french/noveldeglace.ts
similarity index 99%
rename from src/plugins/french/noveldeglace.ts
rename to plugins/french/noveldeglace.ts
index 7d5ead6..05806e9 100644
--- a/src/plugins/french/noveldeglace.ts
+++ b/plugins/french/noveldeglace.ts
@@ -1,6 +1,6 @@
import { load, CheerioAPI } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/french/novhell.ts b/plugins/french/novhell.ts
similarity index 99%
rename from src/plugins/french/novhell.ts
rename to plugins/french/novhell.ts
index 3f77eaf..2253c74 100644
--- a/src/plugins/french/novhell.ts
+++ b/plugins/french/novhell.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/french/phenixscans.ts b/plugins/french/phenixscans.ts
similarity index 99%
rename from src/plugins/french/phenixscans.ts
rename to plugins/french/phenixscans.ts
index 75a1a75..ebb7421 100644
--- a/src/plugins/french/phenixscans.ts
+++ b/plugins/french/phenixscans.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/french/warriorlegendtrad.ts b/plugins/french/warriorlegendtrad.ts
similarity index 99%
rename from src/plugins/french/warriorlegendtrad.ts
rename to plugins/french/warriorlegendtrad.ts
index eaa4dd1..b411b42 100644
--- a/src/plugins/french/warriorlegendtrad.ts
+++ b/plugins/french/warriorlegendtrad.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
import dayjs from 'dayjs';
diff --git a/src/plugins/french/wuxialnscantrad.ts b/plugins/french/wuxialnscantrad.ts
similarity index 99%
rename from src/plugins/french/wuxialnscantrad.ts
rename to plugins/french/wuxialnscantrad.ts
index 8a4fe6b..5789ec2 100644
--- a/src/plugins/french/wuxialnscantrad.ts
+++ b/plugins/french/wuxialnscantrad.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
import dayjs from 'dayjs';
diff --git a/src/plugins/french/xiaowaz.ts b/plugins/french/xiaowaz.ts
similarity index 99%
rename from src/plugins/french/xiaowaz.ts
rename to plugins/french/xiaowaz.ts
index 56a7b80..9c3a0fb 100644
--- a/src/plugins/french/xiaowaz.ts
+++ b/plugins/french/xiaowaz.ts
@@ -1,6 +1,6 @@
import { Cheerio, CheerioAPI, load, Element } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/plugins/index.ts b/plugins/index.ts
new file mode 100644
index 0000000..46d924e
--- /dev/null
+++ b/plugins/index.ts
@@ -0,0 +1,497 @@
+import { Plugin } from '@/types/plugin';
+import p_0 from '@plugins/arabic/ArNovel[madara]';
+import p_1 from '@plugins/arabic/Azora[madara]';
+import p_2 from '@plugins/arabic/HizoManga[madara]';
+import p_3 from '@plugins/arabic/KolNovel[lightnovelwp]';
+import p_4 from '@plugins/arabic/Novel4Up[madara]';
+import p_5 from '@plugins/arabic/NovelsParadise[lightnovelwp]';
+import p_6 from '@plugins/arabic/Olaoecyou[madara]';
+import p_7 from '@plugins/arabic/Riwyat[madara]';
+import p_8 from '@plugins/arabic/dilartube';
+import p_9 from '@plugins/arabic/rewayatclub';
+import p_10 from '@plugins/arabic/sunovels';
+import p_11 from '@plugins/chinese/69shu';
+import p_12 from '@plugins/chinese/69xinshu';
+import p_13 from '@plugins/chinese/Quanben';
+import p_14 from '@plugins/chinese/ixdzs8';
+import p_15 from '@plugins/chinese/linovel';
+import p_16 from '@plugins/chinese/linovelib';
+import p_17 from '@plugins/chinese/linovelib_tw';
+import p_18 from '@plugins/chinese/novel543';
+import p_19 from '@plugins/english/AllNovelFull[readnovelfull]';
+import p_20 from '@plugins/english/AllNovel[readnovelfull]';
+import p_21 from '@plugins/english/ArcaneTranslations[lightnovelwp]';
+import p_22 from '@plugins/english/BelleReservoir[madara]';
+import p_23 from '@plugins/english/BoxNovel[readnovelfull]';
+import p_24 from '@plugins/english/CPUnovel[lightnovelwp]';
+import p_25 from '@plugins/english/CitrusAurora[madara]';
+import p_26 from '@plugins/english/CoralBoutique[madara]';
+import p_27 from '@plugins/english/DaoNovel[madara]';
+import p_28 from '@plugins/english/DaoTranslate[lightnovelwp]';
+import p_29 from '@plugins/english/DaoistQuest[fictioneer]';
+import p_30 from '@plugins/english/DearestRosalie[fictioneer]';
+import p_31 from '@plugins/english/DragonTea[madara]';
+import p_32 from '@plugins/english/Dragonholic[madara]';
+import p_33 from '@plugins/english/DuskBlossoms[madara]';
+import p_34 from '@plugins/english/ElloTL[lightnovelwp]';
+import p_35 from '@plugins/english/Eternalune[madara]';
+import p_36 from '@plugins/english/EtudeTranslations[madara]';
+import p_37 from '@plugins/english/FanNovel[readwn]';
+import p_38 from '@plugins/english/FansMTL[readwn]';
+import p_39 from '@plugins/english/FansTranslations[madara]';
+import p_40 from '@plugins/english/FirstKissNovel[madara]';
+import p_41 from '@plugins/english/Foxaholic[madara]';
+import p_42 from '@plugins/english/FreeWebNovel[readnovelfull]';
+import p_43 from '@plugins/english/GalaxyTranslations[madara]';
+import p_44 from '@plugins/english/Guavaread[madara]';
+import p_45 from '@plugins/english/HiraethTranslation[madara]';
+import p_46 from '@plugins/english/HotNovelPub[hotnovelpub]';
+import p_47 from '@plugins/english/Ippotranslations[lightnovelwp]';
+import p_48 from '@plugins/english/KeopiTranslations[lightnovelwp]';
+import p_49 from '@plugins/english/KnoxT[lightnovelwp]';
+import p_50 from '@plugins/english/LazyGirlTranslations[lightnovelwp]';
+import p_51 from '@plugins/english/LibRead[readnovelfull]';
+import p_52 from '@plugins/english/LightNovelCave[lightnovelworld]';
+import p_53 from '@plugins/english/LightNovelHeaven[madara]';
+import p_54 from '@plugins/english/LightNovelPlus[readnovelfull]';
+import p_55 from '@plugins/english/LightNovelPubVip[lightnovelworld]';
+import p_56 from '@plugins/english/LightNovelUpdates[madara]';
+import p_57 from '@plugins/english/LightNovelWord[lightnovelworld]';
+import p_58 from '@plugins/english/LilyontheValley[fictioneer]';
+import p_59 from '@plugins/english/Ltnovel[readwn]';
+import p_60 from '@plugins/english/LunarLetters[madara]';
+import p_61 from '@plugins/english/MTLNovel[madara]';
+import p_62 from '@plugins/english/MTLNovel[mtlnovel]';
+import p_63 from '@plugins/english/Meownovel[madara]';
+import p_64 from '@plugins/english/MoonlightNovels[lightnovelwp]';
+import p_65 from '@plugins/english/MostNovel[madara]';
+import p_66 from '@plugins/english/MysticalSeries[madara]';
+import p_67 from '@plugins/english/NeoSekaiTranslations[madara]';
+import p_68 from '@plugins/english/NitroManga[madara]';
+import p_69 from '@plugins/english/NobleMTL[lightnovelwp]';
+import p_70 from '@plugins/english/NovelBin[readnovelfull]';
+import p_71 from '@plugins/english/NovelCool[novelcool]';
+import p_72 from '@plugins/english/NovelFull[readnovelfull]';
+import p_73 from '@plugins/english/NovelLib[fictioneer]';
+import p_74 from '@plugins/english/NovelMultiverse[madara]';
+import p_75 from '@plugins/english/NovelOnline';
+import p_76 from '@plugins/english/NovelTranslate[madara]';
+import p_77 from '@plugins/english/NovelsKnight[lightnovelwp]';
+import p_78 from '@plugins/english/PandaMachineTranslations[lightnovelwp]';
+import p_79 from '@plugins/english/PastelTales[madara]';
+import p_80 from '@plugins/english/PenguinSquad[fictioneer]';
+import p_81 from '@plugins/english/Prizma[fictioneer]';
+import p_82 from '@plugins/english/Ranobes[ranobes]';
+import p_83 from '@plugins/english/Ranovel[madara]';
+import p_84 from '@plugins/english/ReadFanfic[madara]';
+import p_85 from '@plugins/english/ReadNovelFull[readnovelfull]';
+import p_86 from '@plugins/english/RequiemTranslations[lightnovelwp]';
+import p_87 from '@plugins/english/SalmonLatte[madara]';
+import p_88 from '@plugins/english/SleepyTranslations[madara]';
+import p_89 from '@plugins/english/SonicMTL[madara]';
+import p_90 from '@plugins/english/SrankManga[madara]';
+import p_91 from '@plugins/english/StorySeedling';
+import p_92 from '@plugins/english/SweetEscape[madara]';
+import p_93 from '@plugins/english/SystemTranslation[lightnovelwp]';
+import p_94 from '@plugins/english/TranslatinOtaku[madara]';
+import p_95 from '@plugins/english/TranslationWeaver[lightnovelwp]';
+import p_96 from '@plugins/english/UniversalNovel[lightnovelwp]';
+import p_97 from '@plugins/english/VandyTranslate[lightnovelwp]';
+import p_98 from '@plugins/english/VioletLily[madara]';
+import p_99 from '@plugins/english/WebNovelLover[madara]';
+import p_100 from '@plugins/english/WebNovelPub[lightnovelworld]';
+import p_101 from '@plugins/english/WebNovelTranslation[madara]';
+import p_102 from '@plugins/english/WhiteMoonlightNovels[lightnovelwp]';
+import p_103 from '@plugins/english/WooksTeahouse[madara]';
+import p_104 from '@plugins/english/WordExcerpt[madara]';
+import p_105 from '@plugins/english/WuxiaSpace[readwn]';
+import p_106 from '@plugins/english/WuxiaV[readwn]';
+import p_107 from '@plugins/english/WuxiaWorldSite[madara]';
+import p_108 from '@plugins/english/Wuxiabox[readwn]';
+import p_109 from '@plugins/english/Wuxiafox[readwn]';
+import p_110 from '@plugins/english/ZetroTranslation[madara]';
+import p_111 from '@plugins/english/ao3';
+import p_112 from '@plugins/english/bestlightnovel';
+import p_113 from '@plugins/english/chrysanthemumgarden';
+import p_114 from '@plugins/english/divinedaolibrary';
+import p_115 from '@plugins/english/dreambigtl';
+import p_116 from '@plugins/english/earlynovel';
+import p_117 from '@plugins/english/faqwikius';
+import p_118 from '@plugins/english/fenrirrealm';
+import p_119 from '@plugins/english/fictionzone';
+import p_120 from '@plugins/english/foxteller';
+import p_121 from '@plugins/english/genesis';
+import p_122 from '@plugins/english/inkitt';
+import p_123 from '@plugins/english/kdtnovels';
+import p_124 from '@plugins/english/lightnovelpub';
+import p_125 from '@plugins/english/lightnoveltranslation';
+import p_126 from '@plugins/english/lnmtl';
+import p_127 from '@plugins/english/mtlreader';
+import p_128 from '@plugins/english/mvlempyr';
+import p_129 from '@plugins/english/novelbuddy';
+import p_130 from '@plugins/english/novelfire';
+import p_131 from '@plugins/english/novelhall';
+import p_132 from '@plugins/english/novelight';
+import p_133 from '@plugins/english/novelupdates';
+import p_134 from '@plugins/english/pawread';
+import p_135 from '@plugins/english/rainofsnow';
+import p_136 from '@plugins/english/readfrom';
+import p_137 from '@plugins/english/readlitenovel';
+import p_138 from '@plugins/english/reaperscans';
+import p_139 from '@plugins/english/relibrary';
+import p_140 from '@plugins/english/royalroad';
+import p_141 from '@plugins/english/scribblehub';
+import p_142 from '@plugins/english/vynovel';
+import p_143 from '@plugins/english/webnovel';
+import p_144 from '@plugins/english/wtrlab';
+import p_145 from '@plugins/english/wuxiaworld';
+import p_146 from '@plugins/french/LighNovelFR[lightnovelwp]';
+import p_147 from '@plugins/french/MTLNovel(FR)[mtlnovel]';
+import p_148 from '@plugins/french/MassNovel[madara]';
+import p_149 from '@plugins/french/WorldNovel[madara]';
+import p_150 from '@plugins/french/chireads';
+import p_151 from '@plugins/french/harkeneliwood';
+import p_152 from '@plugins/french/kisswood';
+import p_153 from '@plugins/french/noveldeglace';
+import p_154 from '@plugins/french/novhell';
+import p_155 from '@plugins/french/phenixscans';
+import p_156 from '@plugins/french/warriorlegendtrad';
+import p_157 from '@plugins/french/wuxialnscantrad';
+import p_158 from '@plugins/french/xiaowaz';
+import p_159 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]';
+import p_160 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]';
+import p_161 from '@plugins/indonesian/MeioNovel[madara]';
+import p_162 from '@plugins/indonesian/NovelBookID[madara]';
+import p_163 from '@plugins/indonesian/Risenovel[madara]';
+import p_164 from '@plugins/indonesian/SekteNovel[lightnovelwp]';
+import p_165 from '@plugins/indonesian/WBNovel[madara]';
+import p_166 from '@plugins/indonesian/indowebnovel';
+import p_167 from '@plugins/indonesian/novelringan';
+import p_168 from '@plugins/indonesian/sakuranovel';
+import p_169 from '@plugins/japanese/Syosetu';
+import p_170 from '@plugins/japanese/kakuyomu';
+import p_171 from '@plugins/korean/Agitoon';
+import p_172 from '@plugins/korean/FortuneEternal[madara]';
+import p_173 from '@plugins/multi/komga';
+import p_174 from '@plugins/polish/novelki';
+import p_175 from '@plugins/portuguese/BetterNovels[lightnovelwp]';
+import p_176 from '@plugins/portuguese/CentralNovel[lightnovelwp]';
+import p_177 from '@plugins/portuguese/Kiniga[madara]';
+import p_178 from '@plugins/portuguese/LaNovels[hotnovelpub]';
+import p_179 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]';
+import p_180 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]';
+import p_181 from '@plugins/portuguese/blogdoamonnovels';
+import p_182 from '@plugins/portuguese/novelmania';
+import p_183 from '@plugins/portuguese/tsundoku';
+import p_184 from '@plugins/russian/Bookhamster[ifreedom]';
+import p_185 from '@plugins/russian/Erolate[rulate]';
+import p_186 from '@plugins/russian/EzNovels[hotnovelpub]';
+import p_187 from '@plugins/russian/LitSpace';
+import p_188 from '@plugins/russian/MTLNovel(RU)[mtlnovel]';
+import p_189 from '@plugins/russian/NovelCool(RU)[novelcool]';
+import p_190 from '@plugins/russian/Ranobes(RU)[ranobes]';
+import p_191 from '@plugins/russian/Rulate[rulate]';
+import p_192 from '@plugins/russian/authortoday';
+import p_193 from '@plugins/russian/bookriver';
+import p_194 from '@plugins/russian/ficbook';
+import p_195 from '@plugins/russian/jaomix';
+import p_196 from '@plugins/russian/neobook';
+import p_197 from '@plugins/russian/novelOvh';
+import p_198 from '@plugins/russian/novelTL';
+import p_199 from '@plugins/russian/ranobehub';
+import p_200 from '@plugins/russian/ranobelib';
+import p_201 from '@plugins/russian/ranoberf';
+import p_202 from '@plugins/russian/renovels';
+import p_203 from '@plugins/russian/ruvers';
+import p_204 from '@plugins/russian/topliba';
+import p_205 from '@plugins/russian/zelluloza';
+import p_206 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]';
+import p_207 from '@plugins/spanish/AllNovelRead[lightnovelwp]';
+import p_208 from '@plugins/spanish/AnimesHoy12[madara]';
+import p_209 from '@plugins/spanish/LightNovelDaily[hotnovelpub]';
+import p_210 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]';
+import p_211 from '@plugins/spanish/PanchoTranslations[madara]';
+import p_212 from '@plugins/spanish/TC&Sega[lightnovelwp]';
+import p_213 from '@plugins/spanish/TraduccionesAmistosas[madara]';
+import p_214 from '@plugins/spanish/hasutl';
+import p_215 from '@plugins/spanish/novelasligera';
+import p_216 from '@plugins/spanish/novelawuxia';
+import p_217 from '@plugins/spanish/oasistranslations';
+import p_218 from '@plugins/spanish/skynovels';
+import p_219 from '@plugins/spanish/tunovelaligera';
+import p_220 from '@plugins/spanish/yukitls';
+import p_221 from '@plugins/thai/NovelLucky[madara]';
+import p_222 from '@plugins/thai/NovelPDF[madara]';
+import p_223 from '@plugins/turkish/ArazNovel[madara]';
+import p_224 from '@plugins/turkish/EKTAPLAR[madara]';
+import p_225 from '@plugins/turkish/KodeksLibrary[lightnovelwp]';
+import p_226 from '@plugins/turkish/MangaTR';
+import p_227 from '@plugins/turkish/NABSCANS[madara]';
+import p_228 from '@plugins/turkish/Namevt[lightnovelwp]';
+import p_229 from '@plugins/turkish/NovelTR[lightnovelwp]';
+import p_230 from '@plugins/turkish/Noveloku[madara]';
+import p_231 from '@plugins/turkish/RagnarScans[madara]';
+import p_232 from '@plugins/turkish/ThNovels[hotnovelpub]';
+import p_233 from '@plugins/turkish/TurkceLightNovels[madara]';
+import p_234 from '@plugins/turkish/WebNovelOku[madara]';
+import p_235 from '@plugins/turkish/epiknovel';
+import p_236 from '@plugins/turkish/kakikata[madara]';
+import p_237 from '@plugins/ukrainian/bakainua';
+import p_238 from '@plugins/ukrainian/smakolykytl';
+import p_239 from '@plugins/ukrainian/uaranobeclub';
+import p_240 from '@plugins/vietnamese/LNHako';
+import p_241 from '@plugins/vietnamese/Truyenconect';
+import p_242 from '@plugins/vietnamese/lightnovelvn';
+import p_243 from '@plugins/vietnamese/nettruyen';
+import p_244 from '@plugins/vietnamese/truyenchu';
+import p_245 from '@plugins/vietnamese/truyenfull';
+
+const PLUGINS: Plugin.PluginBase[] = [
+ p_0,
+ p_1,
+ p_2,
+ p_3,
+ p_4,
+ p_5,
+ p_6,
+ p_7,
+ p_8,
+ p_9,
+ p_10,
+ p_11,
+ p_12,
+ p_13,
+ p_14,
+ p_15,
+ p_16,
+ p_17,
+ p_18,
+ p_19,
+ p_20,
+ p_21,
+ p_22,
+ p_23,
+ p_24,
+ p_25,
+ p_26,
+ p_27,
+ p_28,
+ p_29,
+ p_30,
+ p_31,
+ p_32,
+ p_33,
+ p_34,
+ p_35,
+ p_36,
+ p_37,
+ p_38,
+ p_39,
+ p_40,
+ p_41,
+ p_42,
+ p_43,
+ p_44,
+ p_45,
+ p_46,
+ p_47,
+ p_48,
+ p_49,
+ p_50,
+ p_51,
+ p_52,
+ p_53,
+ p_54,
+ p_55,
+ p_56,
+ p_57,
+ p_58,
+ p_59,
+ p_60,
+ p_61,
+ p_62,
+ p_63,
+ p_64,
+ p_65,
+ p_66,
+ p_67,
+ p_68,
+ p_69,
+ p_70,
+ p_71,
+ p_72,
+ p_73,
+ p_74,
+ p_75,
+ p_76,
+ p_77,
+ p_78,
+ p_79,
+ p_80,
+ p_81,
+ p_82,
+ p_83,
+ p_84,
+ p_85,
+ p_86,
+ p_87,
+ p_88,
+ p_89,
+ p_90,
+ p_91,
+ p_92,
+ p_93,
+ p_94,
+ p_95,
+ p_96,
+ p_97,
+ p_98,
+ p_99,
+ p_100,
+ p_101,
+ p_102,
+ p_103,
+ p_104,
+ p_105,
+ p_106,
+ p_107,
+ p_108,
+ p_109,
+ p_110,
+ p_111,
+ p_112,
+ p_113,
+ p_114,
+ p_115,
+ p_116,
+ p_117,
+ p_118,
+ p_119,
+ p_120,
+ p_121,
+ p_122,
+ p_123,
+ p_124,
+ p_125,
+ p_126,
+ p_127,
+ p_128,
+ p_129,
+ p_130,
+ p_131,
+ p_132,
+ p_133,
+ p_134,
+ p_135,
+ p_136,
+ p_137,
+ p_138,
+ p_139,
+ p_140,
+ p_141,
+ p_142,
+ p_143,
+ p_144,
+ p_145,
+ p_146,
+ p_147,
+ p_148,
+ p_149,
+ p_150,
+ p_151,
+ p_152,
+ p_153,
+ p_154,
+ p_155,
+ p_156,
+ p_157,
+ p_158,
+ p_159,
+ p_160,
+ p_161,
+ p_162,
+ p_163,
+ p_164,
+ p_165,
+ p_166,
+ p_167,
+ p_168,
+ p_169,
+ p_170,
+ p_171,
+ p_172,
+ p_173,
+ p_174,
+ p_175,
+ p_176,
+ p_177,
+ p_178,
+ p_179,
+ p_180,
+ p_181,
+ p_182,
+ p_183,
+ p_184,
+ p_185,
+ p_186,
+ p_187,
+ p_188,
+ p_189,
+ p_190,
+ p_191,
+ p_192,
+ p_193,
+ p_194,
+ p_195,
+ p_196,
+ p_197,
+ p_198,
+ p_199,
+ p_200,
+ p_201,
+ p_202,
+ p_203,
+ p_204,
+ p_205,
+ p_206,
+ p_207,
+ p_208,
+ p_209,
+ p_210,
+ p_211,
+ p_212,
+ p_213,
+ p_214,
+ p_215,
+ p_216,
+ p_217,
+ p_218,
+ p_219,
+ p_220,
+ p_221,
+ p_222,
+ p_223,
+ p_224,
+ p_225,
+ p_226,
+ p_227,
+ p_228,
+ p_229,
+ p_230,
+ p_231,
+ p_232,
+ p_233,
+ p_234,
+ p_235,
+ p_236,
+ p_237,
+ p_238,
+ p_239,
+ p_240,
+ p_241,
+ p_242,
+ p_243,
+ p_244,
+ p_245,
+];
+export default PLUGINS;
diff --git a/src/plugins/indonesian/indowebnovel.ts b/plugins/indonesian/indowebnovel.ts
similarity index 99%
rename from src/plugins/indonesian/indowebnovel.ts
rename to plugins/indonesian/indowebnovel.ts
index 9027cca..a524c6b 100644
--- a/src/plugins/indonesian/indowebnovel.ts
+++ b/plugins/indonesian/indowebnovel.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters, FilterTypes } from '@libs/filterInputs';
diff --git a/src/plugins/indonesian/novelringan.ts b/plugins/indonesian/novelringan.ts
similarity index 99%
rename from src/plugins/indonesian/novelringan.ts
rename to plugins/indonesian/novelringan.ts
index 326f0f1..5963cae 100644
--- a/src/plugins/indonesian/novelringan.ts
+++ b/plugins/indonesian/novelringan.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class NovelRingan implements Plugin.PluginBase {
diff --git a/src/plugins/indonesian/sakuranovel.ts b/plugins/indonesian/sakuranovel.ts
similarity index 99%
rename from src/plugins/indonesian/sakuranovel.ts
rename to plugins/indonesian/sakuranovel.ts
index 685b756..6200861 100644
--- a/src/plugins/indonesian/sakuranovel.ts
+++ b/plugins/indonesian/sakuranovel.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class SakuraNovel implements Plugin.PluginBase {
diff --git a/src/plugins/japanese/Syosetu.ts b/plugins/japanese/Syosetu.ts
similarity index 98%
rename from src/plugins/japanese/Syosetu.ts
rename to plugins/japanese/Syosetu.ts
index 3423377..d45d93d 100644
--- a/src/plugins/japanese/Syosetu.ts
+++ b/plugins/japanese/Syosetu.ts
@@ -1,11 +1,11 @@
import { load as loadCheerio } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
-// const novelStatus = require('@libs/novelStatus');
-// const isUrlAbsolute = require('@libs/isAbsoluteUrl');
+// const novelStatus = require('@/types/constants');
+// const isUrlAbsolute = require('@/lib/utils');
// const parseDate = require('@libs/parseDate');
class Syosetu implements Plugin.PluginBase {
diff --git a/src/plugins/japanese/kakuyomu.ts b/plugins/japanese/kakuyomu.ts
similarity index 98%
rename from src/plugins/japanese/kakuyomu.ts
rename to plugins/japanese/kakuyomu.ts
index 71359dd..fee85e4 100644
--- a/src/plugins/japanese/kakuyomu.ts
+++ b/plugins/japanese/kakuyomu.ts
@@ -1,5 +1,5 @@
-import { fetchText } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { fetchText } from '@/lib/fetch';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { load as loadCheerio } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/korean/Agitoon.ts b/plugins/korean/Agitoon.ts
similarity index 99%
rename from src/plugins/korean/Agitoon.ts
rename to plugins/korean/Agitoon.ts
index f34bd02..df3befe 100644
--- a/src/plugins/korean/Agitoon.ts
+++ b/plugins/korean/Agitoon.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
class Agitoon implements Plugin.PluginBase {
diff --git a/src/plugins/multi/komga.ts b/plugins/multi/komga.ts
similarity index 95%
rename from src/plugins/multi/komga.ts
rename to plugins/multi/komga.ts
index 943368e..c383779 100644
--- a/src/plugins/multi/komga.ts
+++ b/plugins/multi/komga.ts
@@ -1,9 +1,9 @@
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
-import { storage } from '@libs/storage';
+import { storage } from '@/lib/storage';
class KomgaPlugin implements Plugin.PluginBase {
id = 'komga';
@@ -26,10 +26,10 @@ class KomgaPlugin implements Plugin.PluginBase {
}).then(res => res.text());
}
- btoa(input: string = '') {
+ btoa(input = '') {
const chars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
- let str = input;
+ const str = input;
let output = '';
for (
@@ -67,11 +67,11 @@ class KomgaPlugin implements Plugin.PluginBase {
async getSeries(url: string): Promise {
const novels: Plugin.NovelItem[] = [];
- var response = await this.makeRequest(url);
+ const response = await this.makeRequest(url);
const series = JSON.parse(response).content;
- for (let s of series) {
+ for (const s of series) {
novels.push({
name: s.name,
path: 'api/v1/series/' + s.id,
@@ -110,7 +110,7 @@ class KomgaPlugin implements Plugin.PluginBase {
const url = this.site + novelPath;
- var response = await this.makeRequest(url);
+ const response = await this.makeRequest(url);
const series = JSON.parse(response);
@@ -152,7 +152,7 @@ class KomgaPlugin implements Plugin.PluginBase {
const booksData = JSON.parse(booksResponse).content;
- for (let book of booksData) {
+ for (const book of booksData) {
const bookManifestResponse = await this.makeRequest(
this.site + `opds/v2/books/${book.id}/manifest`,
);
@@ -162,7 +162,7 @@ class KomgaPlugin implements Plugin.PluginBase {
const toc = this.flattenArray(bookManifest.toc);
let i = 1;
- for (let page of bookManifest.readingOrder) {
+ for (const page of bookManifest.readingOrder) {
const tocItem = toc.find(
(v: any) => v.href?.split('#')[0] === page.href,
);
diff --git a/scripts/multisrc/fictioneer/generator.js b/plugins/multisrc/fictioneer/generator.js
similarity index 100%
rename from scripts/multisrc/fictioneer/generator.js
rename to plugins/multisrc/fictioneer/generator.js
diff --git a/scripts/multisrc/fictioneer/sources.json b/plugins/multisrc/fictioneer/sources.json
similarity index 100%
rename from scripts/multisrc/fictioneer/sources.json
rename to plugins/multisrc/fictioneer/sources.json
diff --git a/scripts/multisrc/fictioneer/template.ts b/plugins/multisrc/fictioneer/template.ts
similarity index 98%
rename from scripts/multisrc/fictioneer/template.ts
rename to plugins/multisrc/fictioneer/template.ts
index cdb9a0b..8ca8084 100644
--- a/scripts/multisrc/fictioneer/template.ts
+++ b/plugins/multisrc/fictioneer/template.ts
@@ -1,8 +1,8 @@
import { CheerioAPI, load as loadCheerio, load } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
-import { Filters } from '../../../src/libs/filterInputs';
+import { Filters } from '@libs/filterInputs';
type FictioneerOptions = {
browsePage: string;
diff --git a/scripts/multisrc/generate-multisrc-plugins.js b/plugins/multisrc/generate-multisrc-plugins.js
similarity index 94%
rename from scripts/multisrc/generate-multisrc-plugins.js
rename to plugins/multisrc/generate-multisrc-plugins.js
index 6d7c5c8..17cd119 100644
--- a/scripts/multisrc/generate-multisrc-plugins.js
+++ b/plugins/multisrc/generate-multisrc-plugins.js
@@ -24,7 +24,7 @@ const generate = async name => {
console.warn(name, ': lang, filename, pluginScript are required!');
continue;
}
- const pluginsDir = './src/plugins';
+ const pluginsDir = './plugins';
const filePath = path.join(
pluginsDir,
lang.toLowerCase(),
@@ -39,7 +39,7 @@ const generate = async name => {
}
};
-const MULTISRC_DIR = './scripts/multisrc';
+const MULTISRC_DIR = './plugins/multisrc';
const run = async () => {
const sources = fs
diff --git a/scripts/multisrc/hotnovelpub/filter_refresh.ts b/plugins/multisrc/hotnovelpub/filter_refresh.ts
similarity index 100%
rename from scripts/multisrc/hotnovelpub/filter_refresh.ts
rename to plugins/multisrc/hotnovelpub/filter_refresh.ts
diff --git a/scripts/multisrc/hotnovelpub/generator.js b/plugins/multisrc/hotnovelpub/generator.js
similarity index 100%
rename from scripts/multisrc/hotnovelpub/generator.js
rename to plugins/multisrc/hotnovelpub/generator.js
diff --git a/scripts/multisrc/hotnovelpub/sources.json b/plugins/multisrc/hotnovelpub/sources.json
similarity index 100%
rename from scripts/multisrc/hotnovelpub/sources.json
rename to plugins/multisrc/hotnovelpub/sources.json
diff --git a/scripts/multisrc/hotnovelpub/template.ts b/plugins/multisrc/hotnovelpub/template.ts
similarity index 99%
rename from scripts/multisrc/hotnovelpub/template.ts
rename to plugins/multisrc/hotnovelpub/template.ts
index 8eee869..5fa1246 100644
--- a/scripts/multisrc/hotnovelpub/template.ts
+++ b/plugins/multisrc/hotnovelpub/template.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
export type HotNovelPubMetadata = {
diff --git a/scripts/multisrc/ifreedom/generator.js b/plugins/multisrc/ifreedom/generator.js
similarity index 100%
rename from scripts/multisrc/ifreedom/generator.js
rename to plugins/multisrc/ifreedom/generator.js
diff --git a/scripts/multisrc/ifreedom/settings.json b/plugins/multisrc/ifreedom/settings.json
similarity index 100%
rename from scripts/multisrc/ifreedom/settings.json
rename to plugins/multisrc/ifreedom/settings.json
diff --git a/scripts/multisrc/ifreedom/sources.json b/plugins/multisrc/ifreedom/sources.json
similarity index 100%
rename from scripts/multisrc/ifreedom/sources.json
rename to plugins/multisrc/ifreedom/sources.json
diff --git a/scripts/multisrc/ifreedom/template.ts b/plugins/multisrc/ifreedom/template.ts
similarity index 99%
rename from scripts/multisrc/ifreedom/template.ts
rename to plugins/multisrc/ifreedom/template.ts
index bf14015..27f7054 100644
--- a/scripts/multisrc/ifreedom/template.ts
+++ b/plugins/multisrc/ifreedom/template.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { load as parseHTML } from 'cheerio';
import dayjs from 'dayjs';
diff --git a/scripts/multisrc/lightnovelworld/generator.js b/plugins/multisrc/lightnovelworld/generator.js
similarity index 100%
rename from scripts/multisrc/lightnovelworld/generator.js
rename to plugins/multisrc/lightnovelworld/generator.js
diff --git a/scripts/multisrc/lightnovelworld/sources.json b/plugins/multisrc/lightnovelworld/sources.json
similarity index 100%
rename from scripts/multisrc/lightnovelworld/sources.json
rename to plugins/multisrc/lightnovelworld/sources.json
diff --git a/scripts/multisrc/lightnovelworld/template.ts b/plugins/multisrc/lightnovelworld/template.ts
similarity index 99%
rename from scripts/multisrc/lightnovelworld/template.ts
rename to plugins/multisrc/lightnovelworld/template.ts
index df857d5..45c7432 100644
--- a/scripts/multisrc/lightnovelworld/template.ts
+++ b/plugins/multisrc/lightnovelworld/template.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs';
diff --git a/scripts/multisrc/lightnovelwp/README.md b/plugins/multisrc/lightnovelwp/README.md
similarity index 97%
rename from scripts/multisrc/lightnovelwp/README.md
rename to plugins/multisrc/lightnovelwp/README.md
index efd0ce4..f665fc4 100644
--- a/scripts/multisrc/lightnovelwp/README.md
+++ b/plugins/multisrc/lightnovelwp/README.md
@@ -44,6 +44,6 @@ and add it to the folder "public/static/multisrc/lightnovelwp/{sourceID}/icon.pn
### filters
To add filters to a source you need to run the script "get_filters.js" \
-(`npx node scripts/multisrc/lightnovelwp/get_filters.js`
+(`npx node plugins/multisrc/lightnovelwp/get_filters.js`
(if you are at the root of the project) (and you have ran "npm install" before))
and follow the instructions (url is easier and faster but sometimes it doesn't work)
diff --git a/scripts/multisrc/lightnovelwp/filters/TCSega.json b/plugins/multisrc/lightnovelwp/filters/TCSega.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/TCSega.json
rename to plugins/multisrc/lightnovelwp/filters/TCSega.json
diff --git a/scripts/multisrc/lightnovelwp/filters/allnovelread.json b/plugins/multisrc/lightnovelwp/filters/allnovelread.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/allnovelread.json
rename to plugins/multisrc/lightnovelwp/filters/allnovelread.json
diff --git a/scripts/multisrc/lightnovelwp/filters/arcane.json b/plugins/multisrc/lightnovelwp/filters/arcane.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/arcane.json
rename to plugins/multisrc/lightnovelwp/filters/arcane.json
diff --git a/scripts/multisrc/lightnovelwp/filters/bacalightnovel.json b/plugins/multisrc/lightnovelwp/filters/bacalightnovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/bacalightnovel.json
rename to plugins/multisrc/lightnovelwp/filters/bacalightnovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/centralnovel.json b/plugins/multisrc/lightnovelwp/filters/centralnovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/centralnovel.json
rename to plugins/multisrc/lightnovelwp/filters/centralnovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/cpunovel.json b/plugins/multisrc/lightnovelwp/filters/cpunovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/cpunovel.json
rename to plugins/multisrc/lightnovelwp/filters/cpunovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/daotranslate.json b/plugins/multisrc/lightnovelwp/filters/daotranslate.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/daotranslate.json
rename to plugins/multisrc/lightnovelwp/filters/daotranslate.json
diff --git a/scripts/multisrc/lightnovelwp/filters/ellotl.json b/plugins/multisrc/lightnovelwp/filters/ellotl.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/ellotl.json
rename to plugins/multisrc/lightnovelwp/filters/ellotl.json
diff --git a/scripts/multisrc/lightnovelwp/filters/ippotranslations.json b/plugins/multisrc/lightnovelwp/filters/ippotranslations.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/ippotranslations.json
rename to plugins/multisrc/lightnovelwp/filters/ippotranslations.json
diff --git a/scripts/multisrc/lightnovelwp/filters/keopi.json b/plugins/multisrc/lightnovelwp/filters/keopi.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/keopi.json
rename to plugins/multisrc/lightnovelwp/filters/keopi.json
diff --git a/scripts/multisrc/lightnovelwp/filters/keopitranslations.json b/plugins/multisrc/lightnovelwp/filters/keopitranslations.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/keopitranslations.json
rename to plugins/multisrc/lightnovelwp/filters/keopitranslations.json
diff --git a/scripts/multisrc/lightnovelwp/filters/knoxt.json b/plugins/multisrc/lightnovelwp/filters/knoxt.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/knoxt.json
rename to plugins/multisrc/lightnovelwp/filters/knoxt.json
diff --git a/scripts/multisrc/lightnovelwp/filters/kodekslibrary.json b/plugins/multisrc/lightnovelwp/filters/kodekslibrary.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/kodekslibrary.json
rename to plugins/multisrc/lightnovelwp/filters/kodekslibrary.json
diff --git a/scripts/multisrc/lightnovelwp/filters/kolnovel.json b/plugins/multisrc/lightnovelwp/filters/kolnovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/kolnovel.json
rename to plugins/multisrc/lightnovelwp/filters/kolnovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/lazygirltranslations.json b/plugins/multisrc/lightnovelwp/filters/lazygirltranslations.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/lazygirltranslations.json
rename to plugins/multisrc/lightnovelwp/filters/lazygirltranslations.json
diff --git a/scripts/multisrc/lightnovelwp/filters/lightnovelbrasil.json b/plugins/multisrc/lightnovelwp/filters/lightnovelbrasil.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/lightnovelbrasil.json
rename to plugins/multisrc/lightnovelwp/filters/lightnovelbrasil.json
diff --git a/scripts/multisrc/lightnovelwp/filters/lightnovelfr.json b/plugins/multisrc/lightnovelwp/filters/lightnovelfr.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/lightnovelfr.json
rename to plugins/multisrc/lightnovelwp/filters/lightnovelfr.json
diff --git a/scripts/multisrc/lightnovelwp/filters/moonlightnovel.json b/plugins/multisrc/lightnovelwp/filters/moonlightnovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/moonlightnovel.json
rename to plugins/multisrc/lightnovelwp/filters/moonlightnovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/namevt.json b/plugins/multisrc/lightnovelwp/filters/namevt.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/namevt.json
rename to plugins/multisrc/lightnovelwp/filters/namevt.json
diff --git a/scripts/multisrc/lightnovelwp/filters/noblemtl.json b/plugins/multisrc/lightnovelwp/filters/noblemtl.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/noblemtl.json
rename to plugins/multisrc/lightnovelwp/filters/noblemtl.json
diff --git a/scripts/multisrc/lightnovelwp/filters/novelsknight.json b/plugins/multisrc/lightnovelwp/filters/novelsknight.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/novelsknight.json
rename to plugins/multisrc/lightnovelwp/filters/novelsknight.json
diff --git a/scripts/multisrc/lightnovelwp/filters/novelsparadise.json b/plugins/multisrc/lightnovelwp/filters/novelsparadise.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/novelsparadise.json
rename to plugins/multisrc/lightnovelwp/filters/novelsparadise.json
diff --git a/scripts/multisrc/lightnovelwp/filters/noveltr.json b/plugins/multisrc/lightnovelwp/filters/noveltr.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/noveltr.json
rename to plugins/multisrc/lightnovelwp/filters/noveltr.json
diff --git a/scripts/multisrc/lightnovelwp/filters/pandamtl.json b/plugins/multisrc/lightnovelwp/filters/pandamtl.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/pandamtl.json
rename to plugins/multisrc/lightnovelwp/filters/pandamtl.json
diff --git a/scripts/multisrc/lightnovelwp/filters/requiemtls.json b/plugins/multisrc/lightnovelwp/filters/requiemtls.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/requiemtls.json
rename to plugins/multisrc/lightnovelwp/filters/requiemtls.json
diff --git a/scripts/multisrc/lightnovelwp/filters/sektenovel.json b/plugins/multisrc/lightnovelwp/filters/sektenovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/sektenovel.json
rename to plugins/multisrc/lightnovelwp/filters/sektenovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/systemtranslation.json b/plugins/multisrc/lightnovelwp/filters/systemtranslation.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/systemtranslation.json
rename to plugins/multisrc/lightnovelwp/filters/systemtranslation.json
diff --git a/scripts/multisrc/lightnovelwp/filters/transweaver.json b/plugins/multisrc/lightnovelwp/filters/transweaver.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/transweaver.json
rename to plugins/multisrc/lightnovelwp/filters/transweaver.json
diff --git a/scripts/multisrc/lightnovelwp/filters/universalnovel.json b/plugins/multisrc/lightnovelwp/filters/universalnovel.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/universalnovel.json
rename to plugins/multisrc/lightnovelwp/filters/universalnovel.json
diff --git a/scripts/multisrc/lightnovelwp/filters/vandytranslate.json b/plugins/multisrc/lightnovelwp/filters/vandytranslate.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/vandytranslate.json
rename to plugins/multisrc/lightnovelwp/filters/vandytranslate.json
diff --git a/scripts/multisrc/lightnovelwp/filters/whitemoonlightnovels.json b/plugins/multisrc/lightnovelwp/filters/whitemoonlightnovels.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/filters/whitemoonlightnovels.json
rename to plugins/multisrc/lightnovelwp/filters/whitemoonlightnovels.json
diff --git a/scripts/multisrc/lightnovelwp/generator.js b/plugins/multisrc/lightnovelwp/generator.js
similarity index 100%
rename from scripts/multisrc/lightnovelwp/generator.js
rename to plugins/multisrc/lightnovelwp/generator.js
diff --git a/scripts/multisrc/lightnovelwp/get_filters.js b/plugins/multisrc/lightnovelwp/get_filters.js
similarity index 100%
rename from scripts/multisrc/lightnovelwp/get_filters.js
rename to plugins/multisrc/lightnovelwp/get_filters.js
diff --git a/scripts/multisrc/lightnovelwp/sources.json b/plugins/multisrc/lightnovelwp/sources.json
similarity index 100%
rename from scripts/multisrc/lightnovelwp/sources.json
rename to plugins/multisrc/lightnovelwp/sources.json
diff --git a/scripts/multisrc/lightnovelwp/template.ts b/plugins/multisrc/lightnovelwp/template.ts
similarity index 99%
rename from scripts/multisrc/lightnovelwp/template.ts
rename to plugins/multisrc/lightnovelwp/template.ts
index 302ac84..d4b31a3 100644
--- a/scripts/multisrc/lightnovelwp/template.ts
+++ b/plugins/multisrc/lightnovelwp/template.ts
@@ -1,11 +1,11 @@
import { load } from 'cheerio';
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { defaultCover } from '@libs/defaultCover';
import { Filters } from '@libs/filterInputs';
-import { storage } from '@libs/storage';
+import { storage } from '@/lib/storage';
type LightNovelWPOptions = {
reverseChapters?: boolean;
@@ -112,7 +112,7 @@ class LightNovelWPPlugin implements Plugin.PluginBase {
novelPath = novelUrl.replace(this.site, '');
} else {
// TODO: report website new url to server
- let novelParts = novelUrl.split('/');
+ const novelParts = novelUrl.split('/');
novelParts.shift();
novelParts.shift();
novelParts.shift();
diff --git a/scripts/multisrc/madara/README.md b/plugins/multisrc/madara/README.md
similarity index 97%
rename from scripts/multisrc/madara/README.md
rename to plugins/multisrc/madara/README.md
index 809b182..ed6b230 100644
--- a/scripts/multisrc/madara/README.md
+++ b/plugins/multisrc/madara/README.md
@@ -39,6 +39,6 @@ and add it to the folder "public/static/multisrc/madara/{sourceID}/icon.png"
### filters
To add filters to a source you need to run the script "get_filters.js" \
-(`npx node scripts/multisrc/madara/get_filters.js`
+(`npx node plugins/multisrc/madara/get_filters.js`
(if you are at the root of the project) (and you have ran "npm install" before))
and follow the instructions (url is easier and faster but sometimes it doesn't work)
diff --git a/scripts/multisrc/madara/filters/1stkissnovel.json b/plugins/multisrc/madara/filters/1stkissnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/1stkissnovel.json
rename to plugins/multisrc/madara/filters/1stkissnovel.json
diff --git a/scripts/multisrc/madara/filters/Kakikata.json b/plugins/multisrc/madara/filters/Kakikata.json
similarity index 100%
rename from scripts/multisrc/madara/filters/Kakikata.json
rename to plugins/multisrc/madara/filters/Kakikata.json
diff --git a/scripts/multisrc/madara/filters/LightNovelUpdates.json b/plugins/multisrc/madara/filters/LightNovelUpdates.json
similarity index 100%
rename from scripts/multisrc/madara/filters/LightNovelUpdates.json
rename to plugins/multisrc/madara/filters/LightNovelUpdates.json
diff --git a/scripts/multisrc/madara/filters/WebNovelTraslation.json b/plugins/multisrc/madara/filters/WebNovelTraslation.json
similarity index 100%
rename from scripts/multisrc/madara/filters/WebNovelTraslation.json
rename to plugins/multisrc/madara/filters/WebNovelTraslation.json
diff --git a/scripts/multisrc/madara/filters/ar-mtl.json b/plugins/multisrc/madara/filters/ar-mtl.json
similarity index 100%
rename from scripts/multisrc/madara/filters/ar-mtl.json
rename to plugins/multisrc/madara/filters/ar-mtl.json
diff --git a/scripts/multisrc/madara/filters/arnovel.json b/plugins/multisrc/madara/filters/arnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/arnovel.json
rename to plugins/multisrc/madara/filters/arnovel.json
diff --git a/scripts/multisrc/madara/filters/asuralightnovel.json b/plugins/multisrc/madara/filters/asuralightnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/asuralightnovel.json
rename to plugins/multisrc/madara/filters/asuralightnovel.json
diff --git a/scripts/multisrc/madara/filters/azora.json b/plugins/multisrc/madara/filters/azora.json
similarity index 100%
rename from scripts/multisrc/madara/filters/azora.json
rename to plugins/multisrc/madara/filters/azora.json
diff --git a/scripts/multisrc/madara/filters/azraznovel.json b/plugins/multisrc/madara/filters/azraznovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/azraznovel.json
rename to plugins/multisrc/madara/filters/azraznovel.json
diff --git a/scripts/multisrc/madara/filters/bellereservoir.json b/plugins/multisrc/madara/filters/bellereservoir.json
similarity index 100%
rename from scripts/multisrc/madara/filters/bellereservoir.json
rename to plugins/multisrc/madara/filters/bellereservoir.json
diff --git a/scripts/multisrc/madara/filters/citrusaurora.json b/plugins/multisrc/madara/filters/citrusaurora.json
similarity index 100%
rename from scripts/multisrc/madara/filters/citrusaurora.json
rename to plugins/multisrc/madara/filters/citrusaurora.json
diff --git a/scripts/multisrc/madara/filters/coralboutique.json b/plugins/multisrc/madara/filters/coralboutique.json
similarity index 100%
rename from scripts/multisrc/madara/filters/coralboutique.json
rename to plugins/multisrc/madara/filters/coralboutique.json
diff --git a/scripts/multisrc/madara/filters/daonovel.json b/plugins/multisrc/madara/filters/daonovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/daonovel.json
rename to plugins/multisrc/madara/filters/daonovel.json
diff --git a/scripts/multisrc/madara/filters/dragonholic.json b/plugins/multisrc/madara/filters/dragonholic.json
similarity index 100%
rename from scripts/multisrc/madara/filters/dragonholic.json
rename to plugins/multisrc/madara/filters/dragonholic.json
diff --git a/scripts/multisrc/madara/filters/dragontea.json b/plugins/multisrc/madara/filters/dragontea.json
similarity index 100%
rename from scripts/multisrc/madara/filters/dragontea.json
rename to plugins/multisrc/madara/filters/dragontea.json
diff --git a/scripts/multisrc/madara/filters/duskblossoms.json b/plugins/multisrc/madara/filters/duskblossoms.json
similarity index 100%
rename from scripts/multisrc/madara/filters/duskblossoms.json
rename to plugins/multisrc/madara/filters/duskblossoms.json
diff --git a/scripts/multisrc/madara/filters/e-novel.json b/plugins/multisrc/madara/filters/e-novel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/e-novel.json
rename to plugins/multisrc/madara/filters/e-novel.json
diff --git a/scripts/multisrc/madara/filters/ekitaplar.json b/plugins/multisrc/madara/filters/ekitaplar.json
similarity index 100%
rename from scripts/multisrc/madara/filters/ekitaplar.json
rename to plugins/multisrc/madara/filters/ekitaplar.json
diff --git a/scripts/multisrc/madara/filters/eternalune.json b/plugins/multisrc/madara/filters/eternalune.json
similarity index 100%
rename from scripts/multisrc/madara/filters/eternalune.json
rename to plugins/multisrc/madara/filters/eternalune.json
diff --git a/scripts/multisrc/madara/filters/etudetranslations.json b/plugins/multisrc/madara/filters/etudetranslations.json
similarity index 100%
rename from scripts/multisrc/madara/filters/etudetranslations.json
rename to plugins/multisrc/madara/filters/etudetranslations.json
diff --git a/scripts/multisrc/madara/filters/fanTLS.json b/plugins/multisrc/madara/filters/fanTLS.json
similarity index 100%
rename from scripts/multisrc/madara/filters/fanTLS.json
rename to plugins/multisrc/madara/filters/fanTLS.json
diff --git a/scripts/multisrc/madara/filters/fanstranslations.json b/plugins/multisrc/madara/filters/fanstranslations.json
similarity index 100%
rename from scripts/multisrc/madara/filters/fanstranslations.json
rename to plugins/multisrc/madara/filters/fanstranslations.json
diff --git a/scripts/multisrc/madara/filters/fortuneeternal.json b/plugins/multisrc/madara/filters/fortuneeternal.json
similarity index 100%
rename from scripts/multisrc/madara/filters/fortuneeternal.json
rename to plugins/multisrc/madara/filters/fortuneeternal.json
diff --git a/scripts/multisrc/madara/filters/foxaholic.json b/plugins/multisrc/madara/filters/foxaholic.json
similarity index 100%
rename from scripts/multisrc/madara/filters/foxaholic.json
rename to plugins/multisrc/madara/filters/foxaholic.json
diff --git a/scripts/multisrc/madara/filters/galaxytranslations.json b/plugins/multisrc/madara/filters/galaxytranslations.json
similarity index 100%
rename from scripts/multisrc/madara/filters/galaxytranslations.json
rename to plugins/multisrc/madara/filters/galaxytranslations.json
diff --git a/scripts/multisrc/madara/filters/guavaread.json b/plugins/multisrc/madara/filters/guavaread.json
similarity index 100%
rename from scripts/multisrc/madara/filters/guavaread.json
rename to plugins/multisrc/madara/filters/guavaread.json
diff --git a/scripts/multisrc/madara/filters/hiraethtranslation.json b/plugins/multisrc/madara/filters/hiraethtranslation.json
similarity index 100%
rename from scripts/multisrc/madara/filters/hiraethtranslation.json
rename to plugins/multisrc/madara/filters/hiraethtranslation.json
diff --git a/scripts/multisrc/madara/filters/hizomanga.json b/plugins/multisrc/madara/filters/hizomanga.json
similarity index 100%
rename from scripts/multisrc/madara/filters/hizomanga.json
rename to plugins/multisrc/madara/filters/hizomanga.json
diff --git a/scripts/multisrc/madara/filters/kiniga.json b/plugins/multisrc/madara/filters/kiniga.json
similarity index 100%
rename from scripts/multisrc/madara/filters/kiniga.json
rename to plugins/multisrc/madara/filters/kiniga.json
diff --git a/scripts/multisrc/madara/filters/lnheaven.json b/plugins/multisrc/madara/filters/lnheaven.json
similarity index 100%
rename from scripts/multisrc/madara/filters/lnheaven.json
rename to plugins/multisrc/madara/filters/lnheaven.json
diff --git a/scripts/multisrc/madara/filters/lunarletters.json b/plugins/multisrc/madara/filters/lunarletters.json
similarity index 100%
rename from scripts/multisrc/madara/filters/lunarletters.json
rename to plugins/multisrc/madara/filters/lunarletters.json
diff --git a/scripts/multisrc/madara/filters/massnovel.json b/plugins/multisrc/madara/filters/massnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/massnovel.json
rename to plugins/multisrc/madara/filters/massnovel.json
diff --git a/scripts/multisrc/madara/filters/meionovel.json b/plugins/multisrc/madara/filters/meionovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/meionovel.json
rename to plugins/multisrc/madara/filters/meionovel.json
diff --git a/scripts/multisrc/madara/filters/meownovel.json b/plugins/multisrc/madara/filters/meownovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/meownovel.json
rename to plugins/multisrc/madara/filters/meownovel.json
diff --git a/scripts/multisrc/madara/filters/morenovel.json b/plugins/multisrc/madara/filters/morenovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/morenovel.json
rename to plugins/multisrc/madara/filters/morenovel.json
diff --git a/scripts/multisrc/madara/filters/mostnovel.json b/plugins/multisrc/madara/filters/mostnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/mostnovel.json
rename to plugins/multisrc/madara/filters/mostnovel.json
diff --git a/scripts/multisrc/madara/filters/mtl-novel.json b/plugins/multisrc/madara/filters/mtl-novel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/mtl-novel.json
rename to plugins/multisrc/madara/filters/mtl-novel.json
diff --git a/scripts/multisrc/madara/filters/mtlnovel.club.json b/plugins/multisrc/madara/filters/mtlnovel.club.json
similarity index 100%
rename from scripts/multisrc/madara/filters/mtlnovel.club.json
rename to plugins/multisrc/madara/filters/mtlnovel.club.json
diff --git a/scripts/multisrc/madara/filters/mysticalmerries.json b/plugins/multisrc/madara/filters/mysticalmerries.json
similarity index 100%
rename from scripts/multisrc/madara/filters/mysticalmerries.json
rename to plugins/multisrc/madara/filters/mysticalmerries.json
diff --git a/scripts/multisrc/madara/filters/nabiscans.json b/plugins/multisrc/madara/filters/nabiscans.json
similarity index 100%
rename from scripts/multisrc/madara/filters/nabiscans.json
rename to plugins/multisrc/madara/filters/nabiscans.json
diff --git a/scripts/multisrc/madara/filters/neosekaiTLS.json b/plugins/multisrc/madara/filters/neosekaiTLS.json
similarity index 100%
rename from scripts/multisrc/madara/filters/neosekaiTLS.json
rename to plugins/multisrc/madara/filters/neosekaiTLS.json
diff --git a/scripts/multisrc/madara/filters/nitromanga.json b/plugins/multisrc/madara/filters/nitromanga.json
similarity index 100%
rename from scripts/multisrc/madara/filters/nitromanga.json
rename to plugins/multisrc/madara/filters/nitromanga.json
diff --git a/scripts/multisrc/madara/filters/novel-lucky.json b/plugins/multisrc/madara/filters/novel-lucky.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novel-lucky.json
rename to plugins/multisrc/madara/filters/novel-lucky.json
diff --git a/scripts/multisrc/madara/filters/novel4up.json b/plugins/multisrc/madara/filters/novel4up.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novel4up.json
rename to plugins/multisrc/madara/filters/novel4up.json
diff --git a/scripts/multisrc/madara/filters/novelTL.json b/plugins/multisrc/madara/filters/novelTL.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelTL.json
rename to plugins/multisrc/madara/filters/novelTL.json
diff --git a/scripts/multisrc/madara/filters/novelbookid.json b/plugins/multisrc/madara/filters/novelbookid.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelbookid.json
rename to plugins/multisrc/madara/filters/novelbookid.json
diff --git a/scripts/multisrc/madara/filters/novelci.json b/plugins/multisrc/madara/filters/novelci.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelci.json
rename to plugins/multisrc/madara/filters/novelci.json
diff --git a/scripts/multisrc/madara/filters/novelmultiverse.json b/plugins/multisrc/madara/filters/novelmultiverse.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelmultiverse.json
rename to plugins/multisrc/madara/filters/novelmultiverse.json
diff --git a/scripts/multisrc/madara/filters/noveloku.json b/plugins/multisrc/madara/filters/noveloku.json
similarity index 100%
rename from scripts/multisrc/madara/filters/noveloku.json
rename to plugins/multisrc/madara/filters/noveloku.json
diff --git a/scripts/multisrc/madara/filters/novelokutr.json b/plugins/multisrc/madara/filters/novelokutr.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelokutr.json
rename to plugins/multisrc/madara/filters/novelokutr.json
diff --git a/scripts/multisrc/madara/filters/novelpdf.json b/plugins/multisrc/madara/filters/novelpdf.json
similarity index 100%
rename from scripts/multisrc/madara/filters/novelpdf.json
rename to plugins/multisrc/madara/filters/novelpdf.json
diff --git a/scripts/multisrc/madara/filters/olaoe.json b/plugins/multisrc/madara/filters/olaoe.json
similarity index 100%
rename from scripts/multisrc/madara/filters/olaoe.json
rename to plugins/multisrc/madara/filters/olaoe.json
diff --git a/scripts/multisrc/madara/filters/panchotranslations.json b/plugins/multisrc/madara/filters/panchotranslations.json
similarity index 100%
rename from scripts/multisrc/madara/filters/panchotranslations.json
rename to plugins/multisrc/madara/filters/panchotranslations.json
diff --git a/scripts/multisrc/madara/filters/pasteltales.json b/plugins/multisrc/madara/filters/pasteltales.json
similarity index 100%
rename from scripts/multisrc/madara/filters/pasteltales.json
rename to plugins/multisrc/madara/filters/pasteltales.json
diff --git a/scripts/multisrc/madara/filters/ragnarscans.json b/plugins/multisrc/madara/filters/ragnarscans.json
similarity index 100%
rename from scripts/multisrc/madara/filters/ragnarscans.json
rename to plugins/multisrc/madara/filters/ragnarscans.json
diff --git a/scripts/multisrc/madara/filters/ranovel.json b/plugins/multisrc/madara/filters/ranovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/ranovel.json
rename to plugins/multisrc/madara/filters/ranovel.json
diff --git a/scripts/multisrc/madara/filters/readfanfic.json b/plugins/multisrc/madara/filters/readfanfic.json
similarity index 100%
rename from scripts/multisrc/madara/filters/readfanfic.json
rename to plugins/multisrc/madara/filters/readfanfic.json
diff --git a/scripts/multisrc/madara/filters/riwyat.json b/plugins/multisrc/madara/filters/riwyat.json
similarity index 100%
rename from scripts/multisrc/madara/filters/riwyat.json
rename to plugins/multisrc/madara/filters/riwyat.json
diff --git a/scripts/multisrc/madara/filters/salmonlatte.json b/plugins/multisrc/madara/filters/salmonlatte.json
similarity index 100%
rename from scripts/multisrc/madara/filters/salmonlatte.json
rename to plugins/multisrc/madara/filters/salmonlatte.json
diff --git a/scripts/multisrc/madara/filters/sleeptTLS.json b/plugins/multisrc/madara/filters/sleeptTLS.json
similarity index 100%
rename from scripts/multisrc/madara/filters/sleeptTLS.json
rename to plugins/multisrc/madara/filters/sleeptTLS.json
diff --git a/scripts/multisrc/madara/filters/sonicmtl.json b/plugins/multisrc/madara/filters/sonicmtl.json
similarity index 100%
rename from scripts/multisrc/madara/filters/sonicmtl.json
rename to plugins/multisrc/madara/filters/sonicmtl.json
diff --git a/scripts/multisrc/madara/filters/sweetEscapeTL.json b/plugins/multisrc/madara/filters/sweetEscapeTL.json
similarity index 100%
rename from scripts/multisrc/madara/filters/sweetEscapeTL.json
rename to plugins/multisrc/madara/filters/sweetEscapeTL.json
diff --git a/scripts/multisrc/madara/filters/sweetescape.json b/plugins/multisrc/madara/filters/sweetescape.json
similarity index 100%
rename from scripts/multisrc/madara/filters/sweetescape.json
rename to plugins/multisrc/madara/filters/sweetescape.json
diff --git a/scripts/multisrc/madara/filters/translatinotaku.json b/plugins/multisrc/madara/filters/translatinotaku.json
similarity index 100%
rename from scripts/multisrc/madara/filters/translatinotaku.json
rename to plugins/multisrc/madara/filters/translatinotaku.json
diff --git a/scripts/multisrc/madara/filters/turkcelightnovels.json b/plugins/multisrc/madara/filters/turkcelightnovels.json
similarity index 100%
rename from scripts/multisrc/madara/filters/turkcelightnovels.json
rename to plugins/multisrc/madara/filters/turkcelightnovels.json
diff --git a/scripts/multisrc/madara/filters/violetlily.json b/plugins/multisrc/madara/filters/violetlily.json
similarity index 100%
rename from scripts/multisrc/madara/filters/violetlily.json
rename to plugins/multisrc/madara/filters/violetlily.json
diff --git a/scripts/multisrc/madara/filters/wbnovel.json b/plugins/multisrc/madara/filters/wbnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/wbnovel.json
rename to plugins/multisrc/madara/filters/wbnovel.json
diff --git a/scripts/multisrc/madara/filters/webnoveloku.json b/plugins/multisrc/madara/filters/webnoveloku.json
similarity index 100%
rename from scripts/multisrc/madara/filters/webnoveloku.json
rename to plugins/multisrc/madara/filters/webnoveloku.json
diff --git a/scripts/multisrc/madara/filters/webnovelover.json b/plugins/multisrc/madara/filters/webnovelover.json
similarity index 100%
rename from scripts/multisrc/madara/filters/webnovelover.json
rename to plugins/multisrc/madara/filters/webnovelover.json
diff --git a/scripts/multisrc/madara/filters/wooksteahouse.json b/plugins/multisrc/madara/filters/wooksteahouse.json
similarity index 100%
rename from scripts/multisrc/madara/filters/wooksteahouse.json
rename to plugins/multisrc/madara/filters/wooksteahouse.json
diff --git a/scripts/multisrc/madara/filters/wordexcerpt.json b/plugins/multisrc/madara/filters/wordexcerpt.json
similarity index 100%
rename from scripts/multisrc/madara/filters/wordexcerpt.json
rename to plugins/multisrc/madara/filters/wordexcerpt.json
diff --git a/scripts/multisrc/madara/filters/worldnovel.json b/plugins/multisrc/madara/filters/worldnovel.json
similarity index 100%
rename from scripts/multisrc/madara/filters/worldnovel.json
rename to plugins/multisrc/madara/filters/worldnovel.json
diff --git a/scripts/multisrc/madara/filters/wuxiaworld.site.json b/plugins/multisrc/madara/filters/wuxiaworld.site.json
similarity index 100%
rename from scripts/multisrc/madara/filters/wuxiaworld.site.json
rename to plugins/multisrc/madara/filters/wuxiaworld.site.json
diff --git a/scripts/multisrc/madara/filters/zetroTL.json b/plugins/multisrc/madara/filters/zetroTL.json
similarity index 100%
rename from scripts/multisrc/madara/filters/zetroTL.json
rename to plugins/multisrc/madara/filters/zetroTL.json
diff --git a/scripts/multisrc/madara/generator.js b/plugins/multisrc/madara/generator.js
similarity index 100%
rename from scripts/multisrc/madara/generator.js
rename to plugins/multisrc/madara/generator.js
diff --git a/scripts/multisrc/madara/get_filters.js b/plugins/multisrc/madara/get_filters.js
similarity index 100%
rename from scripts/multisrc/madara/get_filters.js
rename to plugins/multisrc/madara/get_filters.js
diff --git a/scripts/multisrc/madara/sources.json b/plugins/multisrc/madara/sources.json
similarity index 100%
rename from scripts/multisrc/madara/sources.json
rename to plugins/multisrc/madara/sources.json
diff --git a/scripts/multisrc/madara/template.ts b/plugins/multisrc/madara/template.ts
similarity index 99%
rename from scripts/multisrc/madara/template.ts
rename to plugins/multisrc/madara/template.ts
index 4c8752d..bb825da 100644
--- a/scripts/multisrc/madara/template.ts
+++ b/plugins/multisrc/madara/template.ts
@@ -1,11 +1,11 @@
import { fetchApi } from '@libs/fetch';
import { Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Cheerio, AnyNode, CheerioAPI, load as parseHTML } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
import dayjs from 'dayjs';
-import { storage } from '@libs/storage';
+import { storage } from '@/lib/storage';
const includesAny = (str: string, keywords: string[]) =>
new RegExp(keywords.join('|')).test(str);
diff --git a/scripts/multisrc/mtlnovel/filters/mtlnovel.json b/plugins/multisrc/mtlnovel/filters/mtlnovel.json
similarity index 100%
rename from scripts/multisrc/mtlnovel/filters/mtlnovel.json
rename to plugins/multisrc/mtlnovel/filters/mtlnovel.json
diff --git a/scripts/multisrc/mtlnovel/generator.js b/plugins/multisrc/mtlnovel/generator.js
similarity index 100%
rename from scripts/multisrc/mtlnovel/generator.js
rename to plugins/multisrc/mtlnovel/generator.js
diff --git a/scripts/multisrc/mtlnovel/sources.json b/plugins/multisrc/mtlnovel/sources.json
similarity index 100%
rename from scripts/multisrc/mtlnovel/sources.json
rename to plugins/multisrc/mtlnovel/sources.json
diff --git a/scripts/multisrc/mtlnovel/template.ts b/plugins/multisrc/mtlnovel/template.ts
similarity index 99%
rename from scripts/multisrc/mtlnovel/template.ts
rename to plugins/multisrc/mtlnovel/template.ts
index 261edd0..e0a4437 100644
--- a/scripts/multisrc/mtlnovel/template.ts
+++ b/plugins/multisrc/mtlnovel/template.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { defaultCover } from '@libs/defaultCover';
import { Filters } from '@libs/filterInputs';
diff --git a/scripts/multisrc/novelcool/generator.js b/plugins/multisrc/novelcool/generator.js
similarity index 100%
rename from scripts/multisrc/novelcool/generator.js
rename to plugins/multisrc/novelcool/generator.js
diff --git a/scripts/multisrc/novelcool/sources.json b/plugins/multisrc/novelcool/sources.json
similarity index 100%
rename from scripts/multisrc/novelcool/sources.json
rename to plugins/multisrc/novelcool/sources.json
diff --git a/scripts/multisrc/novelcool/template.ts b/plugins/multisrc/novelcool/template.ts
similarity index 99%
rename from scripts/multisrc/novelcool/template.ts
rename to plugins/multisrc/novelcool/template.ts
index ace9141..80df521 100644
--- a/scripts/multisrc/novelcool/template.ts
+++ b/plugins/multisrc/novelcool/template.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs';
diff --git a/scripts/multisrc/ranobes/generator.js b/plugins/multisrc/ranobes/generator.js
similarity index 100%
rename from scripts/multisrc/ranobes/generator.js
rename to plugins/multisrc/ranobes/generator.js
diff --git a/scripts/multisrc/ranobes/sources.json b/plugins/multisrc/ranobes/sources.json
similarity index 100%
rename from scripts/multisrc/ranobes/sources.json
rename to plugins/multisrc/ranobes/sources.json
diff --git a/scripts/multisrc/ranobes/template.ts b/plugins/multisrc/ranobes/template.ts
similarity index 99%
rename from scripts/multisrc/ranobes/template.ts
rename to plugins/multisrc/ranobes/template.ts
index aeb8b75..788ee49 100644
--- a/scripts/multisrc/ranobes/template.ts
+++ b/plugins/multisrc/ranobes/template.ts
@@ -1,6 +1,6 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
type RanobesOptions = {
diff --git a/scripts/multisrc/readnovelfull/README.md b/plugins/multisrc/readnovelfull/README.md
similarity index 94%
rename from scripts/multisrc/readnovelfull/README.md
rename to plugins/multisrc/readnovelfull/README.md
index ab799a9..7e0e7d6 100644
--- a/scripts/multisrc/readnovelfull/README.md
+++ b/plugins/multisrc/readnovelfull/README.md
@@ -16,8 +16,9 @@ To add a new source you need to add it to sources.json:
- sourceName: the name of the source (you can use the value of "name" in "https://site.com/wp-json/" if it exists)
- sourceSite: the site url
- options: the options of the source
+
- lang?: the language of the source (default: "English") (check that the language
- exists in the languages (check folder names in "plugins/"))
+ exists in the languages (check folder names in "plugins/"))
- versionIncrements?: needs to be updated everytime the site url is updated
- latestPage: the href value using this CSS selector `a[title="Latest Release"]`
- searchPage: path for search
@@ -26,17 +27,17 @@ To add a new source you need to add it to sources.json:
- pageParam?: if a site uses something other than "page" for accessing pages
// All the following is for when if a page uses a main path for querying novels and just adds params to it to get different outputs (see urls in lightnovelplus)
+
- novelListing?: Main path for browsing novels
- typeParam?: Field for entering the type of novelListing (eg: latest, hot, completed, etc), default: type
- genreParam?: Field for entering type of novelListing dedicated for genres (since param websites dont use the path change), default: category_novel
- genreKey?: Field for entering key representing the genre within the genreParam, default: id (eg: ?type=category_novel&id={value})
- langParam?: Field for entering the key representing language(?), do not understand reason for this param honestly, but recreate normal website behaviour as much as possible, default: none.
- - urlLangCode?: the value for langParam, default: none. eg: 'en'
-
+ - urlLangCode?: the value for langParam, default: none. eg: 'en'
### filters
To add filters to a source you need to run the script "get_filters.js" \
-(`npx node scripts/multisrc/readnovelfull/get_filters.js`
+(`npx node plugins/multisrc/readnovelfull/get_filters.js`
(if you are at the root of the project) (and you have ran "npm install" before))
and follow the instructions (url is easier and faster but sometimes it doesn't work)
diff --git a/scripts/multisrc/readnovelfull/filters/FWN.com.json b/plugins/multisrc/readnovelfull/filters/FWN.com.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/FWN.com.json
rename to plugins/multisrc/readnovelfull/filters/FWN.com.json
diff --git a/scripts/multisrc/readnovelfull/filters/allnovel.json b/plugins/multisrc/readnovelfull/filters/allnovel.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/allnovel.json
rename to plugins/multisrc/readnovelfull/filters/allnovel.json
diff --git a/scripts/multisrc/readnovelfull/filters/anf.net.json b/plugins/multisrc/readnovelfull/filters/anf.net.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/anf.net.json
rename to plugins/multisrc/readnovelfull/filters/anf.net.json
diff --git a/scripts/multisrc/readnovelfull/filters/boxnovel.json b/plugins/multisrc/readnovelfull/filters/boxnovel.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/boxnovel.json
rename to plugins/multisrc/readnovelfull/filters/boxnovel.json
diff --git a/scripts/multisrc/readnovelfull/filters/libread.json b/plugins/multisrc/readnovelfull/filters/libread.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/libread.json
rename to plugins/multisrc/readnovelfull/filters/libread.json
diff --git a/scripts/multisrc/readnovelfull/filters/lightnovelplus.json b/plugins/multisrc/readnovelfull/filters/lightnovelplus.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/lightnovelplus.json
rename to plugins/multisrc/readnovelfull/filters/lightnovelplus.json
diff --git a/scripts/multisrc/readnovelfull/filters/novelbin.json b/plugins/multisrc/readnovelfull/filters/novelbin.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/novelbin.json
rename to plugins/multisrc/readnovelfull/filters/novelbin.json
diff --git a/scripts/multisrc/readnovelfull/filters/novelfull.json b/plugins/multisrc/readnovelfull/filters/novelfull.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/novelfull.json
rename to plugins/multisrc/readnovelfull/filters/novelfull.json
diff --git a/scripts/multisrc/readnovelfull/filters/readnovelfull.json b/plugins/multisrc/readnovelfull/filters/readnovelfull.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/filters/readnovelfull.json
rename to plugins/multisrc/readnovelfull/filters/readnovelfull.json
diff --git a/scripts/multisrc/readnovelfull/generator.js b/plugins/multisrc/readnovelfull/generator.js
similarity index 100%
rename from scripts/multisrc/readnovelfull/generator.js
rename to plugins/multisrc/readnovelfull/generator.js
diff --git a/scripts/multisrc/readnovelfull/get_filters.js b/plugins/multisrc/readnovelfull/get_filters.js
similarity index 100%
rename from scripts/multisrc/readnovelfull/get_filters.js
rename to plugins/multisrc/readnovelfull/get_filters.js
diff --git a/scripts/multisrc/readnovelfull/sources.json b/plugins/multisrc/readnovelfull/sources.json
similarity index 100%
rename from scripts/multisrc/readnovelfull/sources.json
rename to plugins/multisrc/readnovelfull/sources.json
diff --git a/scripts/multisrc/readnovelfull/template.ts b/plugins/multisrc/readnovelfull/template.ts
similarity index 99%
rename from scripts/multisrc/readnovelfull/template.ts
rename to plugins/multisrc/readnovelfull/template.ts
index 97aa249..f883ad5 100644
--- a/scripts/multisrc/readnovelfull/template.ts
+++ b/plugins/multisrc/readnovelfull/template.ts
@@ -1,6 +1,6 @@
import { Parser } from 'htmlparser2';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters } from '@libs/filterInputs';
diff --git a/scripts/multisrc/readwn/filters/fannovel.json b/plugins/multisrc/readwn/filters/fannovel.json
similarity index 100%
rename from scripts/multisrc/readwn/filters/fannovel.json
rename to plugins/multisrc/readwn/filters/fannovel.json
diff --git a/scripts/multisrc/readwn/filters/ltnovel.json b/plugins/multisrc/readwn/filters/ltnovel.json
similarity index 100%
rename from scripts/multisrc/readwn/filters/ltnovel.json
rename to plugins/multisrc/readwn/filters/ltnovel.json
diff --git a/scripts/multisrc/readwn/filters/wuxiacity.json b/plugins/multisrc/readwn/filters/wuxiacity.json
similarity index 100%
rename from scripts/multisrc/readwn/filters/wuxiacity.json
rename to plugins/multisrc/readwn/filters/wuxiacity.json
diff --git a/scripts/multisrc/readwn/filters/wuxiamtl.json b/plugins/multisrc/readwn/filters/wuxiamtl.json
similarity index 100%
rename from scripts/multisrc/readwn/filters/wuxiamtl.json
rename to plugins/multisrc/readwn/filters/wuxiamtl.json
diff --git a/scripts/multisrc/readwn/filters/wuxiap.json b/plugins/multisrc/readwn/filters/wuxiap.json
similarity index 100%
rename from scripts/multisrc/readwn/filters/wuxiap.json
rename to plugins/multisrc/readwn/filters/wuxiap.json
diff --git a/scripts/multisrc/readwn/generator.js b/plugins/multisrc/readwn/generator.js
similarity index 100%
rename from scripts/multisrc/readwn/generator.js
rename to plugins/multisrc/readwn/generator.js
diff --git a/scripts/multisrc/readwn/get_filters.ts b/plugins/multisrc/readwn/get_filters.ts
similarity index 100%
rename from scripts/multisrc/readwn/get_filters.ts
rename to plugins/multisrc/readwn/get_filters.ts
diff --git a/scripts/multisrc/readwn/settings.json b/plugins/multisrc/readwn/settings.json
similarity index 100%
rename from scripts/multisrc/readwn/settings.json
rename to plugins/multisrc/readwn/settings.json
diff --git a/scripts/multisrc/readwn/sources.json b/plugins/multisrc/readwn/sources.json
similarity index 100%
rename from scripts/multisrc/readwn/sources.json
rename to plugins/multisrc/readwn/sources.json
diff --git a/scripts/multisrc/readwn/template.ts b/plugins/multisrc/readwn/template.ts
similarity index 99%
rename from scripts/multisrc/readwn/template.ts
rename to plugins/multisrc/readwn/template.ts
index 5a03a46..4b73f4d 100644
--- a/scripts/multisrc/readwn/template.ts
+++ b/plugins/multisrc/readwn/template.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { load as parseHTML } from 'cheerio';
import dayjs from 'dayjs';
diff --git a/scripts/multisrc/rulate/generator.js b/plugins/multisrc/rulate/generator.js
similarity index 100%
rename from scripts/multisrc/rulate/generator.js
rename to plugins/multisrc/rulate/generator.js
diff --git a/scripts/multisrc/rulate/settings.json b/plugins/multisrc/rulate/settings.json
similarity index 100%
rename from scripts/multisrc/rulate/settings.json
rename to plugins/multisrc/rulate/settings.json
diff --git a/scripts/multisrc/rulate/sources.json b/plugins/multisrc/rulate/sources.json
similarity index 100%
rename from scripts/multisrc/rulate/sources.json
rename to plugins/multisrc/rulate/sources.json
diff --git a/scripts/multisrc/rulate/template.ts b/plugins/multisrc/rulate/template.ts
similarity index 99%
rename from scripts/multisrc/rulate/template.ts
rename to plugins/multisrc/rulate/template.ts
index e5487d0..a5bee83 100644
--- a/scripts/multisrc/rulate/template.ts
+++ b/plugins/multisrc/rulate/template.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { load as parseHTML } from 'cheerio';
import dayjs from 'dayjs';
diff --git a/src/plugins/polish/novelki.ts b/plugins/polish/novelki.ts
similarity index 99%
rename from src/plugins/polish/novelki.ts
rename to plugins/polish/novelki.ts
index 0ba7780..be3e1af 100644
--- a/src/plugins/polish/novelki.ts
+++ b/plugins/polish/novelki.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { load as parseHTML } from 'cheerio';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/portuguese/.gitkeep b/plugins/portuguese/.gitkeep
similarity index 100%
rename from src/plugins/portuguese/.gitkeep
rename to plugins/portuguese/.gitkeep
diff --git a/src/plugins/portuguese/blogdoamonnovels.ts b/plugins/portuguese/blogdoamonnovels.ts
similarity index 99%
rename from src/plugins/portuguese/blogdoamonnovels.ts
rename to plugins/portuguese/blogdoamonnovels.ts
index 82123d5..83328cb 100644
--- a/src/plugins/portuguese/blogdoamonnovels.ts
+++ b/plugins/portuguese/blogdoamonnovels.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { Filters } from '@libs/filterInputs';
diff --git a/src/plugins/portuguese/novelmania.ts b/plugins/portuguese/novelmania.ts
similarity index 99%
rename from src/plugins/portuguese/novelmania.ts
rename to plugins/portuguese/novelmania.ts
index 5709802..d3cda71 100644
--- a/src/plugins/portuguese/novelmania.ts
+++ b/plugins/portuguese/novelmania.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
import { load as parseHTML } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
diff --git a/src/plugins/portuguese/tsundoku.ts b/plugins/portuguese/tsundoku.ts
similarity index 99%
rename from src/plugins/portuguese/tsundoku.ts
rename to plugins/portuguese/tsundoku.ts
index 3710591..5dd4204 100644
--- a/src/plugins/portuguese/tsundoku.ts
+++ b/plugins/portuguese/tsundoku.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import dayjs from 'dayjs';
import { Filters, FilterTypes } from '@libs/filterInputs';
diff --git a/src/plugins/russian/LitSpace.ts b/plugins/russian/LitSpace.ts
similarity index 96%
rename from src/plugins/russian/LitSpace.ts
rename to plugins/russian/LitSpace.ts
index 49e53ec..3a2d867 100644
--- a/src/plugins/russian/LitSpace.ts
+++ b/plugins/russian/LitSpace.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
@@ -197,7 +197,7 @@ class freedlit implements Plugin.PluginBase {
export default new freedlit();
-interface Books {
+type Books = {
current_page: number;
data: DataEntity[];
first_page_url: string;
@@ -210,8 +210,8 @@ interface Books {
prev_page_url?: null;
to: number;
total: number;
-}
-interface DataEntity {
+};
+type DataEntity = {
id: number;
item_id: number;
type: string;
@@ -252,29 +252,29 @@ interface DataEntity {
annotation: string;
total_comments: number;
total_libraries: number;
-}
-interface AuthorsNamesEntity {
+};
+type AuthorsNamesEntity = {
id: number;
url: string;
name: string;
type: string;
-}
-interface GenresEntity {
+};
+type GenresEntity = {
id: number;
-}
-interface TagsEntity {
+};
+type TagsEntity = {
id: number;
name: string;
-}
+};
-interface chaptersData {
+type chaptersData = {
id: number;
header: string;
first_published_formated: string;
intro_snippet_end: number;
-}
+};
-interface chapterContent {
+type chapterContent = {
id: number;
book_id: number;
header: string;
@@ -289,9 +289,9 @@ interface chapterContent {
is_chapter_avalaible: boolean;
total_characters: number;
total_characters_clear: string;
-}
+};
-export interface book {
+export type book = {
id: number;
cover?: string | null;
title?: string | null;
@@ -307,4 +307,4 @@ export interface book {
author_name?: string | null;
user_link?: string | null;
img?: string | null;
-}
+};
diff --git a/src/plugins/russian/authortoday.ts b/plugins/russian/authortoday.ts
similarity index 99%
rename from src/plugins/russian/authortoday.ts
rename to plugins/russian/authortoday.ts
index 8a86834..23d2a61 100644
--- a/src/plugins/russian/authortoday.ts
+++ b/plugins/russian/authortoday.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/russian/bookriver.ts b/plugins/russian/bookriver.ts
similarity index 99%
rename from src/plugins/russian/bookriver.ts
rename to plugins/russian/bookriver.ts
index 9f53c31..0a51a1e 100644
--- a/src/plugins/russian/bookriver.ts
+++ b/plugins/russian/bookriver.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/ficbook.ts b/plugins/russian/ficbook.ts
similarity index 99%
rename from src/plugins/russian/ficbook.ts
rename to plugins/russian/ficbook.ts
index d04bdf9..e343072 100644
--- a/src/plugins/russian/ficbook.ts
+++ b/plugins/russian/ficbook.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/jaomix.ts b/plugins/russian/jaomix.ts
similarity index 99%
rename from src/plugins/russian/jaomix.ts
rename to plugins/russian/jaomix.ts
index 33cc846..a60bb16 100644
--- a/src/plugins/russian/jaomix.ts
+++ b/plugins/russian/jaomix.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/neobook.ts b/plugins/russian/neobook.ts
similarity index 99%
rename from src/plugins/russian/neobook.ts
rename to plugins/russian/neobook.ts
index 1aef565..3b989c1 100644
--- a/src/plugins/russian/neobook.ts
+++ b/plugins/russian/neobook.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/russian/novelOvh.ts b/plugins/russian/novelOvh.ts
similarity index 99%
rename from src/plugins/russian/novelOvh.ts
rename to plugins/russian/novelOvh.ts
index 0024f34..f50da09 100644
--- a/src/plugins/russian/novelOvh.ts
+++ b/plugins/russian/novelOvh.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/novelTL.ts b/plugins/russian/novelTL.ts
similarity index 99%
rename from src/plugins/russian/novelTL.ts
rename to plugins/russian/novelTL.ts
index 0371ad3..79d237b 100644
--- a/src/plugins/russian/novelTL.ts
+++ b/plugins/russian/novelTL.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/russian/ranobehub.ts b/plugins/russian/ranobehub.ts
similarity index 99%
rename from src/plugins/russian/ranobehub.ts
rename to plugins/russian/ranobehub.ts
index caa81c4..0459db0 100644
--- a/src/plugins/russian/ranobehub.ts
+++ b/plugins/russian/ranobehub.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/ranobelib.ts b/plugins/russian/ranobelib.ts
similarity index 99%
rename from src/plugins/russian/ranobelib.ts
rename to plugins/russian/ranobelib.ts
index ba899cf..b59c067 100644
--- a/src/plugins/russian/ranobelib.ts
+++ b/plugins/russian/ranobelib.ts
@@ -1,9 +1,9 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
-import { storage, localStorage } from '@libs/storage';
+import { storage, localStorage } from '@/lib/storage';
import dayjs from 'dayjs';
const statusKey: Record = {
diff --git a/src/plugins/russian/ranoberf.ts b/plugins/russian/ranoberf.ts
similarity index 99%
rename from src/plugins/russian/ranoberf.ts
rename to plugins/russian/ranoberf.ts
index bbac441..e5d557f 100644
--- a/src/plugins/russian/ranoberf.ts
+++ b/plugins/russian/ranoberf.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/russian/renovels.ts b/plugins/russian/renovels.ts
similarity index 99%
rename from src/plugins/russian/renovels.ts
rename to plugins/russian/renovels.ts
index aab6f67..3aeec10 100644
--- a/src/plugins/russian/renovels.ts
+++ b/plugins/russian/renovels.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/russian/ruvers.ts b/plugins/russian/ruvers.ts
similarity index 99%
rename from src/plugins/russian/ruvers.ts
rename to plugins/russian/ruvers.ts
index 68e584c..86d2f7d 100644
--- a/src/plugins/russian/ruvers.ts
+++ b/plugins/russian/ruvers.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { defaultCover } from '@libs/defaultCover';
import { fetchApi } from '@libs/fetch';
diff --git a/src/plugins/russian/topliba.ts b/plugins/russian/topliba.ts
similarity index 99%
rename from src/plugins/russian/topliba.ts
rename to plugins/russian/topliba.ts
index 95ce46b..51b60e2 100644
--- a/src/plugins/russian/topliba.ts
+++ b/plugins/russian/topliba.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { load as parseHTML } from 'cheerio';
diff --git a/src/plugins/russian/zelluloza.ts b/plugins/russian/zelluloza.ts
similarity index 99%
rename from src/plugins/russian/zelluloza.ts
rename to plugins/russian/zelluloza.ts
index d42e9a0..ac74d05 100644
--- a/src/plugins/russian/zelluloza.ts
+++ b/plugins/russian/zelluloza.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/spanish/hasutl.ts b/plugins/spanish/hasutl.ts
similarity index 98%
rename from src/plugins/spanish/hasutl.ts
rename to plugins/spanish/hasutl.ts
index d766502..8f6875d 100644
--- a/src/plugins/spanish/hasutl.ts
+++ b/plugins/spanish/hasutl.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class HasulTL implements Plugin.PluginBase {
id = 'HasuTL';
diff --git a/src/plugins/spanish/novelasligera.ts b/plugins/spanish/novelasligera.ts
similarity index 99%
rename from src/plugins/spanish/novelasligera.ts
rename to plugins/spanish/novelasligera.ts
index ee24a39..0292e86 100644
--- a/src/plugins/spanish/novelasligera.ts
+++ b/plugins/spanish/novelasligera.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
class Ligera implements Plugin.PluginBase {
diff --git a/src/plugins/spanish/novelawuxia.ts b/plugins/spanish/novelawuxia.ts
similarity index 99%
rename from src/plugins/spanish/novelawuxia.ts
rename to plugins/spanish/novelawuxia.ts
index b021477..c4150f9 100644
--- a/src/plugins/spanish/novelawuxia.ts
+++ b/plugins/spanish/novelawuxia.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
import { defaultCover } from '@libs/defaultCover';
import { Filters } from '@libs/filterInputs';
diff --git a/src/plugins/spanish/oasistranslations.ts b/plugins/spanish/oasistranslations.ts
similarity index 99%
rename from src/plugins/spanish/oasistranslations.ts
rename to plugins/spanish/oasistranslations.ts
index 9e804a8..9b677c0 100644
--- a/src/plugins/spanish/oasistranslations.ts
+++ b/plugins/spanish/oasistranslations.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
class Oasis implements Plugin.PluginBase {
id = 'oasistranslations';
diff --git a/src/plugins/spanish/skynovels.ts b/plugins/spanish/skynovels.ts
similarity index 99%
rename from src/plugins/spanish/skynovels.ts
rename to plugins/spanish/skynovels.ts
index 48a92bf..ca1dfaa 100644
--- a/src/plugins/spanish/skynovels.ts
+++ b/plugins/spanish/skynovels.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class SkyNovels implements Plugin.PluginBase {
id = 'skynovels';
diff --git a/src/plugins/spanish/tunovelaligera.ts b/plugins/spanish/tunovelaligera.ts
similarity index 99%
rename from src/plugins/spanish/tunovelaligera.ts
rename to plugins/spanish/tunovelaligera.ts
index a4d668f..9f8c8e1 100644
--- a/src/plugins/spanish/tunovelaligera.ts
+++ b/plugins/spanish/tunovelaligera.ts
@@ -1,7 +1,7 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
import { FilterTypes, Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { defaultCover } from '@libs/defaultCover';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/spanish/yukitls.ts b/plugins/spanish/yukitls.ts
similarity index 99%
rename from src/plugins/spanish/yukitls.ts
rename to plugins/spanish/yukitls.ts
index 8b57877..63ab695 100644
--- a/src/plugins/spanish/yukitls.ts
+++ b/plugins/spanish/yukitls.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Filters } from '@libs/filterInputs';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { load as parseHTML } from 'cheerio';
class Yuuki implements Plugin.PluginBase {
diff --git a/src/plugins/thai/.gitkeep b/plugins/thai/.gitkeep
similarity index 100%
rename from src/plugins/thai/.gitkeep
rename to plugins/thai/.gitkeep
diff --git a/src/plugins/turkish/MangaTR.ts b/plugins/turkish/MangaTR.ts
similarity index 99%
rename from src/plugins/turkish/MangaTR.ts
rename to plugins/turkish/MangaTR.ts
index bd98723..1af193c 100644
--- a/src/plugins/turkish/MangaTR.ts
+++ b/plugins/turkish/MangaTR.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';
class MangaTR implements Plugin.PluginBase {
diff --git a/src/plugins/turkish/epiknovel.ts b/plugins/turkish/epiknovel.ts
similarity index 99%
rename from src/plugins/turkish/epiknovel.ts
rename to plugins/turkish/epiknovel.ts
index ba3c430..d230e4d 100644
--- a/src/plugins/turkish/epiknovel.ts
+++ b/plugins/turkish/epiknovel.ts
@@ -1,6 +1,6 @@
import { load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
class EpikNovel implements Plugin.PluginBase {
id = 'epiknovel';
diff --git a/src/plugins/ukrainian/bakainua.ts b/plugins/ukrainian/bakainua.ts
similarity index 96%
rename from src/plugins/ukrainian/bakainua.ts
rename to plugins/ukrainian/bakainua.ts
index b2f2bed..c6833ae 100644
--- a/src/plugins/ukrainian/bakainua.ts
+++ b/plugins/ukrainian/bakainua.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { Filters, FilterTypes } from '@libs/filterInputs';
@@ -20,7 +20,7 @@ class BakaInUa implements Plugin.PluginBase {
): Promise {
const fictionIds: string[] = [];
- let url: URL = new URL(this.site + '/fictions/alphabetical');
+ const url: URL = new URL(this.site + '/fictions/alphabetical');
if (pageNo > 1) url.searchParams.append('page', pageNo.toString());
if (showLatestNovels || (filters && filters.only_new.value))
@@ -100,7 +100,7 @@ class BakaInUa implements Plugin.PluginBase {
break;
}
- let chapters: Plugin.ChapterItem[] = [];
+ const chapters: Plugin.ChapterItem[] = [];
$('li.group a').each((index, elem) => {
const chapter: Plugin.ChapterItem = {
name: $(elem).find('span').eq(1).text().trim(),
@@ -123,7 +123,7 @@ class BakaInUa implements Plugin.PluginBase {
}
async searchNovels(searchTerm: string): Promise {
- let novels: Plugin.NovelItem[] = [];
+ const novels: Plugin.NovelItem[] = [];
const result = await fetchApi(
this.site + '/search?search%5B%5D=' + searchTerm + '&only_fictions=true',
diff --git a/src/plugins/ukrainian/smakolykytl.ts b/plugins/ukrainian/smakolykytl.ts
similarity index 99%
rename from src/plugins/ukrainian/smakolykytl.ts
rename to plugins/ukrainian/smakolykytl.ts
index b8b5696..7f153cb 100644
--- a/src/plugins/ukrainian/smakolykytl.ts
+++ b/plugins/ukrainian/smakolykytl.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
import dayjs from 'dayjs';
diff --git a/src/plugins/ukrainian/uaranobeclub.ts b/plugins/ukrainian/uaranobeclub.ts
similarity index 99%
rename from src/plugins/ukrainian/uaranobeclub.ts
rename to plugins/ukrainian/uaranobeclub.ts
index 0a34af9..df226f9 100644
--- a/src/plugins/ukrainian/uaranobeclub.ts
+++ b/plugins/ukrainian/uaranobeclub.ts
@@ -1,5 +1,5 @@
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
const UA_RANOBE_ID = 'uaranobeclub' as const;
const UA_RANOBE_URL = 'https://uaranobe.club/' as const;
diff --git a/src/plugins/vietnamese/LNHako.ts b/plugins/vietnamese/LNHako.ts
similarity index 99%
rename from src/plugins/vietnamese/LNHako.ts
rename to plugins/vietnamese/LNHako.ts
index 5aeabbd..042bdcf 100644
--- a/src/plugins/vietnamese/LNHako.ts
+++ b/plugins/vietnamese/LNHako.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { Parser } from 'htmlparser2';
-import { HTMLParser2Util, Plugin } from '@typings/plugin';
+import { HTMLParser2Util, Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { FilterTypes, Filters } from '@libs/filterInputs';
diff --git a/src/plugins/vietnamese/Truyenconect.ts b/plugins/vietnamese/Truyenconect.ts
similarity index 99%
rename from src/plugins/vietnamese/Truyenconect.ts
rename to plugins/vietnamese/Truyenconect.ts
index 540a901..815ad2a 100644
--- a/src/plugins/vietnamese/Truyenconect.ts
+++ b/plugins/vietnamese/Truyenconect.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { FilterTypes, Filters } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/vietnamese/lightnovelvn.ts b/plugins/vietnamese/lightnovelvn.ts
similarity index 99%
rename from src/plugins/vietnamese/lightnovelvn.ts
rename to plugins/vietnamese/lightnovelvn.ts
index 3326dff..37a4d07 100644
--- a/src/plugins/vietnamese/lightnovelvn.ts
+++ b/plugins/vietnamese/lightnovelvn.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { Filters } from '@libs/filterInputs';
import { NovelStatus } from '@libs/novelStatus';
diff --git a/src/plugins/vietnamese/nettruyen.ts b/plugins/vietnamese/nettruyen.ts
similarity index 98%
rename from src/plugins/vietnamese/nettruyen.ts
rename to plugins/vietnamese/nettruyen.ts
index 401fe19..004309a 100644
--- a/src/plugins/vietnamese/nettruyen.ts
+++ b/plugins/vietnamese/nettruyen.ts
@@ -1,6 +1,6 @@
import { fetchApi } from '@libs/fetch';
import { NovelStatus } from '@libs/novelStatus';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { CheerioAPI, load as parseHTML } from 'cheerio';
class Nettruyen implements Plugin.PagePlugin {
diff --git a/src/plugins/vietnamese/truyenchu.ts b/plugins/vietnamese/truyenchu.ts
similarity index 99%
rename from src/plugins/vietnamese/truyenchu.ts
rename to plugins/vietnamese/truyenchu.ts
index 4f75ea9..65851de 100644
--- a/src/plugins/vietnamese/truyenchu.ts
+++ b/plugins/vietnamese/truyenchu.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
class TruyenFull implements Plugin.PagePlugin {
diff --git a/src/plugins/vietnamese/truyenfull.ts b/plugins/vietnamese/truyenfull.ts
similarity index 99%
rename from src/plugins/vietnamese/truyenfull.ts
rename to plugins/vietnamese/truyenfull.ts
index dba9a6a..0c88c5a 100644
--- a/src/plugins/vietnamese/truyenfull.ts
+++ b/plugins/vietnamese/truyenfull.ts
@@ -1,6 +1,6 @@
import { CheerioAPI, load as parseHTML } from 'cheerio';
import { fetchApi } from '@libs/fetch';
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { NovelStatus } from '@libs/novelStatus';
import { FilterTypes, Filters } from '@libs/filterInputs';
diff --git a/proxy.ts b/proxy.ts
index eea5e97..db93a11 100644
--- a/proxy.ts
+++ b/proxy.ts
@@ -193,7 +193,7 @@ const proxyRequest: Connect.SimpleHandleFunction = (req, res) => {
};
proxy.on('proxyRes', function (proxyRes, req, res) {
- var statusCode = proxyRes.statusCode;
+ const statusCode = proxyRes.statusCode;
// Redirect
if (
statusCode === 301 ||
diff --git a/public/ico.png b/public/ico.png
deleted file mode 100644
index d2f483c..0000000
Binary files a/public/ico.png and /dev/null differ
diff --git a/public/icon.svg b/public/icon.svg
new file mode 100644
index 0000000..c9614f9
--- /dev/null
+++ b/public/icon.svg
@@ -0,0 +1,15 @@
+
+
+
+ 読
+
+
diff --git a/scripts/build-plugin-manifest.js b/scripts/build-plugin-manifest.js
index a19ecbb..35d2dd2 100644
--- a/scripts/build-plugin-manifest.js
+++ b/scripts/build-plugin-manifest.js
@@ -19,7 +19,7 @@ const USER_CONTENT_LINK = process.env.USER_CONTENT_BASE
: `https://raw.githubusercontent.com/${USERNAME}/${REPO}/${CURRENT_BRANCH}`;
const STATIC_LINK = `${USER_CONTENT_LINK}/public/static`;
-const PLUGIN_LINK = `${USER_CONTENT_LINK}/.js/src/plugins`;
+const PLUGIN_LINK = `${USER_CONTENT_LINK}/.js/plugins`;
const DIST_DIR = '.dist';
@@ -83,7 +83,7 @@ const proxy = createRecursiveProxy();
const _require = () => proxy;
-const COMPILED_PLUGIN_DIR = './.js/src/plugins';
+const COMPILED_PLUGIN_DIR = './.js/plugins';
for (let language in languages) {
console.log(
@@ -204,7 +204,7 @@ if (!ONLY_NEW)
// check for broken plugins
for (let language in languages) {
const tsFiles = fs.readdirSync(
- path.join('./src/plugins', language.toLocaleLowerCase()),
+ path.join('./plugins', language.toLocaleLowerCase()),
);
tsFiles
.filter(f => f.endsWith('.broken.ts'))
diff --git a/scripts/generate-plugin-index.js b/scripts/generate-plugin-index.js
index 4e2a5ae..7f19c22 100644
--- a/scripts/generate-plugin-index.js
+++ b/scripts/generate-plugin-index.js
@@ -1,18 +1,18 @@
import fs from 'fs';
import { execSync } from 'child_process';
-let content = `import { Plugin } from '@typings/plugin';\n`;
+let content = `import { Plugin } from '@/types/plugin';\n`;
let pluginCounter = 0;
-const PLUGIN_DIR = 'src/plugins';
+const PLUGIN_DIR = 'plugins';
fs.readdirSync(PLUGIN_DIR)
- .filter(f => !f.includes('index'))
+ .filter(f => !f.includes('index') && f !== 'multisrc')
.forEach(langName => {
const LANG_DIR = PLUGIN_DIR + '/' + langName;
fs.readdirSync(LANG_DIR)
.filter(f => !f.includes('broken') && !f.startsWith('.'))
.forEach(pluginName => {
- content += `import p_${pluginCounter} from './${langName}/${pluginName.replace(/\.ts$/, '')}';\n`;
+ content += `import p_${pluginCounter} from '@plugins/${langName}/${pluginName.replace(/\.ts$/, '')}';\n`;
pluginCounter += 1;
});
});
@@ -22,7 +22,7 @@ content += `\nconst PLUGINS: Plugin.PluginBase[] = [${Array(pluginCounter)
.map((v, index) => 'p_' + index.toString())
.join(', ')}];\nexport default PLUGINS`;
-const outputPath = './src/plugins/index.ts';
+const outputPath = './plugins/index.ts';
fs.writeFileSync(outputPath, content, { encoding: 'utf-8' });
execSync(`npx prettier --write ${outputPath}`, { stdio: 'inherit' });
diff --git a/scripts/publish-plugins.ps1 b/scripts/publish-plugins.ps1
index 846dc49..18a80fd 100644
--- a/scripts/publish-plugins.ps1
+++ b/scripts/publish-plugins.ps1
@@ -29,7 +29,7 @@ if (-not (Test-Path .dist) -or -not (Get-ChildItem -Path .dist -Force)) {
exit 1
}
-git add -f public/static .dist .js/src/plugins total.svg
+git add -f public/static .dist .js/plugins total.svg
git commit -m "chore: Publish Plugins"
git push -f origin $dist
diff --git a/scripts/publish-plugins.sh b/scripts/publish-plugins.sh
index de555ef..e5721a1 100755
--- a/scripts/publish-plugins.sh
+++ b/scripts/publish-plugins.sh
@@ -8,17 +8,20 @@ current=`git rev-parse --abbrev-ref HEAD`
version=`node -e "console.log(require('./package.json').version);"`
dist="plugins/v$version"
+echo "Publishing plugins: $current -> $dist (v$version)"
+
if [[ "$1" == "--all-branches" ]]; then
rm -rf .dist .js
git fetch --all
branches=$(git branch -r | grep -v '\->')
for branch in $branches; do
- # Check if the branch has the same version of publish-plugins.sh as the current branch
+ # Skip branches with different publish-plugins.sh version
if ! diff scripts/publish-plugins.sh <(git show "$branch:scripts/publish-plugins.sh") >/dev/null; then
- echo "Branch $branch does not have the current version of publish-plugins.sh. Skipping."
+ echo "⚠️ Skipping $branch (script version mismatch)"
continue
fi
echo "::group::Branch $branch"
+ echo "Processing: $branch"
git stash push -a -- .dist .js
git checkout -f $branch
exists=`git show-ref refs/heads/$dist`
@@ -28,30 +31,36 @@ if [[ "$1" == "--all-branches" ]]; then
git stash pop
npm run clean:multisrc
npm run build:multisrc
+ echo "Compiling TypeScript..."
npx tsc --project tsconfig.production.json
echo "# $branch" >> $GITHUB_STEP_SUMMARY
npm run build:manifest -- --only-new 2>> $GITHUB_STEP_SUMMARY
if [ ! -d ".dist" ] || [ -z "$(ls -A .dist)" ]; then
- echo "=========="
- echo "JSON files were not generated! See the error above and fix it!"
+ echo "❌ ERROR: Manifest generation failed - .dist is missing or empty"
+ exit 1
fi
+ echo "✅ Done: $branch"
echo "::endgroup::"
done
echo
echo "::group::Publish All Branches"
+ echo "Publishing combined plugins..."
git checkout --orphan $dist
if [ $? -eq 1 ]; then
- # If checkout failed
- echo "=========="
- echo "Could not checkout branch dist! See the error above and fix it!"
+ echo "❌ ERROR: Failed to create branch $dist"
echo "::endgroup::"
exit 1
fi
git reset
- git add -f public/static .dist .js/src/plugins total.svg
+ # Copy plugins to legacy path (.js/src/plugins) for backward compatibility
+ echo "Copying .js/plugins -> .js/src/plugins (backward compatibility)"
+ mkdir -p .js/src
+ cp -r .js/plugins .js/src/plugins
+ git add -f public/static .dist .js/plugins .js/src/plugins total.svg
git commit -m "chore: Publish Plugins From All Branches"
git push -f origin $dist
git checkout -f $branch
+ echo "✅ Published all branches to $dist"
echo "::endgroup::"
exit 0
fi
@@ -65,9 +74,7 @@ fi
git checkout --orphan $dist 2>&1
if [ $? -eq 1 ]; then
- # If checkout failed
- echo "=========="
- echo "Could not checkout branch dist! See the error above and fix it!"
+ echo "❌ ERROR: Failed to create branch $dist"
exit 1
fi
@@ -75,17 +82,22 @@ git reset
rm -rf .js
npm run clean:multisrc
npm run build:multisrc
+echo "Compiling TypeScript..."
npx tsc --project tsconfig.production.json
npm run build:manifest
if [ ! -d ".dist" ] || [ -z "$(ls -A .dist)" ]; then
- echo "=========="
- echo "JSON files were not generated! See the error above and fix it!"
+ echo "❌ ERROR: Manifest generation failed - .dist is missing or empty"
exit 1
fi
-git add -f public/static .dist .js/src/plugins total.svg
+# Copy plugins to legacy path (.js/src/plugins) for backward compatibility
+echo "Copying .js/plugins -> .js/src/plugins (backward compatibility)"
+mkdir -p .js/src
+cp -r .js/plugins .js/src/plugins
+git add -f public/static .dist .js/plugins .js/src/plugins total.svg
git commit -m "chore: Publish Plugins"
git push -f origin $dist 2>&1
git checkout -f $current 2>&1
+echo "✅ Published to $dist"
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index 503364d..0000000
--- a/src/App.css
+++ /dev/null
@@ -1,46 +0,0 @@
-#root {
- margin: 0 auto;
- text-align: center;
- width: 100vw;
- padding-bottom: 40px;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
-
-button:focus {
- outline: none !important;
-}
diff --git a/src/App.tsx b/src/App.tsx
index 08d05f4..68a0634 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,53 +1,16 @@
import React from 'react';
-import './App.css';
-import {
- Container,
- createTheme,
- CssBaseline,
- StyledEngineProvider,
- ThemeProvider,
-} from '@mui/material';
-import Appbar from '@components/Appbar';
-import AppProvider from './provider';
-import PopularNovels from '@components/accordions/PopularNovels';
-import SearchNovels from '@components/accordions/SearchNovels';
-import ParseNovel from '@components/accordions/ParseNovel';
-import ParseChapter from '@components/accordions/ParseChapter';
-import HeadersSection from '@components/accordions/Headers';
+import { Toaster } from '@/components/ui/sonner';
+import Home from './pages/home';
+import { TooltipProvider } from './components/ui/tooltip';
function App() {
- const theme = createTheme({
- components: {
- // Name of the component
- MuiButtonBase: {
- defaultProps: {
- // The props to change the default for.
- disableRipple: true, // No more ripple, on the whole application 💣!
- },
- },
- },
- });
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
);
}
diff --git a/src/components/Appbar/index.tsx b/src/components/Appbar/index.tsx
deleted file mode 100644
index 1b9bea2..0000000
--- a/src/components/Appbar/index.tsx
+++ /dev/null
@@ -1,161 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import AppBar from '@mui/material/AppBar';
-import Box from '@mui/material/Box';
-import Toolbar from '@mui/material/Toolbar';
-import {
- Avatar,
- Backdrop,
- FormControl,
- InputAdornment,
- Link,
- ListItem,
- ListItemAvatar,
- ListItemButton,
- ListItemText,
- TextField,
- Typography,
-} from '@mui/material';
-import { Search } from '@mui/icons-material';
-import { searchPlugins } from '@provider/plugins';
-import { Plugin } from '@typings/plugin';
-import { FixedSizeList, ListChildComponentProps } from 'react-window';
-import { useAppStore } from '@store';
-
-const resovleIcon = (iconPath: string) => {
- return '/static/' + iconPath;
-};
-
-function renderPlugin(setListVisible: (v: boolean) => void) {
- return function (props: ListChildComponentProps) {
- const { index, style, data } = props;
- const plugin = data[index];
- const { selectPlugin, pluginItem } = useAppStore(state => state);
-
- return (
-
- {
- selectPlugin({
- id: plugin.id,
- name: plugin.name,
- version: plugin.version,
- icon: plugin.icon,
- site: plugin.site,
- });
- setListVisible(false);
- }}
- >
-
-
-
-
-
-
- );
- };
-}
-
-export default function Appbar() {
- const [searchedPlugins, setSearchPlugins] = useState([]);
- const [keyword, setKeyword] = useState('');
- const [listVisible, setListVisible] = useState(false);
-
- const plugin = useAppStore(state => state.plugin);
-
- useEffect(() => {
- const plugins = searchPlugins(keyword);
- setSearchPlugins(plugins);
- }, [keyword]);
-
- return (
-
-
-
- setKeyword(e.target.value)}
- InputProps={{
- startAdornment: (
-
-
-
- ),
- }}
- fullWidth
- autoComplete="off"
- onFocus={() => {
- setListVisible(true);
- if (searchedPlugins.length === 0)
- setSearchPlugins(searchPlugins(keyword));
- }}
- />
- {listVisible ? (
-
- {renderPlugin(setListVisible)}
-
- ) : null}
-
- setListVisible(false)}
- sx={{ zIndex: 9 }}
- invisible={true}
- />
- {plugin ? (
-
-
-
- {plugin.name} - v{plugin.version}
-
-
- ) : null}
-
-
- );
-}
diff --git a/src/components/CopiableItem.tsx b/src/components/CopiableItem.tsx
deleted file mode 100644
index 2bd45c9..0000000
--- a/src/components/CopiableItem.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import React, { ReactNode, useEffect, useState } from 'react';
-import Alert from '@mui/material/Alert';
-
-export default function CopiableItem({
- content,
- children,
-}: {
- content?: string;
- children: ReactNode;
-}) {
- const [alertVisible, setAlertVisble] = useState(false);
- useEffect(() => {
- if (alertVisible) {
- setTimeout(() => setAlertVisble(false), 1000);
- }
- }, [alertVisible]);
- return (
- {
- if (content) {
- navigator.clipboard.writeText(content).then(() => {
- setAlertVisble(true);
- });
- }
- }}
- >
- {alertVisible ? (
-
theme.zIndex.tooltip + 1,
- }}
- severity="success"
- >
- Copied
-
- ) : null}
- {children}
-
- );
-}
diff --git a/src/components/PathItem.tsx b/src/components/PathItem.tsx
deleted file mode 100644
index da5aa88..0000000
--- a/src/components/PathItem.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import { Box, Button, Tooltip } from '@mui/material';
-import { createTheme, ThemeProvider } from '@mui/material/styles';
-import React from 'react';
-import CopiableItem from './CopiableItem';
-
-type Validation = {
- type?: 'error' | 'warning';
- message?: string;
-};
-
-const validatePath = (path: string): Validation => {
- if (path.includes('http'))
- return {
- type: 'error',
- message: 'Path must be relative, please remove the domain',
- };
- if (/^\/|\/$/.test(path)) {
- return {
- type: 'warning',
- message: 'your path should not contain leading or trailing "/"',
- };
- }
- return {};
-};
-
-export default function PathItem({ path }: { path: string }) {
- const validation = validatePath(path);
- const errorTheme = createTheme({
- components: {
- MuiTooltip: {
- styleOverrides: {
- tooltip: {
- color: '#FFF',
- backgroundColor: '#BA000D',
- },
- },
- },
- },
- });
- const warningTheme = createTheme({
- components: {
- MuiTooltip: {
- styleOverrides: {
- tooltip: {
- color: '#FFF',
- backgroundColor: 'orange',
- },
- },
- },
- },
- });
- const ValidateWrapper = validation.type ? Tooltip : Box;
- return (
-
-
-
-
-
-
-
- Path
-
-
-
-
-
-
-
- );
-}
diff --git a/src/components/StyledSwitch.tsx b/src/components/StyledSwitch.tsx
deleted file mode 100644
index 2611e0f..0000000
--- a/src/components/StyledSwitch.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { styled, Switch } from '@mui/material';
-
-export const StyledSwitch = styled(Switch)(() => ({
- padding: 8,
- '& .MuiSwitch-track': {
- borderRadius: 22 / 2,
- },
- '& .MuiSwitch-thumb': {
- boxShadow: 'none',
- width: 16,
- height: 16,
- margin: 2,
- },
-}));
diff --git a/src/components/Textarea.tsx b/src/components/Textarea.tsx
deleted file mode 100644
index f42dee5..0000000
--- a/src/components/Textarea.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { styled, TextareaAutosize } from '@mui/material';
-
-const blue = {
- 100: '#DAECFF',
- 200: '#b6daff',
- 400: '#3399FF',
- 500: '#007FFF',
- 600: '#0072E5',
- 900: '#003A75',
-};
-
-const grey = {
- 50: '#F3F6F9',
- 100: '#E5EAF2',
- 200: '#DAE2ED',
- 300: '#C7D0DD',
- 400: '#B0B8C4',
- 500: '#9DA8B7',
- 600: '#6B7A90',
- 700: '#434D5B',
- 800: '#303740',
- 900: '#1C2025',
-};
-
-const Textarea = styled(TextareaAutosize)(
- ({ theme }) => `
- box-sizing: border-box;
- width: 320px;
- font-family: 'IBM Plex Sans', sans-serif;
- font-size: 0.875rem;
- font-weight: 400;
- line-height: 1.5;
- padding: 8px 12px;
- border-radius: 8px;
- color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
- background: ${theme.palette.mode === 'dark' ? grey[900] : '#fff'};
- border: 1px solid ${theme.palette.mode === 'dark' ? grey[700] : grey[200]};
- box-shadow: 0px 2px 2px ${theme.palette.mode === 'dark' ? grey[900] : grey[50]};
-
- &:hover {
- border-color: ${blue[400]};
- }
-
- &:focus {
- border-color: ${blue[400]};
- box-shadow: 0 0 0 3px ${theme.palette.mode === 'dark' ? blue[600] : blue[200]};
- }
-
- // firefox
- &:focus-visible {
- outline: 0;
- }
- `,
-);
-
-export default Textarea;
diff --git a/src/components/accordions/Headers/index.tsx b/src/components/accordions/Headers/index.tsx
deleted file mode 100644
index eecb149..0000000
--- a/src/components/accordions/Headers/index.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import AccordionContainer from '../components/AccordionContainer';
-import {
- Alert,
- Box,
- InputAdornment,
- MenuItem,
- Select,
- TextField,
- Tooltip,
-} from '@mui/material';
-import Checkbox from '@mui/material/Checkbox';
-import useDebounce from '@hooks/useDebounce';
-import { FetchMode } from '@typings/types';
-
-export default function HeadersSection() {
- const [loading, setLoading] = useState(false);
- const [cookies, setCookies] = useState('');
- const debounceCookies = useDebounce(cookies, 500);
- const [fetchMode, setFetchMode] = useState(FetchMode.PROXY);
- const [alertVisible, setAlertVisble] = useState(false);
- const [useUserAgent, setUseUserAgent] = useState(true);
- useEffect(() => {
- if (alertVisible) {
- const id = setTimeout(() => setAlertVisble(false), 1000);
- return () => clearTimeout(id);
- }
- }, [alertVisible]);
-
- useEffect(() => {
- setLoading(true);
- fetch('settings', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- cookies: debounceCookies,
- fetchMode: fetchMode,
- useUserAgent,
- }),
- })
- .then(() => setAlertVisble(true))
- .finally(() => setLoading(false));
- }, [debounceCookies, fetchMode, useUserAgent]);
-
- return (
-
- {alertVisible ? (
-
- Settings updated
-
- ) : null}
-
-
- User Agent
- ),
- },
- }}
- disabled
- value={navigator.userAgent}
- sx={{ width: '100%' }}
- />
-
- setUseUserAgent(e.target.checked)}
- />
-
-
- Cookies
- ),
- },
- }}
- value={cookies}
- onChange={e => {
- setCookies(e.target.value.trim());
- }}
- sx={{ width: '100%' }}
- />
-
-
- Fetch Mode:
- setFetchMode(e.target.value as FetchMode)}
- >
- Proxy
- Node fetch
- Curl
-
-
-
- );
-}
diff --git a/src/components/accordions/ParseChapter/index.tsx b/src/components/accordions/ParseChapter/index.tsx
deleted file mode 100644
index 7ce0bc9..0000000
--- a/src/components/accordions/ParseChapter/index.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { Box, Button, Stack, TextField } from '@mui/material';
-import React, { useState } from 'react';
-import AccordionContainer from '../components/AccordionContainer';
-import Textarea from '@components/Textarea';
-import { useAppStore } from '@store';
-export default function ParseChapter() {
- const plugin = useAppStore(state => state.plugin);
- const [loading, setLoading] = useState(false);
- const [chapterPath, setchapterPath] = useState('');
- const [chapterText, setChapterText] = useState('');
- const fetchChapter = () => {
- if (plugin) {
- setLoading(true);
- plugin
- .parseChapter(chapterPath)
- .then(res => setChapterText(res))
- .finally(() => setLoading(false));
- }
- };
- return (
-
-
- setchapterPath(e.target.value)}
- size="small"
- label="Chapter path"
- />
-
- Fetch
-
-
-
- {chapterText ? (
-
- ) : null}
-
- );
-}
diff --git a/src/components/accordions/ParseNovel/ChaptertList.tsx b/src/components/accordions/ParseNovel/ChaptertList.tsx
deleted file mode 100644
index 2253c0d..0000000
--- a/src/components/accordions/ParseNovel/ChaptertList.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import PathItem from '@components/PathItem';
-import {
- Paper,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableHead,
- TableRow,
-} from '@mui/material';
-import { Plugin } from '@typings/plugin';
-import dayjs from 'dayjs';
-import React from 'react';
-import { TableComponents, TableVirtuoso } from 'react-virtuoso';
-
-const VirtuosoTableComponents: TableComponents = {
- Scroller: React.forwardRef((props, ref) => (
-
- )),
- Table: props => (
-
- ),
- // @ts-ignore
- TableHead,
- TableRow: ({ item: _item, ...props }) => ,
- TableBody: React.forwardRef((props, ref) => (
-
- )),
-};
-
-function fixedHeaderContent() {
- return (
-
- Index
- Name
- Path
- Release Time
- Number
-
- );
-}
-
-function rowContent(_index: number, row: Plugin.ChapterItem) {
- return (
-
- {_index}
- {row.name}
-
-
-
- {dayjs(row.releaseTime).format('YYYY/MM/DD')}
- {row.chapterNumber}
-
- );
-}
-export default function ChapterList({
- chapters,
-}: {
- chapters: Plugin.ChapterItem[];
-}) {
- return (
-
-
-
- );
-}
diff --git a/src/components/accordions/ParseNovel/SourceNovelCard.tsx b/src/components/accordions/ParseNovel/SourceNovelCard.tsx
deleted file mode 100644
index 1821aa5..0000000
--- a/src/components/accordions/ParseNovel/SourceNovelCard.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-import React, { ReactNode } from 'react';
-import { Plugin } from '@typings/plugin';
-import {
- Box,
- Button,
- Card,
- CardContent,
- CardMedia,
- Chip,
- ListItem,
- Stack,
- Tooltip,
- Typography,
- useTheme,
-} from '@mui/material';
-import CopiableItem from '@components/CopiableItem';
-import PathItem from '@components/PathItem';
-
-const FlexRow = ({ children }: { children: ReactNode }) => (
-
- {children}
-
-);
-
-export default function SourceNovelCard({
- sourceNovel,
-}: {
- sourceNovel: Plugin.SourceNovel;
-}) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {sourceNovel.name}
-
-
-
-
-
-
-
-
- Status:
-
-
-
- Author:
-
-
-
- Artist:
-
-
-
-
-
-
-
-
-
- Genres
-
-
- {sourceNovel.genres?.split(/,\s*/).map((genre, index) => (
-
-
-
- ))}
-
-
-
-
- Summary
-
- {sourceNovel.summary}
-
-
-
-
- );
-}
diff --git a/src/components/accordions/ParseNovel/index.tsx b/src/components/accordions/ParseNovel/index.tsx
deleted file mode 100644
index 9526488..0000000
--- a/src/components/accordions/ParseNovel/index.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-import { Box, Button, Pagination, Stack, TextField } from '@mui/material';
-import React, { useState } from 'react';
-import AccordionContainer from '../components/AccordionContainer';
-import { Plugin } from '@typings/plugin';
-import SourceNovelCard from './SourceNovelCard';
-import ChapterList from './ChaptertList';
-import { useAppStore } from '@store';
-
-export default function ParseNovel() {
- const plugin = useAppStore(state => state.plugin);
- const [sourceNovel, setSouceNovel] = useState<
- (Plugin.SourceNovel & { totalPages?: number }) | undefined
- >();
- const [chapters, setChapters] = useState([]);
- const [loading, setLoading] = useState(false);
- const [novelPath, setNovelPath] = useState('');
- const fetchNovel = () => {
- if (plugin) {
- setLoading(true);
- plugin
- .parseNovel(novelPath)
- .then(res => {
- setSouceNovel(res);
- setChapters(res.chapters || []);
- })
- .finally(() => setLoading(false));
- }
- };
- const fetchPage = (page: number) => {
- if (plugin && page) {
- setLoading(true);
- (plugin as Plugin.PagePlugin)
- .parsePage(novelPath, page.toString())
- .then(res => setChapters(res.chapters))
- .finally(() => setLoading(false));
- }
- };
- return (
-
-
-
- setNovelPath(e.target.value)}
- size="small"
- label="Novel path"
- />
-
- Fetch
-
-
- {sourceNovel ? : null}
-
- {chapters.length ? : null}
-
- {sourceNovel?.totalPages ? (
- fetchPage(page)}
- variant="outlined"
- />
- ) : null}
-
-
- );
-}
diff --git a/src/components/accordions/PopularNovels/index.css b/src/components/accordions/PopularNovels/index.css
deleted file mode 100644
index 9aab880..0000000
--- a/src/components/accordions/PopularNovels/index.css
+++ /dev/null
@@ -1,11 +0,0 @@
-#filtersContent {
- display: flex;
- flex-direction: column;
- align-content: center;
-}
-
-.switch_filter {
- display: flex;
- flex-direction: column;
- align-items: center;
-}
diff --git a/src/components/accordions/PopularNovels/index.tsx b/src/components/accordions/PopularNovels/index.tsx
deleted file mode 100644
index 3f6d240..0000000
--- a/src/components/accordions/PopularNovels/index.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import {
- Box,
- Button,
- Stack,
- ToggleButton,
- ToggleButtonGroup,
- Switch,
- FormControlLabel,
- FormGroup,
-} from '@mui/material';
-import React, { useEffect, useState, ChangeEvent, useRef } from 'react';
-import AccordionContainer from '../components/AccordionContainer';
-import { Plugin } from '@typings/plugin';
-import NovelItemCard from '../components/NovelItemCard';
-import { Filters, FilterToValues } from '@libs/filterInputs';
-import { useAppStore } from '@store';
-import './index.css';
-import { DialogRef, FiltersDialog } from '../components/filters/FiltersDialog';
-
-export default function PopularNovels() {
- const plugin = useAppStore(state => state.plugin);
- const [novels, setNovels] = useState([]);
- const [filterValues, setFilterValues] = useState<
- FilterToValues | undefined
- >();
- const [loading, setLoading] = useState(false);
- const [currentIndex, setCurrentIndex] = useState(0);
- const [maxIndex, setMaxIndex] = useState(0);
- const [isLatest, setIsLatest] = useState(true);
- const dialogRef = useRef(null);
-
- const fetchNovelsByIndex = async (index: number) => {
- if (plugin && index) {
- setLoading(true);
- const novels = await plugin.popularNovels(index, {
- filters: filterValues || {},
- showLatestNovels: isLatest,
- });
- if (novels.length !== 0) {
- setCurrentIndex(index);
- if (index > maxIndex) {
- setMaxIndex(index);
- }
- setNovels(novels);
- }
- setLoading(false);
- }
- };
-
- const handleSwitchLatestChange = (event: ChangeEvent) => {
- setIsLatest(event.target.checked);
- };
-
- useEffect(() => {
- if (plugin) {
- setCurrentIndex(1);
- setMaxIndex(1);
- fetchNovelsByIndex(1);
- }
- }, [isLatest]);
-
- useEffect(() => {
- // Reset when changing plugins.
- // TODO: Fix crashing on plugin change!
- setCurrentIndex(0);
- setMaxIndex(0);
- setNovels([]);
-
- if (plugin?.filters) {
- const filters: FilterToValues = {};
- for (const fKey in plugin.filters) {
- filters[fKey as keyof typeof filters] = {
- type: plugin.filters[fKey].type,
- value: plugin.filters[fKey].value,
- };
- }
- setFilterValues(filters);
- }
- }, [plugin]);
-
- return (
-
-
-
-
- }
- label={{isLatest ? 'Latest' : 'Popular'} }
- />
-
- fetchNovelsByIndex(1)}
- variant="contained"
- >
- Fetch
-
- fetchNovelsByIndex(currentIndex + 1)}
- >
- Next Page
-
- {
- dialogRef.current?.show();
- }}
- >
- Filters
-
- fetchNovelsByIndex(1)}
- />
- fetchNovelsByIndex(value)}
- >
- {Array.from({ length: maxIndex }, (_, index) => index + 1).map(
- number => (
-
- {number}
-
- ),
- )}
-
-
-
- {novels.map((novel, index) => (
-
- ))}
-
-
- );
-}
diff --git a/src/components/accordions/SearchNovels/index.tsx b/src/components/accordions/SearchNovels/index.tsx
deleted file mode 100644
index decdf43..0000000
--- a/src/components/accordions/SearchNovels/index.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Box, Button, Stack, TextField } from '@mui/material';
-import React, { useEffect, useState } from 'react';
-import AccordionContainer from '../components/AccordionContainer';
-import { Plugin } from '@typings/plugin';
-import NovelItemCard from '../components/NovelItemCard';
-import { useAppStore } from '@store';
-
-export default function SearchNovels() {
- const plugin = useAppStore(state => state.plugin);
-
- const [searchTerm, setSearchTerm] = useState('');
- const [currentPage, setCurrentPage] = useState(1);
- const [novels, setNovels] = useState([]);
- const [loading, setLoading] = useState(false);
-
- const [fetchError, setFetchError] = useState('');
-
- const fetchNovels = (page: number) => {
- if (plugin) {
- setLoading(true);
- plugin
- .searchNovels(searchTerm, page)
- .then(res => setNovels(res))
- .finally(() => setLoading(false))
- .catch(e => {
- setFetchError(e.message);
- });
- }
- };
-
- useEffect(() => {
- setCurrentPage(1);
- }, [plugin]);
-
- return (
-
- {fetchError && {fetchError} }
-
- setSearchTerm(e.target.value)}
- size="small"
- label="Search term"
- />
- fetchNovels(currentPage)}
- variant="contained"
- >
- Fetch
-
- {
- fetchNovels(currentPage + 1);
- setCurrentPage(pre => pre + 1);
- }}
- >
- Next Page
-
-
-
-
- {novels?.map((novel, index) => (
-
- ))}
-
-
-
- );
-}
diff --git a/src/components/accordions/components/AccordionContainer.tsx b/src/components/accordions/components/AccordionContainer.tsx
deleted file mode 100644
index fd20978..0000000
--- a/src/components/accordions/components/AccordionContainer.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import {
- Accordion,
- AccordionDetails,
- AccordionSummary,
- Box,
- LinearProgress,
- Typography,
-} from '@mui/material';
-import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
-import React, { ReactNode } from 'react';
-
-export default function AccordionContainer({
- children,
- title,
- loading,
-}: {
- title: string;
- loading?: boolean;
- children: ReactNode;
-}) {
- return (
-
- }>
- {title}
-
- {loading ? (
-
-
-
- ) : null}
-
- {children}
-
-
- );
-}
diff --git a/src/components/accordions/components/NovelItemCard.tsx b/src/components/accordions/components/NovelItemCard.tsx
deleted file mode 100644
index 2da0992..0000000
--- a/src/components/accordions/components/NovelItemCard.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import {
- Box,
- Button,
- Card,
- CardContent,
- CardMedia,
- Tooltip,
- Typography,
-} from '@mui/material';
-import React from 'react';
-import { Plugin } from '@typings/plugin';
-import CopiableItem from '@components/CopiableItem';
-import PathItem from '@components/PathItem';
-export default function NovelItemCard({ item }: { item: Plugin.NovelItem }) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- {item.name}
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/src/components/accordions/components/filters/CheckboxFilter.tsx b/src/components/accordions/components/filters/CheckboxFilter.tsx
deleted file mode 100644
index 44ce44b..0000000
--- a/src/components/accordions/components/filters/CheckboxFilter.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import { Filter, FilterTypes, ValueOfFilter } from '@libs/filterInputs';
-import {
- Checkbox,
- FormControl,
- FormControlLabel,
- FormLabel,
- Grid,
-} from '@mui/material';
-
-type FilterType = FilterTypes.CheckboxGroup;
-
-export const CheckboxFilter = ({
- filter: { key, filter },
- value,
- set,
-}: {
- filter: { key: string; filter: Filter };
- value: ValueOfFilter;
- set: (v: typeof value) => void;
-}) => {
- const label = filter.label.replace(/s+/gi, '-');
- return (
-
- {filter.label}
-
- {filter.options.map(option => {
- return (
-
-
- {
- set(
- value.includes(option.value)
- ? value.filter(q => q !== option.value)
- : [...value, option.value],
- );
- }}
- checked={value.includes(option.value)}
- />
- }
- label={option.label}
- />
-
-
- );
- })}
-
-
- );
-};
diff --git a/src/components/accordions/components/filters/PickerFilter.tsx b/src/components/accordions/components/filters/PickerFilter.tsx
deleted file mode 100644
index 23e18db..0000000
--- a/src/components/accordions/components/filters/PickerFilter.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import React from 'react';
-import { Filter, FilterTypes, ValueOfFilter } from '@libs/filterInputs';
-import { FormControl, InputLabel, MenuItem, Select } from '@mui/material';
-
-type FilterType = FilterTypes.Picker;
-
-export const PickerFilter = ({
- filter: { key, filter },
- value,
- set,
-}: {
- filter: { key: string; filter: Filter };
- value: ValueOfFilter;
- set: (v: ValueOfFilter) => void;
-}) => {
- const label = filter.label.replace(/s+/gi, '-');
- return (
-
-
- {filter.label}
-
- {
- if (newValue === key) newValue = '';
- set(newValue);
- }}
- MenuProps={{ slotProps: { paper: { sx: { maxHeight: 36 * 4 } } } }}
- label={filter.label}
- >
- {filter.options.map(option => {
- return (
-
- {option.label}
-
- );
- })}
-
-
- );
-};
diff --git a/src/components/accordions/components/filters/SwitchFilter.tsx b/src/components/accordions/components/filters/SwitchFilter.tsx
deleted file mode 100644
index 2f0c859..0000000
--- a/src/components/accordions/components/filters/SwitchFilter.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import { Filter, FilterTypes, ValueOfFilter } from '@libs/filterInputs';
-import { FormControl, FormControlLabel } from '@mui/material';
-import { StyledSwitch } from '../../../StyledSwitch';
-
-type FilterType = FilterTypes.Switch;
-
-export const SwitchFilter = ({
- filter: { key, filter },
- value,
- set,
-}: {
- filter: { key: string; filter: Filter };
- value: ValueOfFilter;
- set: (v: typeof value) => void;
-}) => {
- const label = filter.label.replace(/s+/gi, '-');
- return (
-
- set(!value)} />}
- />
-
- );
-};
diff --git a/src/components/accordions/components/filters/TextFilter.tsx b/src/components/accordions/components/filters/TextFilter.tsx
deleted file mode 100644
index c7107a5..0000000
--- a/src/components/accordions/components/filters/TextFilter.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, { useRef } from 'react';
-import { Filter, FilterTypes, ValueOfFilter } from '@libs/filterInputs';
-import { FormControl, TextField } from '@mui/material';
-
-type FilterType = FilterTypes.TextInput;
-
-export const TextFilter = ({
- filter: { key, filter },
- value,
- set,
-}: {
- filter: { key: string; filter: Filter };
- value: ValueOfFilter;
- set: (v: typeof value) => void;
-}) => {
- const label = filter.label.replace(/s+/gi, '-');
- const textRef = useRef(null);
- return (
-
- {
- if (textRef.current) {
- set(textRef.current.value ?? '');
- }
- }}
- />
-
- );
-};
diff --git a/src/components/accordions/components/filters/TriStateCheckbox.tsx b/src/components/accordions/components/filters/TriStateCheckbox.tsx
deleted file mode 100644
index fdd639d..0000000
--- a/src/components/accordions/components/filters/TriStateCheckbox.tsx
+++ /dev/null
@@ -1,140 +0,0 @@
-import { styled } from '@mui/system';
-import React, { useRef, useState } from 'react';
-
-class TriStateCheckboxClasses {
- root = 'TriStateCheckboxRoot';
- base = 'TriStateCheckboxBase';
- input = 'TriStateCheckboxInput';
- svg = 'TriStateCheckboxSVG';
- checked: string;
- unchecked: string;
- neutral: string;
- offsets = {
- neutral: 16,
- checked: 16 * 2,
- unchecked: 0,
- };
- constructor() {
- this.checked = `${this.base}-checked`;
- this.neutral = `${this.base}-neutral`;
- this.unchecked = `${this.base}-unchecked`;
- }
-}
-
-const classes = new TriStateCheckboxClasses();
-
-const TriStateCheckboxRoot = styled(`span`, {
- name: classes.root,
- slot: 'root',
-})(({ theme }) => ({
- [`&.${classes.checked}`]: {
- color: theme.palette.primary.main,
- },
- [`&.${classes.unchecked}`]: {
- color: 'red',
- },
- display: 'inline-flex',
- alignItems: 'center',
- justifyContent: 'center',
- position: 'relative',
- boxSizing: 'border-box',
- outline: 0,
- border: 0,
- margin: 0,
- cursor: 'pointer',
- userSelect: 'none',
- textDecoration: 'none',
- borderRadius: '50%',
- padding: '9px',
-}));
-
-const TriStateCheckboxInput = styled(`input`, {
- name: classes.input,
- slot: 'input',
-})(() => ({
- cursor: 'inherit',
- position: 'absolute',
- opacity: 0,
- height: '100%',
- width: '100%',
- top: 0,
- left: 0,
- margin: 0,
- padding: 0,
- zIndex: 1,
-}));
-
-const TriStateCheckboxSVG = styled(`svg`, { name: classes.svg, slot: 'image' })(
- () => ({
- userSelect: 'none',
- width: '1em',
- height: '1em',
- display: 'inline-block',
- fill: 'currentcolor',
- flexShrink: 0,
- fontSize: '1.5rem',
- transition: 'fill 200ms cubic-bezier(0.4,0,0.2,1) 0ms',
- }),
-);
-
-const emptyPath = (
-
-);
-
-const checkmarkPath = (
-
-);
-
-const uncheckedPath = (
-
-);
-
-export type TriStateCheckboxState = 'checked' | 'unchecked' | 'neutral';
-
-export const TriStateCheckbox = function ({
- value,
- onChange,
-}: {
- value?: TriStateCheckboxState;
- onChange?: (newValue: TriStateCheckboxState) => void;
-}) {
- const [state, sSt] = useState(value ?? 'neutral');
- const setState = (v: TriStateCheckboxState) => {
- onChange?.(v);
- sSt(value ?? v);
- };
- const root = useRef(null);
-
- const curVal = value ?? state;
-
- return (
- <>
- {
- switch (curVal) {
- case 'checked':
- return setState('unchecked');
- case 'neutral':
- return setState('checked');
- case 'unchecked':
- return setState('neutral');
- }
- }}
- >
-
-
- {curVal === 'checked'
- ? checkmarkPath
- : curVal === 'unchecked'
- ? uncheckedPath
- : emptyPath}
-
-
- >
- );
-};
diff --git a/src/components/accordions/components/filters/TriStateSwitch.tsx b/src/components/accordions/components/filters/TriStateSwitch.tsx
deleted file mode 100644
index f8a348c..0000000
--- a/src/components/accordions/components/filters/TriStateSwitch.tsx
+++ /dev/null
@@ -1,191 +0,0 @@
-import { styled } from '@mui/system';
-import React, { useRef, useState } from 'react';
-
-class TriStateSwitchClasses {
- root = 'TriStateSwitchRoot';
- base = 'TriStateSwitchBase';
- track = 'TriStateSwitchTrack';
- thumb = 'TriStateSwitchThumb';
- input = 'TriStateSwitchInput';
- checked: string;
- unchecked: string;
- neutral: string;
- offsets = {
- neutral: 18,
- checked: 18 * 2,
- unchecked: 0,
- };
- width = 16 * 4 + 10;
- constructor() {
- this.base;
- this.checked = `${this.base}-checked`;
- this.neutral = `${this.base}-neutral`;
- this.unchecked = `${this.base}-unchecked`;
- }
-}
-
-const classes = new TriStateSwitchClasses();
-
-const TriStateSwitchRoot = styled(`span`, {
- name: classes.root,
- slot: 'root',
-})(() => ({
- display: 'inline-flex',
- width: `${classes.width}px`,
- height: '38px',
- overflow: 'hidden',
- boxSizing: 'border-box',
- position: 'relative',
- flexShrink: 0,
- zIndex: 0,
- verticalAlign: 'middle',
- padding: '8px',
-}));
-
-const TriStateSwitchTrack = styled(`span`, {
- name: classes.track,
- slot: 'track',
-})(() => ({
- // Android12 visuals:
- borderRadius: 22 / 2,
- // base Track
- width: '100%',
- height: '100%',
- zIndex: -1,
- content: `''`,
- transition:
- 'opacity 150ms cubic-bezier(0.4,0,0.2,1) 0ms, background-color 150ms cubic-bezier(0.4,0,0.2,1) 0ms',
- backgroundColor: '#000',
- opacity: 0.38,
-}));
-
-const TriStateSwitchBase = styled(`span`, {
- name: classes.base,
- slot: 'base',
-})(({ theme }) => ({
- [`&.${classes.unchecked}`]: {
- transform: `translateX(${classes.offsets.unchecked}px)`,
- color: '#f33',
- },
- [`&.${classes.checked}`]: {
- transform: `translateX(${classes.offsets.checked}px)`,
- color: theme.palette.primary.main,
- },
- [`&.${classes.neutral}`]: {
- transform: `translateX(${classes.offsets.neutral}px)`,
- color: 'gray',
- },
-
- [`&.${classes.checked} + span`]: {
- opacity: 0.5,
- backgroundColor: theme.palette.primary.main,
- },
- [`&.${classes.unchecked} + span`]: {
- opacity: 0.5,
- backgroundColor: '#f33',
- },
- display: 'inline-flex',
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: 'transparent',
- outline: 0,
- border: 0,
- margin: 0,
- cursor: 'pointer',
- userSelect: 'none',
- textDecoration: 'none',
- padding: '9px',
- borderRadius: '50%',
- position: 'absolute',
- top: 0,
- left: 0,
- zIndex: 1,
- color: '#fff',
- transition:
- 'left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,transform 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;',
-}));
-
-const TriStateSwitchInput = styled(`input`, {
- name: classes.input,
- slot: 'input',
-})(() => ({
- left: '-100%',
- width: '300%',
- cursor: 'inherit',
- position: 'absolute',
- opacity: 0,
- height: '100%',
- top: 0,
- margin: 0,
- padding: 0,
- zIndex: 1,
-}));
-
-const TriStateSwitchThumb = styled(`span`, {
- name: classes.thumb,
- slot: 'thumb',
-})(() => ({
- boxShadow: 'none',
- width: '16px',
- height: '16px',
- margin: '2px',
- backgroundColor: 'currentColor',
- borderRadius: '50%',
-}));
-type TriStateSwitchState = 'checked' | 'unchecked' | 'neutral';
-
-export const TriStateSwitch = function ({
- value,
- onChange,
-}: {
- value?: TriStateSwitchState;
- onChange?: (newValue: TriStateSwitchState) => void;
-}) {
- const [state, sSt] = useState(value ?? 'neutral');
- const setState = (v: TriStateSwitchState) => {
- onChange?.(v);
- sSt(value ?? v);
- };
-
- const root = useRef(null);
- return (
- <>
- {
- const offsetX =
- e.clientX - (root.current?.getBoundingClientRect().x ?? 0);
-
- const inputWidth = parseFloat(
- getComputedStyle(e.currentTarget).width,
- );
- const clickPercentage = offsetX / inputWidth;
- const sidePressed =
- clickPercentage < 0.33
- ? 'left'
- : clickPercentage > 0.66
- ? 'right'
- : 'center';
-
- console.log(inputWidth, offsetX);
-
- switch (sidePressed) {
- case 'center':
- return setState('neutral');
- case 'left':
- return setState('unchecked');
- case 'right':
- return setState('checked');
- }
- }}
- >
-
-
-
-
-
-
- >
- );
-};
diff --git a/src/components/accordions/components/filters/XCheckboxFilter.tsx b/src/components/accordions/components/filters/XCheckboxFilter.tsx
deleted file mode 100644
index 81f569a..0000000
--- a/src/components/accordions/components/filters/XCheckboxFilter.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import React from 'react';
-import { Filter, FilterTypes, ValueOfFilter } from '@libs/filterInputs';
-import { FormControl, FormControlLabel, FormLabel, Grid } from '@mui/material';
-import { useAppStore } from '@store';
-import { TriStateCheckbox, TriStateCheckboxState } from './TriStateCheckbox';
-import { TriStateSwitch } from './TriStateSwitch';
-
-type FilterType = FilterTypes.ExcludableCheckboxGroup;
-
-export const XCheckboxFilter = ({
- filter: { key, filter },
- value,
- set,
-}: {
- filter: { key: string; filter: Filter };
- value: ValueOfFilter;
- set: (v: typeof value) => void;
-}) => {
- const useSwitches = useAppStore(state => state.useSwitches);
-
- const getCheckboxState = (v: string): TriStateCheckboxState => {
- if (value.include?.includes(v)) return 'checked';
- if (value.exclude?.includes(v)) return 'unchecked';
- return 'neutral';
- };
-
- const handleChange = (key: string, v: TriStateCheckboxState) => {
- console.log(`setting ${key} to`, v);
- if (v === 'unchecked')
- return set({
- exclude: value.exclude
- ? Array.from(new Set([...value.exclude, key]))
- : [key],
- include: value.include?.filter(f => f !== key),
- });
- if (v === 'checked')
- return set({
- include: value.include
- ? Array.from(new Set([...value.include, key]))
- : [key],
- exclude: value.exclude?.filter(f => f !== key),
- });
- return set({
- include: value.include?.filter(f => f !== key),
- exclude: value.exclude?.filter(f => f !== key),
- });
- };
-
- return (
-
- {filter.label}
-
- {filter.options.map(option => {
- return (
-
-
- handleChange(option.value, c)}
- />
- ) : (
- handleChange(option.value, c)}
- />
- )
- }
- label={option.label}
- />
-
-
- );
- })}
-
-
- );
-};
diff --git a/src/components/filters/checkbox-filter.tsx b/src/components/filters/checkbox-filter.tsx
new file mode 100644
index 0000000..9d9c0f4
--- /dev/null
+++ b/src/components/filters/checkbox-filter.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { Label } from '@/components/ui/label';
+import { Checkbox } from '@/components/ui/checkbox';
+import { FilterTypes } from '@libs/filterInputs';
+import type { Filter } from '@libs/filterInputs';
+
+type CheckboxFilterProps = {
+ filter: {
+ key: string;
+ filter: Filter;
+ };
+ value: string[];
+ set: (value: string[]) => void;
+};
+
+export function CheckboxFilter({ filter, value, set }: CheckboxFilterProps) {
+ const toggleOption = (optionValue: string) => {
+ if (value.includes(optionValue)) {
+ set(value.filter(v => v !== optionValue));
+ } else {
+ set([...value, optionValue]);
+ }
+ };
+
+ return (
+
+
{filter.filter.label}
+
+ {filter.filter.options.map(option => (
+
+ toggleOption(option.value)}
+ />
+
+ {option.label}
+
+
+ ))}
+
+
+ );
+}
diff --git a/src/components/filters/excludable-checkbox-filter.tsx b/src/components/filters/excludable-checkbox-filter.tsx
new file mode 100644
index 0000000..8eeffc8
--- /dev/null
+++ b/src/components/filters/excludable-checkbox-filter.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import { Label } from '@/components/ui/label';
+import { Badge } from '@/components/ui/badge';
+import { FilterTypes } from '@libs/filterInputs';
+import type { Filter } from '@libs/filterInputs';
+
+type ExcludableCheckboxFilterProps = {
+ filter: {
+ key: string;
+ filter: Filter;
+ };
+ value: {
+ include?: string[];
+ exclude?: string[];
+ };
+ set: (value: { include?: string[]; exclude?: string[] }) => void;
+};
+
+type CheckState = 'unchecked' | 'included' | 'excluded';
+
+export function ExcludableCheckboxFilter({
+ filter,
+ value,
+ set,
+}: ExcludableCheckboxFilterProps) {
+ const getState = (optionValue: string): CheckState => {
+ if (value.include?.includes(optionValue)) return 'included';
+ if (value.exclude?.includes(optionValue)) return 'excluded';
+ return 'unchecked';
+ };
+
+ const toggleOption = (optionValue: string) => {
+ const currentState = getState(optionValue);
+ let newInclude = value.include || [];
+ let newExclude = value.exclude || [];
+
+ switch (currentState) {
+ case 'unchecked':
+ // Unchecked -> Included
+ newInclude = [...newInclude, optionValue];
+ break;
+ case 'included':
+ // Included -> Excluded
+ newInclude = newInclude.filter(v => v !== optionValue);
+ newExclude = [...newExclude, optionValue];
+ break;
+ case 'excluded':
+ // Excluded -> Unchecked
+ newExclude = newExclude.filter(v => v !== optionValue);
+ break;
+ }
+
+ set({ include: newInclude, exclude: newExclude });
+ };
+
+ return (
+
+
{filter.filter.label}
+
+ {filter.filter.options.map(option => {
+ const state = getState(option.value);
+ return (
+ toggleOption(option.value)}
+ className="flex items-center justify-between w-full px-3 py-2 text-sm rounded-md border border-border hover:bg-muted/50 transition-colors"
+ >
+ {option.label}
+ {state === 'included' && (
+
+ Include
+
+ )}
+ {state === 'excluded' && (
+
+ Exclude
+
+ )}
+
+ );
+ })}
+
+
+ Click once to include, twice to exclude, three times to reset
+
+
+ );
+}
diff --git a/src/components/accordions/components/filters/FiltersDialog.tsx b/src/components/filters/filters-sheet.tsx
similarity index 61%
rename from src/components/accordions/components/filters/FiltersDialog.tsx
rename to src/components/filters/filters-sheet.tsx
index a82f1a8..96cf626 100644
--- a/src/components/accordions/components/filters/FiltersDialog.tsx
+++ b/src/components/filters/filters-sheet.tsx
@@ -1,28 +1,25 @@
-import React, {
- forwardRef,
- ReactNode,
- useEffect,
- useImperativeHandle,
-} from 'react';
+import React, { useEffect, useState, ReactNode } from 'react';
+import { Button } from '@/components/ui/button';
import {
- Button,
- Dialog,
- DialogActions,
- DialogContent,
- DialogTitle,
-} from '@mui/material';
-import { useState } from 'react';
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+} from '@/components/ui/sheet';
import {
AnyFilterValue,
Filters,
FilterToValues,
FilterTypes,
} from '@libs/filterInputs';
-import { PickerFilter } from './PickerFilter';
-import { SwitchFilter } from './SwitchFilter';
-import { TextFilter } from './TextFilter';
-import { CheckboxFilter } from './CheckboxFilter';
-import { XCheckboxFilter } from './XCheckboxFilter';
+import { PickerFilter } from './picker-filter';
+import { SwitchFilter } from './switch-filter';
+import { TextFilter } from './text-filter';
+import { CheckboxFilter } from './checkbox-filter';
+import { ExcludableCheckboxFilter } from './excludable-checkbox-filter';
+import { RotateCcw } from 'lucide-react';
const renderFilters = (
filters: Filters | undefined,
@@ -41,7 +38,8 @@ const renderFilters = (
return typeof o === typeof f || checkIfIsCorrectObjectType(o, f);
};
- if (!filters || !values) return false;
+ if (!filters || !values) return null;
+
return (
<>
{Object.entries(filters).map(([key, filter]) => {
@@ -51,17 +49,13 @@ const renderFilters = (
}
switch (filter.type) {
case FilterTypes.Picker: {
- // Check if filterValues have correct type
- // this needs to be inside of every case in this switch to get correct value type
- const value = values[key].value; // here value has every possible value type
- // We could just do `as typeof filter.value` but just to be sure I made a typeguard
+ const value = values[key].value;
if (!isValueCorrectType(value, filter.value)) {
console.error(
`FilterValue for filter [${key}] has a wrong type!`,
);
return null;
}
- // value; // here value has only Picker's value
return (
(value, filter.value)) {
console.error(
`FilterValue for filter [${key}] has a wrong type!`,
);
return null;
}
- // value; // here value has only Picker's value
return (
set(key, newValue)}
value={value}
- key={`checkbox_filter_${key}`}
+ key={`xcheсkbox_filter_${key}`}
/>
);
}
@@ -149,21 +139,27 @@ const renderFilters = (
);
};
-export type DialogRef = { show(): void; hide(): void };
+type FiltersSheetProps = {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ values: FilterToValues | undefined;
+ filters: Filters | undefined;
+ setValues: React.Dispatch<
+ React.SetStateAction | undefined>
+ >;
+ refetch: () => void;
+};
+
+export function FiltersSheet({
+ open,
+ onOpenChange,
+ values,
+ setValues,
+ filters,
+ refetch,
+}: FiltersSheetProps) {
+ const [filterElements, setFilterElements] = useState(null);
-export const FiltersDialog = forwardRef<
- DialogRef,
- {
- values: FilterToValues | undefined;
- filters: Filters | undefined;
- setValues: React.Dispatch<
- React.SetStateAction | undefined>
- >;
- refetch(): void;
- }
->(function FiltersDialog({ values, setValues, filters, refetch }, ref) {
- const [dialogOpen, setDialogOpen] = useState(false);
- const [filterElements, setFilterElements] = useState(false);
const setFilterWithKey = (key: string, newValue: AnyFilterValue) =>
setValues(fValues =>
!fValues
@@ -177,35 +173,58 @@ export const FiltersDialog = forwardRef<
},
);
- useImperativeHandle(ref, () => ({
- show() {
- setDialogOpen(true);
- },
- hide() {
- setDialogOpen(false);
- },
- }));
+ const resetFilters = () => {
+ if (filters) {
+ const resetValues: FilterToValues = {};
+ for (const fKey in filters) {
+ resetValues[fKey as keyof typeof resetValues] = {
+ type: filters[fKey].type,
+ value: filters[fKey].value,
+ };
+ }
+ setValues(resetValues);
+ }
+ };
useEffect(() => {
setFilterElements(renderFilters(filters, values, setFilterWithKey));
- }, [values]);
+ }, [values, filters]);
+
+ const handleApply = () => {
+ refetch();
+ onOpenChange(false);
+ };
return (
- setDialogOpen(false)}
- >
- Filters
-
- {filterElements}
-
-
- refetch()}>Refetch
- setDialogOpen(false)}>
- Close
-
-
-
+
+
+
+ Filters
+
+ Customize your search with these filter options
+
+
+
+ {filterElements || (
+
+ No filters available
+
+ )}
+
+
+
+ Apply Filters
+
+
+
+ Reset to Default
+
+
+
+
);
-});
+}
diff --git a/src/components/filters/picker-filter.tsx b/src/components/filters/picker-filter.tsx
new file mode 100644
index 0000000..381712f
--- /dev/null
+++ b/src/components/filters/picker-filter.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { Label } from '@/components/ui/label';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select';
+import { FilterTypes } from '@libs/filterInputs';
+import type { Filter } from '@libs/filterInputs';
+
+type PickerFilterProps = {
+ filter: {
+ key: string;
+ filter: Filter;
+ };
+ value: string;
+ set: (value: string) => void;
+};
+
+const EMPTY_VALUE_PLACEHOLDER = '__lnreader_empty__';
+
+export function PickerFilter({ filter, value, set }: PickerFilterProps) {
+ // Map empty string to placeholder for Radix UI Select
+ const displayValue = value === '' ? EMPTY_VALUE_PLACEHOLDER : value;
+
+ // Handle change and map placeholder back to empty string
+ const handleChange = (newValue: string) => {
+ set(newValue === EMPTY_VALUE_PLACEHOLDER ? '' : newValue);
+ };
+
+ return (
+
+ {filter.filter.label}
+
+
+
+
+
+ {filter.filter.options.map(option => {
+ // Map empty string values to placeholder
+ const optionValue =
+ option.value === '' ? EMPTY_VALUE_PLACEHOLDER : option.value;
+ return (
+
+ {option.label || option.value || 'All'}
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/src/components/filters/switch-filter.tsx b/src/components/filters/switch-filter.tsx
new file mode 100644
index 0000000..3dbe0ff
--- /dev/null
+++ b/src/components/filters/switch-filter.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Label } from '@/components/ui/label';
+import { Switch } from '@/components/ui/switch';
+import { FilterTypes } from '@libs/filterInputs';
+import type { Filter } from '@libs/filterInputs';
+
+type SwitchFilterProps = {
+ filter: {
+ key: string;
+ filter: Filter;
+ };
+ value: boolean;
+ set: (value: boolean) => void;
+};
+
+export function SwitchFilter({ filter, value, set }: SwitchFilterProps) {
+ return (
+
+
+ {filter.filter.label}
+
+
+
+ );
+}
diff --git a/src/components/filters/text-filter.tsx b/src/components/filters/text-filter.tsx
new file mode 100644
index 0000000..710242d
--- /dev/null
+++ b/src/components/filters/text-filter.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Label } from '@/components/ui/label';
+import { Input } from '@/components/ui/input';
+import { FilterTypes } from '@libs/filterInputs';
+import type { Filter } from '@libs/filterInputs';
+
+type TextFilterProps = {
+ filter: {
+ key: string;
+ filter: Filter;
+ };
+ value: string;
+ set: (value: string) => void;
+};
+
+export function TextFilter({ filter, value, set }: TextFilterProps) {
+ return (
+
+
+ {filter.filter.label}
+
+ set(e.target.value)}
+ placeholder={`Enter ${filter.filter.label.toLowerCase()}...`}
+ />
+
+ );
+}
diff --git a/src/components/novel-card.tsx b/src/components/novel-card.tsx
new file mode 100644
index 0000000..bceae45
--- /dev/null
+++ b/src/components/novel-card.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import { Copy, Zap } from 'lucide-react';
+import { toast } from 'sonner';
+
+import { Button } from '@/components/ui/button';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+import { Plugin } from '@/types/plugin';
+
+type NovelCardProps = {
+ novel: Plugin.NovelItem;
+ onParse: (path: string) => void;
+};
+
+export function NovelCard({ novel, onParse }: NovelCardProps) {
+ const handleCopyPath = () => {
+ navigator.clipboard.writeText(novel.path);
+ toast.success('Novel path copied!');
+ };
+
+ return (
+
+
+
+
+
+
+ {novel.name}
+
+
+
+
+
+
+
+
+
+ Copy path
+
+
+
+
+ onParse(novel.path)}
+ >
+
+
+
+
+ Parse novel
+
+
+
+
+
+ );
+}
diff --git a/src/components/parse-chapter.tsx b/src/components/parse-chapter.tsx
new file mode 100644
index 0000000..f219ea6
--- /dev/null
+++ b/src/components/parse-chapter.tsx
@@ -0,0 +1,247 @@
+import React, { useState, useEffect } from 'react';
+import { Copy, FileText } from 'lucide-react';
+import { toast } from 'sonner';
+
+import { Button } from '@/components/ui/button';
+import { Card } from '@/components/ui/card';
+import { Input } from '@/components/ui/input';
+import { Skeleton } from '@/components/ui/skeleton';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+import { useAppStore } from '@/store';
+
+export default function ParseChapterSection() {
+ const plugin = useAppStore(state => state.plugin);
+ const parseChapterPath = useAppStore(state => state.parseChapterPath);
+ const shouldAutoSubmitChapter = useAppStore(
+ state => state.shouldAutoSubmitChapter,
+ );
+ const clearParseChapterPath = useAppStore(
+ state => state.clearParseChapterPath,
+ );
+ const [chapterPath, setChapterPath] = useState('');
+ const [chapterText, setChapterText] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [fetchError, setFetchError] = useState('');
+
+ const fetchChapterByPath = async (path: string) => {
+ if (plugin && path.trim()) {
+ setLoading(true);
+ setFetchError('');
+ try {
+ const result = await plugin.parseChapter(path);
+ setChapterText(result);
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : 'Failed to fetch chapter';
+ setFetchError(errorMessage);
+ console.error('Error parsing chapter:', error);
+ } finally {
+ setLoading(false);
+ }
+ }
+ };
+
+ const fetchChapter = async () => {
+ await fetchChapterByPath(chapterPath);
+ };
+
+ const handleKeyPress = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter' && chapterPath.trim()) {
+ fetchChapter();
+ }
+ };
+
+ const copyToClipboard = (text?: string, label?: string) => {
+ if (text) {
+ navigator.clipboard.writeText(text);
+ toast.success(`${label || 'Text'} copied to clipboard!`);
+ }
+ };
+
+ // Handle pre-filled path from navigation
+ useEffect(() => {
+ if (parseChapterPath) {
+ setChapterPath(parseChapterPath);
+
+ if (shouldAutoSubmitChapter && plugin) {
+ fetchChapterByPath(parseChapterPath);
+ }
+
+ clearParseChapterPath();
+ }
+ }, [
+ parseChapterPath,
+ shouldAutoSubmitChapter,
+ plugin,
+ clearParseChapterPath,
+ ]);
+
+ return (
+
+
+
+
+
+ Parse Chapter
+
+
+ {plugin
+ ? 'Enter a chapter path to fetch content'
+ : 'Select a plugin to parse chapters'}
+
+
+
+
+
+ setChapterPath(e.target.value)}
+ onKeyPress={handleKeyPress}
+ className="flex-1"
+ disabled={!plugin}
+ />
+
+ {loading ? 'Fetching...' : 'Fetch'}
+
+
+
+ {fetchError && (
+
+ )}
+
+ {loading && !chapterText ? (
+
+ ) : !chapterText ? (
+
+
+
+
+
+ {plugin ? 'Ready to parse' : 'No plugin selected'}
+
+
+ {plugin
+ ? 'Enter a chapter path in the field above and click "Fetch" to load the chapter content.'
+ : 'Please select a plugin from the sidebar to get started.'}
+
+
+ ) : chapterText ? (
+
+
+
+
+ Chapter Content
+
+
+ {chapterPath}
+
+
+
+
+
+
+ copyToClipboard(chapterPath, 'Chapter path')
+ }
+ >
+
+ Copy Path
+
+
+
+ Copy chapter path to clipboard
+
+
+
+
+
+ copyToClipboard(chapterText, 'Chapter text')
+ }
+ >
+
+ Copy Text
+
+
+
+ Copy chapter text to clipboard
+
+
+
+
+
+
+
+
+ CHAPTER CONTENT ({chapterText.length} characters)
+
+
+
+
+
+
+
+ Content loaded successfully
+
+
{
+ setChapterText('');
+ setChapterPath('');
+ }}
+ >
+ Clear
+
+
+
+ ) : null}
+
+
+ );
+}
diff --git a/src/components/parse-novel.tsx b/src/components/parse-novel.tsx
new file mode 100644
index 0000000..9fb451a
--- /dev/null
+++ b/src/components/parse-novel.tsx
@@ -0,0 +1,499 @@
+import React, { useState, useEffect } from 'react';
+import { BookOpen, ChevronLeft, ChevronRight, Copy, Zap } from 'lucide-react';
+import { toast } from 'sonner';
+
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { Card } from '@/components/ui/card';
+import { Input } from '@/components/ui/input';
+import { Skeleton } from '@/components/ui/skeleton';
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from '@/components/ui/tooltip';
+import { useAppStore } from '@/store';
+import { Plugin } from '@/types/plugin';
+
+type ParseNovelSectionProps = {
+ onNavigateToParseChapter?: () => void;
+};
+
+export default function ParseNovelSection({
+ onNavigateToParseChapter,
+}: ParseNovelSectionProps) {
+ const plugin = useAppStore(state => state.plugin);
+ const parseNovelPath = useAppStore(state => state.parseNovelPath);
+ const shouldAutoSubmitNovel = useAppStore(
+ state => state.shouldAutoSubmitNovel,
+ );
+ const clearParseNovelPath = useAppStore(state => state.clearParseNovelPath);
+ const setParseChapterPath = useAppStore(state => state.setParseChapterPath);
+ const [novelPath, setNovelPath] = useState('');
+ const [sourceNovel, setSourceNovel] = useState<
+ (Plugin.SourceNovel & { totalPages?: number }) | undefined
+ >();
+ const [chapters, setChapters] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [currentPage, setCurrentPage] = useState(1);
+ const [fetchError, setFetchError] = useState('');
+
+ const fetchNovelByPath = async (path: string) => {
+ if (plugin && path.trim()) {
+ setLoading(true);
+ setFetchError('');
+ try {
+ const result = await plugin.parseNovel(path);
+ setSourceNovel(result);
+ setChapters(result.chapters || []);
+ setCurrentPage(1);
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : 'Failed to fetch novel';
+ setFetchError(errorMessage);
+ console.error('Error parsing novel:', error);
+ } finally {
+ setLoading(false);
+ }
+ }
+ };
+
+ const fetchNovel = async () => {
+ await fetchNovelByPath(novelPath);
+ };
+
+ const fetchPage = async (page: number) => {
+ if (plugin && novelPath && sourceNovel?.totalPages) {
+ setLoading(true);
+ setFetchError('');
+ try {
+ const result = await (plugin as Plugin.PagePlugin).parsePage(
+ novelPath,
+ page.toString(),
+ );
+ setChapters(result.chapters);
+ setCurrentPage(page);
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : 'Failed to fetch page';
+ setFetchError(errorMessage);
+ console.error('Error fetching page:', error);
+ } finally {
+ setLoading(false);
+ }
+ }
+ };
+
+ const handleKeyPress = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter' && novelPath.trim()) {
+ fetchNovel();
+ }
+ };
+
+ const copyToClipboard = (text?: string, label?: string) => {
+ if (text) {
+ navigator.clipboard.writeText(text);
+ toast.success(`${label || 'Text'} copied to clipboard!`);
+ }
+ };
+
+ const handleParseChapter = (path: string) => {
+ setParseChapterPath(path, true);
+ onNavigateToParseChapter?.();
+ };
+
+ useEffect(() => {
+ if (parseNovelPath) {
+ setNovelPath(parseNovelPath);
+
+ if (shouldAutoSubmitNovel && plugin) {
+ fetchNovelByPath(parseNovelPath);
+ }
+
+ clearParseNovelPath();
+ }
+ }, [parseNovelPath, shouldAutoSubmitNovel, plugin, clearParseNovelPath]);
+
+ const formatDate = (dateString?: string | null) => {
+ if (!dateString) return 'N/A';
+ try {
+ const date = new Date(dateString);
+ return date.toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ });
+ } catch {
+ return dateString;
+ }
+ };
+
+ return (
+
+
+
+
+
+ Parse Novel
+
+
+ {plugin
+ ? 'Enter a novel path to fetch details'
+ : 'Select a plugin to parse novels'}
+
+
+
+
+
+ setNovelPath(e.target.value)}
+ onKeyPress={handleKeyPress}
+ className="flex-1"
+ disabled={!plugin}
+ />
+
+ {loading ? 'Fetching...' : 'Fetch'}
+
+
+
+ {fetchError && (
+
+ )}
+
+ {loading && !sourceNovel ? (
+
+ ) : !sourceNovel ? (
+
+
+
+
+
+ {plugin ? 'Ready to parse' : 'No plugin selected'}
+
+
+ {plugin
+ ? 'Enter a novel path in the field above and click "Fetch" to load detailed information, including chapters, metadata, and more.'
+ : 'Please select a plugin from the sidebar to get started.'}
+
+
+ ) : sourceNovel ? (
+
+
+ {/* Novel Info */}
+
+
+
+ copyToClipboard(sourceNovel.cover, 'Cover URL')
+ }
+ >
+
+
+
+
+ {sourceNovel.name}
+
+
+ {sourceNovel.status && (
+
+
+ Status
+
+
+ {sourceNovel.status}
+
+
+ )}
+ {sourceNovel.author && (
+
+
+ Author
+
+
+ {sourceNovel.author}
+
+
+ )}
+ {sourceNovel.artist && (
+
+
+ Artist
+
+
+ {sourceNovel.artist}
+
+
+ )}
+ {sourceNovel.rating && (
+
+
+ Rating
+
+
+ {sourceNovel.rating.toFixed(1)} / 5.0
+
+
+ )}
+
+
+
+
+ copyToClipboard(sourceNovel.path, 'Novel path')
+ }
+ >
+
+ Copy Path
+
+
+
+ Copy novel path to clipboard
+
+
+
+
+
+ {sourceNovel.genres && (
+
+
+ Genres
+
+
+ {sourceNovel.genres.split(/,\s*/).map((genre, index) => (
+
+ {genre}
+
+ ))}
+
+
+ )}
+
+ {sourceNovel.summary && (
+
+
+ Summary
+
+
+ {sourceNovel.summary}
+
+
+ )}
+
+
+ {/* Sidebar Info */}
+
+
Metadata
+
+
+
+ Total Chapters
+
+
+ {chapters.length}
+
+
+ {sourceNovel.totalPages && (
+
+
+ Total Pages
+
+
+ {sourceNovel.totalPages}
+
+
+ )}
+ {chapters.length > 0 && chapters[0].releaseTime && (
+
+
+ First Chapter
+
+
+ {formatDate(chapters[0].releaseTime)}
+
+
+ )}
+ {chapters.length > 0 &&
+ chapters[chapters.length - 1].releaseTime && (
+
+
+ Last Updated
+
+
+ {formatDate(
+ chapters[chapters.length - 1].releaseTime,
+ )}
+
+
+ )}
+
+
+
+
+ {/* Chapters Table */}
+ {chapters.length > 0 && (
+
+
+
+ Chapters ({chapters.length})
+
+ {sourceNovel.totalPages && sourceNovel.totalPages > 1 && (
+
+ fetchPage(currentPage - 1)}
+ disabled={currentPage === 1 || loading}
+ >
+
+ Previous
+
+
+ Page {currentPage} of {sourceNovel.totalPages}
+
+ fetchPage(currentPage + 1)}
+ disabled={
+ currentPage === sourceNovel.totalPages || loading
+ }
+ >
+ Next
+
+
+
+ )}
+
+
+
+
+
+
+ #
+
+
+ Name
+
+
+ Actions
+
+
+ Release Time
+
+ {chapters.some(ch => ch.chapterNumber) && (
+
+ Chapter #
+
+ )}
+
+
+
+ {chapters.map((chapter, index) => (
+
+
+ {index}
+
+
+ {chapter.name}
+
+
+
+
+
+
+ copyToClipboard(
+ chapter.path,
+ 'Chapter path',
+ )
+ }
+ >
+
+
+
+
+ Copy chapter path
+
+
+
+
+
+ handleParseChapter(chapter.path)
+ }
+ >
+
+
+
+
+ Parse chapter
+
+
+
+
+
+ {formatDate(chapter.releaseTime)}
+
+ {chapters.some(ch => ch.chapterNumber) && (
+
+ {chapter.chapterNumber || '-'}
+
+ )}
+
+ ))}
+
+
+
+
+ )}
+
+ ) : null}
+
+
+ );
+}
diff --git a/src/components/plugin-header.tsx b/src/components/plugin-header.tsx
new file mode 100644
index 0000000..bd25054
--- /dev/null
+++ b/src/components/plugin-header.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+
+import { Plugin } from '@/types/plugin';
+
+type PluginHeaderProps = {
+ selectedPlugin?: Plugin.PluginBase;
+};
+
+export default function PluginHeader({ selectedPlugin }: PluginHeaderProps) {
+ return (
+
+
+
+
+ 読
+
+
+
+ Plugin Playground
+
+
+ {selectedPlugin?.name}
+
+
+
+
+
+ );
+}
diff --git a/src/components/popular-novels.tsx b/src/components/popular-novels.tsx
new file mode 100644
index 0000000..c8d5f75
--- /dev/null
+++ b/src/components/popular-novels.tsx
@@ -0,0 +1,219 @@
+import React, { useState, useEffect } from 'react';
+import { Filter, Zap } from 'lucide-react';
+
+import { FiltersSheet } from '@/components/filters/filters-sheet';
+import { NovelCard } from '@/components/novel-card';
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { Card } from '@/components/ui/card';
+import { Input } from '@/components/ui/input';
+import { Skeleton } from '@/components/ui/skeleton';
+import { useAppStore } from '@/store';
+import { FilterToValues, Filters } from '@libs/filterInputs';
+import { Plugin } from '@/types/plugin';
+
+type PopularNovelsSectionProps = {
+ onNavigateToParseNovel?: () => void;
+};
+
+export default function PopularNovelsSection({
+ onNavigateToParseNovel,
+}: PopularNovelsSectionProps) {
+ const plugin = useAppStore(state => state.plugin);
+ const setParseNovelPath = useAppStore(state => state.setParseNovelPath);
+ const [novels, setNovels] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const [maxIndex, setMaxIndex] = useState(0);
+ const [isLatest, setIsLatest] = useState(true);
+ const [filtersOpen, setFiltersOpen] = useState(false);
+ const [filterValues, setFilterValues] = useState<
+ FilterToValues | undefined
+ >();
+
+ const fetchNovelsByIndex = async (index: number) => {
+ if (plugin && index) {
+ setLoading(true);
+ try {
+ const fetchedNovels = await plugin.popularNovels(index, {
+ filters: filterValues || {},
+ showLatestNovels: isLatest,
+ });
+ if (fetchedNovels.length !== 0) {
+ setCurrentIndex(index);
+ if (index > maxIndex) {
+ setMaxIndex(index);
+ }
+ setNovels(fetchedNovels);
+ }
+ } catch (error) {
+ console.error('Error fetching novels:', error);
+ } finally {
+ setLoading(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ if (plugin) {
+ setCurrentIndex(1);
+ setMaxIndex(1);
+ fetchNovelsByIndex(1);
+ }
+ }, [isLatest]);
+
+ useEffect(() => {
+ // Reset when changing plugins
+ setCurrentIndex(0);
+ setMaxIndex(0);
+ setNovels([]);
+
+ if (plugin?.filters) {
+ const filters: FilterToValues = {};
+ for (const fKey in plugin.filters) {
+ filters[fKey as keyof typeof filters] = {
+ type: plugin.filters[fKey].type,
+ value: plugin.filters[fKey].value,
+ };
+ }
+ setFilterValues(filters);
+ }
+ }, [plugin]);
+
+ const handleParseNovel = (path: string) => {
+ setParseNovelPath(path, true);
+ onNavigateToParseNovel?.();
+ };
+
+ return (
+
+
+
+
+
+ Popular Novels
+
+
+ {plugin
+ ? `Browse ${isLatest ? 'latest' : 'popular'} novels`
+ : 'Select a plugin to browse novels'}
+
+
+
+ setFiltersOpen(true)}
+ >
+
+ Filters
+
+ fetchNovelsByIndex(1)}
+ >
+ {loading ? 'Loading...' : 'Fetch'}
+
+ fetchNovelsByIndex(currentIndex + 1)}
+ >
+ Next Page
+
+
+
+
+
+ {['Latest', 'Popular'].map(option => (
+
setIsLatest(option === 'Latest')}
+ >
+ {option}
+
+ ))}
+ {currentIndex > 0 && (
+
+ Page
+ ) => {
+ const page = parseInt(e.target.value);
+ if (page > 0 && page <= maxIndex) {
+ fetchNovelsByIndex(page);
+ }
+ }}
+ className="w-16 h-7 text-center text-xs"
+ disabled={loading}
+ />
+
+ of {maxIndex}+
+
+
+ )}
+
+
+ {loading ? (
+
+ {Array.from({ length: 12 }).map((_, index) => (
+
+ ))}
+
+ ) : novels.length === 0 ? (
+
+
+
+
+
+ {plugin ? 'No novels to display' : 'No plugin selected'}
+
+
+ {plugin
+ ? 'Click the "Fetch" button above to load the latest or popular novels from this source.'
+ : 'Please select a plugin from the sidebar to get started.'}
+
+
+ ) : (
+
+ {novels.map((novel, index) => (
+
+ ))}
+
+ )}
+
+
+
fetchNovelsByIndex(1)}
+ />
+
+ );
+}
diff --git a/src/components/search-novels.tsx b/src/components/search-novels.tsx
new file mode 100644
index 0000000..30a4266
--- /dev/null
+++ b/src/components/search-novels.tsx
@@ -0,0 +1,162 @@
+import React, { useState, useEffect } from 'react';
+import { Search as SearchIcon } from 'lucide-react';
+
+import { NovelCard } from '@/components/novel-card';
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { Card } from '@/components/ui/card';
+import { Input } from '@/components/ui/input';
+import { Skeleton } from '@/components/ui/skeleton';
+import { useAppStore } from '@/store';
+import { Plugin } from '@/types/plugin';
+
+type SearchNovelsSectionProps = {
+ onNavigateToParseNovel?: () => void;
+};
+
+export default function SearchNovelsSection({
+ onNavigateToParseNovel,
+}: SearchNovelsSectionProps) {
+ const plugin = useAppStore(state => state.plugin);
+ const setParseNovelPath = useAppStore(state => state.setParseNovelPath);
+ const [searchTerm, setSearchTerm] = useState('');
+ const [currentPage, setCurrentPage] = useState(1);
+ const [novels, setNovels] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [fetchError, setFetchError] = useState('');
+
+ const fetchNovels = async (page: number) => {
+ if (plugin && searchTerm.trim()) {
+ setLoading(true);
+ setFetchError('');
+ try {
+ const results = await plugin.searchNovels(searchTerm, page);
+ setNovels(results);
+ setCurrentPage(page);
+ } catch (error) {
+ const errorMessage =
+ error instanceof Error ? error.message : 'Failed to fetch novels';
+ setFetchError(errorMessage);
+ console.error('Error searching novels:', error);
+ } finally {
+ setLoading(false);
+ }
+ }
+ };
+
+ useEffect(() => {
+ setCurrentPage(1);
+ setNovels([]);
+ setSearchTerm('');
+ setFetchError('');
+ }, [plugin]);
+
+ const handleKeyPress = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter' && searchTerm.trim()) {
+ fetchNovels(1);
+ }
+ };
+
+ const handleParseNovel = (path: string) => {
+ setParseNovelPath(path, true);
+ onNavigateToParseNovel?.();
+ };
+
+ return (
+
+
+
+
+
+ Search Novels
+
+
+ {plugin
+ ? 'Search for novels by title or keywords'
+ : 'Select a plugin to search novels'}
+
+
+ {currentPage > 1 && (
+
Page {currentPage}
+ )}
+
+
+
+ setSearchTerm(e.target.value)}
+ onKeyPress={handleKeyPress}
+ className="flex-1"
+ disabled={!plugin}
+ />
+ fetchNovels(1)}
+ disabled={!plugin || !searchTerm.trim() || loading}
+ >
+ {loading ? 'Searching...' : 'Search'}
+
+ fetchNovels(currentPage + 1)}
+ disabled={!plugin || novels.length === 0 || loading}
+ >
+ Next Page
+
+
+
+ {fetchError && (
+
+ )}
+
+ {loading ? (
+
+ {Array.from({ length: 12 }).map((_, index) => (
+
+ ))}
+
+ ) : novels.length === 0 ? (
+
+
+
+
+
+ {searchTerm
+ ? 'No results found'
+ : plugin
+ ? 'Ready to search'
+ : 'No plugin selected'}
+
+
+ {searchTerm
+ ? 'Try adjusting your search term or check the spelling. Different sources may have different availability.'
+ : plugin
+ ? 'Enter a search term in the field above and click "Search" to find novels.'
+ : 'Please select a plugin from the sidebar to get started.'}
+
+
+ ) : (
+
+ {novels.map((novel, index) => (
+
+ ))}
+
+ )}
+
+
+ );
+}
diff --git a/src/components/settings.tsx b/src/components/settings.tsx
new file mode 100644
index 0000000..7bbad2b
--- /dev/null
+++ b/src/components/settings.tsx
@@ -0,0 +1,199 @@
+import React, { useState, useEffect } from 'react';
+import { CheckedState } from '@radix-ui/react-checkbox';
+import { Check } from 'lucide-react';
+
+import { Card } from '@/components/ui/card';
+import { Checkbox } from '@/components/ui/checkbox';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select';
+import useDebounce from '@/hooks/useDebounce';
+import { FetchMode } from '@/types/types';
+
+export default function SettingsSection() {
+ const [cookies, setCookies] = useState('');
+ const debouncedCookies = useDebounce(cookies, 500);
+ const [fetchMode, setFetchMode] = useState(FetchMode.PROXY);
+ const [useUserAgent, setUseUserAgent] = useState(true);
+ const [loading, setLoading] = useState(false);
+ const [alertVisible, setAlertVisible] = useState(false);
+
+ useEffect(() => {
+ if (alertVisible) {
+ const id = setTimeout(() => setAlertVisible(false), 2000);
+ return () => clearTimeout(id);
+ }
+ }, [alertVisible]);
+
+ useEffect(() => {
+ setLoading(true);
+ fetch('settings', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ cookies: debouncedCookies,
+ fetchMode: fetchMode,
+ useUserAgent: useUserAgent === true,
+ }),
+ })
+ .then(() => setAlertVisible(true))
+ .catch(error => console.error('Failed to save settings:', error))
+ .finally(() => setLoading(false));
+ }, [debouncedCookies, fetchMode, useUserAgent]);
+
+ const getFetchModeLabel = (mode: FetchMode) => {
+ switch (mode) {
+ case FetchMode.PROXY:
+ return 'Proxy';
+ case FetchMode.NODE_FETCH:
+ return 'Node Fetch';
+ case FetchMode.CURL:
+ return 'Curl';
+ default:
+ return 'Proxy';
+ }
+ };
+
+ return (
+
+
+ {alertVisible && (
+
+
+ Settings updated
+
+ )}
+
+
+
+
Settings
+
+ Settings are automatically saved
+
+
+ {loading && (
+
Saving...
+ )}
+
+
+
+ {/* Request Configuration Section */}
+
+
+
+
+ Request Configuration
+
+
+
+
+
+ {/* User Agent */}
+
+
+ Browser User Agent
+
+
+
+ Enable to send your browser's user agent with requests
+
+
+
+ {/* Cookies */}
+
+
+ Cookies
+
+
setCookies(e.target.value.trim())}
+ placeholder="Enter cookies (optional)..."
+ className="font-mono text-xs"
+ />
+
+ Additional cookies to send with requests (optional)
+
+
+
+
+
+ {/* Fetch Settings Section */}
+
+
+
+
+ Fetch Settings
+
+
+
+
+
+
+ Fetch Mode
+
+
+ setFetchMode(parseInt(value) as FetchMode)
+ }
+ >
+
+ {getFetchModeLabel(fetchMode)}
+
+
+
+ Proxy
+
+
+ Node Fetch
+
+
+ Curl
+
+
+
+
+ Select the method used to fetch data from sources
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx
new file mode 100644
index 0000000..b0c1fc9
--- /dev/null
+++ b/src/components/ui/badge.tsx
@@ -0,0 +1,46 @@
+import * as React from 'react';
+import { Slot } from '@radix-ui/react-slot';
+import { cva, type VariantProps } from 'class-variance-authority';
+
+import { cn } from '@/lib/utils';
+
+const badgeVariants = cva(
+ 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
+ {
+ variants: {
+ variant: {
+ default:
+ 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
+ secondary:
+ 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
+ destructive:
+ 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ },
+ },
+);
+
+function Badge({
+ className,
+ variant,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'span'> &
+ VariantProps & { asChild?: boolean }) {
+ const Comp = asChild ? Slot : 'span';
+
+ return (
+
+ );
+}
+
+export { Badge, badgeVariants };
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..08da3e6
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,60 @@
+import * as React from 'react';
+import { Slot } from '@radix-ui/react-slot';
+import { cva, type VariantProps } from 'class-variance-authority';
+
+import { cn } from '@/lib/utils';
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ {
+ variants: {
+ variant: {
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
+ destructive:
+ 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
+ outline:
+ 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
+ secondary:
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ ghost:
+ 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
+ link: 'text-primary underline-offset-4 hover:underline',
+ },
+ size: {
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
+ sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
+ icon: 'size-9',
+ 'icon-sm': 'size-8',
+ 'icon-lg': 'size-10',
+ },
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ },
+ },
+);
+
+function Button({
+ className,
+ variant,
+ size,
+ asChild = false,
+ ...props
+}: React.ComponentProps<'button'> &
+ VariantProps & {
+ asChild?: boolean;
+ }) {
+ const Comp = asChild ? Slot : 'button';
+
+ return (
+
+ );
+}
+
+export { Button, buttonVariants };
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
new file mode 100644
index 0000000..850392e
--- /dev/null
+++ b/src/components/ui/card.tsx
@@ -0,0 +1,92 @@
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Card({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardAction,
+ CardDescription,
+ CardContent,
+};
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..3468424
--- /dev/null
+++ b/src/components/ui/checkbox.tsx
@@ -0,0 +1,32 @@
+'use client';
+
+import * as React from 'react';
+import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
+import { CheckIcon } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+function Checkbox({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+ );
+}
+
+export { Checkbox };
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 0000000..33b3936
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,21 @@
+import * as React from 'react';
+
+import { cn } from '@/lib/utils';
+
+function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
+ return (
+
+ );
+}
+
+export { Input };
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
new file mode 100644
index 0000000..3f438ea
--- /dev/null
+++ b/src/components/ui/label.tsx
@@ -0,0 +1,22 @@
+import * as React from 'react';
+import * as LabelPrimitive from '@radix-ui/react-label';
+
+import { cn } from '@/lib/utils';
+
+function Label({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export { Label };
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
new file mode 100644
index 0000000..d8642ed
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,185 @@
+import * as React from 'react';
+import * as SelectPrimitive from '@radix-ui/react-select';
+import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+function Select({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function SelectGroup({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function SelectValue({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function SelectTrigger({
+ className,
+ size = 'default',
+ children,
+ ...props
+}: React.ComponentProps & {
+ size?: 'sm' | 'default';
+}) {
+ return (
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectContent({
+ className,
+ children,
+ position = 'popper',
+ align = 'center',
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+function SelectLabel({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SelectItem({
+ className,
+ children,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+
+
+
+ {children}
+
+ );
+}
+
+function SelectSeparator({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function SelectScrollUpButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+function SelectScrollDownButton({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+export {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectScrollDownButton,
+ SelectScrollUpButton,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+};
diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx
new file mode 100644
index 0000000..28fd5d7
--- /dev/null
+++ b/src/components/ui/sheet.tsx
@@ -0,0 +1,131 @@
+import * as React from 'react';
+import * as SheetPrimitive from '@radix-ui/react-dialog';
+import { X } from 'lucide-react';
+
+import { cn } from '@/lib/utils';
+
+const Sheet = SheetPrimitive.Root;
+
+const SheetTrigger = SheetPrimitive.Trigger;
+
+const SheetClose = SheetPrimitive.Close;
+
+const SheetPortal = SheetPrimitive.Portal;
+
+const SheetOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
+
+type SheetContentProps = React.ComponentPropsWithoutRef<
+ typeof SheetPrimitive.Content
+> & {
+ side?: 'top' | 'right' | 'bottom' | 'left';
+};
+
+const SheetContent = React.forwardRef<
+ React.ElementRef,
+ SheetContentProps
+>(({ side = 'right', className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+));
+SheetContent.displayName = SheetPrimitive.Content.displayName;
+
+const SheetHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+SheetHeader.displayName = 'SheetHeader';
+
+const SheetFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+SheetFooter.displayName = 'SheetFooter';
+
+const SheetTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SheetTitle.displayName = SheetPrimitive.Title.displayName;
+
+const SheetDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SheetDescription.displayName = SheetPrimitive.Description.displayName;
+
+export {
+ Sheet,
+ SheetPortal,
+ SheetOverlay,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+};
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx
new file mode 100644
index 0000000..16e5a50
--- /dev/null
+++ b/src/components/ui/skeleton.tsx
@@ -0,0 +1,16 @@
+import * as React from 'react';
+import { cn } from '@/lib/utils';
+
+function Skeleton({
+ className,
+ ...props
+}: React.HTMLAttributes) {
+ return (
+
+ );
+}
+
+export { Skeleton };
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
new file mode 100644
index 0000000..96de4f5
--- /dev/null
+++ b/src/components/ui/sonner.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import {
+ CircleCheckIcon,
+ InfoIcon,
+ Loader2Icon,
+ OctagonXIcon,
+ TriangleAlertIcon,
+} from 'lucide-react';
+import { Toaster as Sonner, type ToasterProps } from 'sonner';
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ return (
+ ,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
+ style={
+ {
+ '--normal-bg': 'var(--popover)',
+ '--normal-text': 'var(--popover-foreground)',
+ '--normal-border': 'var(--border)',
+ '--border-radius': 'var(--radius)',
+ } as React.CSSProperties
+ }
+ {...props}
+ />
+ );
+};
+
+export { Toaster };
diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx
new file mode 100644
index 0000000..0195656
--- /dev/null
+++ b/src/components/ui/switch.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react';
+import * as SwitchPrimitives from '@radix-ui/react-switch';
+
+import { cn } from '@/lib/utils';
+
+const Switch = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+Switch.displayName = SwitchPrimitives.Root.displayName;
+
+export { Switch };
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
new file mode 100644
index 0000000..97945e9
--- /dev/null
+++ b/src/components/ui/tabs.tsx
@@ -0,0 +1,64 @@
+import * as React from 'react';
+import * as TabsPrimitive from '@radix-ui/react-tabs';
+
+import { cn } from '@/lib/utils';
+
+function Tabs({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function TabsList({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function TabsTrigger({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+function TabsContent({
+ className,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+ );
+}
+
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..0243b83
--- /dev/null
+++ b/src/components/ui/tooltip.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react';
+import * as TooltipPrimitive from '@radix-ui/react-tooltip';
+
+import { cn } from '@/lib/utils';
+
+const TooltipProvider = TooltipPrimitive.Provider;
+
+function Tooltip({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function TooltipTrigger({
+ ...props
+}: React.ComponentProps) {
+ return ;
+}
+
+function TooltipContent({
+ className,
+ sideOffset = 4,
+ ...props
+}: React.ComponentProps) {
+ return (
+
+
+
+ );
+}
+
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/src/hooks/useQueryParams.ts b/src/hooks/useQueryParams.ts
new file mode 100644
index 0000000..8648820
--- /dev/null
+++ b/src/hooks/useQueryParams.ts
@@ -0,0 +1,36 @@
+import { useCallback } from 'react';
+
+export const useQueryParams = () => {
+ const getParam = useCallback((key: string): string | null => {
+ const urlParams = new URLSearchParams(window.location.search);
+ return urlParams.get(key);
+ }, []);
+
+ const setParam = useCallback((key: string, value: string) => {
+ const url = new URL(window.location.href);
+ url.searchParams.set(key, value);
+ window.history.pushState({}, '', url);
+ }, []);
+
+ const removeParam = useCallback((key: string) => {
+ const url = new URL(window.location.href);
+ url.searchParams.delete(key);
+ window.history.pushState({}, '', url);
+ }, []);
+
+ const getAllParams = useCallback((): Record => {
+ const urlParams = new URLSearchParams(window.location.search);
+ const result: Record = {};
+ urlParams.forEach((value, key) => {
+ result[key] = value;
+ });
+ return result;
+ }, []);
+
+ return {
+ getParam,
+ setParam,
+ removeParam,
+ getAllParams,
+ };
+};
diff --git a/src/index.css b/src/index.css
index bc6959e..c2ef8d3 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,70 +1,136 @@
-body::-webkit-scrollbar {
- display: none;
-}
+@import 'tailwindcss';
+@import 'tw-animate-css';
+@import '@fontsource/geist-sans/index.css';
+@import '@fontsource/geist-mono/index.css';
+
+@custom-variant dark (&:is(.dark *));
+
:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --radius: 0.625rem;
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+ --accent-strong: #1d6378;
+ --accent-soft: rgba(43, 127, 150, 0.18);
+ --outline: rgba(45, 52, 64, 0.45);
}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
+.dark {
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.145 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.145 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.985 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.396 0.141 25.723);
+ --destructive-foreground: oklch(0.637 0.237 25.331);
+ --border: oklch(0.269 0 0);
+ --input: oklch(0.269 0 0);
+ --ring: oklch(0.439 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(0.269 0 0);
+ --sidebar-ring: oklch(0.439 0 0);
+ --accent-strong: #2b7f96;
+ --accent-soft: rgba(43, 127, 150, 0.25);
+ --outline: rgba(43, 127, 150, 0.45);
}
-body {
- margin: 0;
- display: flex;
- min-width: 320px;
- min-height: 100vh;
+@theme inline {
+ --font-sans: 'Geist Sans', system-ui, -apple-system, sans-serif;
+ --font-mono: 'Geist Mono', ui-monospace, monospace;
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+ --color-accent-strong: var(--accent-strong);
+ --color-accent-soft: var(--accent-soft);
+ --color-outline: var(--outline);
}
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
+@layer base {
+ * {
+ @apply border-border outline-ring/50;
}
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
+ body {
+ @apply bg-background text-foreground font-sans;
}
}
diff --git a/src/lib/fetch.ts b/src/lib/fetch.ts
new file mode 100644
index 0000000..401d2b6
--- /dev/null
+++ b/src/lib/fetch.ts
@@ -0,0 +1,156 @@
+/* global Buffer, RequestInit */
+
+import { parse as parseProto } from 'protobufjs';
+
+type FetchInit = {
+ headers?: Record | Headers;
+ method?: string;
+ body?: FormData | string;
+ [x: string]:
+ | string
+ | Record
+ | undefined
+ | FormData
+ | Headers;
+};
+
+const makeInit = async (init?: FetchInit) => {
+ const defaultHeaders: Record = {
+ 'Connection': 'keep-alive',
+ 'Accept': '*/*',
+ 'Accept-Language': '*',
+ 'Sec-Fetch-Mode': 'cors',
+ 'Accept-Encoding': 'gzip, deflate',
+ };
+ if (init?.headers) {
+ if (init.headers instanceof Headers) {
+ for (const [name, value] of Object.entries(defaultHeaders)) {
+ if (!init.headers.get(name)) init.headers.set(name, value);
+ }
+ } else {
+ init.headers = {
+ ...defaultHeaders,
+ ...init.headers,
+ };
+ }
+ } else {
+ init = {
+ ...init,
+ headers: defaultHeaders,
+ };
+ }
+ return init;
+};
+
+/**
+ * Fetch with (Android) User Agent
+ * @param url
+ * @param init
+ * @returns response as normal fetch
+ */
+export async function fetchApi(url: string, init?: FetchInit) {
+ init = await makeInit(init);
+ console.log(url, init);
+ return await fetch(url, init as RequestInit);
+}
+
+/**
+ *
+ * @param url
+ * @param init
+ * @returns base64 string of file
+ * @example fetchFile('https://avatars.githubusercontent.com/u/81222734?s=48&v=4');
+ */
+export const fetchFile = async function (url: string, init?: FetchInit) {
+ init = await makeInit(init);
+ console.log(url, init);
+ try {
+ const res = await fetch(url, init as RequestInit);
+ if (!res.ok) return '';
+ const arrayBuffer = await res.arrayBuffer();
+ return Buffer.from(arrayBuffer).toString('base64');
+ } catch (e) {
+ return '';
+ }
+};
+
+/**
+ *
+ * @param url
+ * @param init
+ * @param encoding default: `utf-8`. link: https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/encoding
+ * @returns plain text
+ * @example fetchText('https://github.com/LNReader/lnreader', {}, 'gbk');
+ */
+export const fetchText = async function (
+ url: string,
+ init?: FetchInit,
+ encoding?: string,
+): Promise {
+ init = await makeInit(init);
+ console.log(url, init);
+ try {
+ const res = await fetch(url, init as RequestInit);
+ if (!res.ok) return '';
+ const arrayBuffer = await res.arrayBuffer();
+ const decoder = new TextDecoder(encoding);
+ return decoder.decode(arrayBuffer);
+ } catch (e) {
+ return '';
+ }
+};
+
+type ProtoRequestInit = {
+ // merged .proto file
+ proto: string;
+ requestType: string;
+ requestData?: any;
+ responseType: string;
+};
+
+const BYTE_MARK = BigInt((1 << 8) - 1);
+
+export const fetchProto = async function (
+ protoInit: ProtoRequestInit,
+ url: string,
+ init?: FetchInit,
+) {
+ const protoRoot = parseProto(protoInit.proto).root;
+ const RequestMessge = protoRoot.lookupType(protoInit.requestType);
+ if (RequestMessge.verify(protoInit.requestData)) {
+ throw new Error('Invalid Proto');
+ }
+ // encode request data
+ const encodedrequest = RequestMessge.encode(protoInit.requestData).finish();
+ const requestLength = BigInt(encodedrequest.length);
+ const headers = new Uint8Array(
+ Array(5)
+ .fill(0)
+ .map((v, idx) => {
+ if (idx === 0) return 0;
+ return Number((requestLength >> BigInt(8 * (5 - idx - 1))) & BYTE_MARK);
+ }),
+ );
+ init = await makeInit(init);
+ const bodyArray = new Uint8Array(headers.length + encodedrequest.length);
+ bodyArray.set(headers, 0);
+ bodyArray.set(encodedrequest, headers.length);
+ return fetch(url, {
+ method: 'POST',
+ ...init,
+ body: bodyArray,
+ } as RequestInit)
+ .then(r => r.arrayBuffer())
+ .then(arr => {
+ // decode response data
+ const payload = new Uint8Array(arr);
+ const length = Number(
+ BigInt(payload[1] << 24) |
+ BigInt(payload[2] << 16) |
+ BigInt(payload[3] << 8) |
+ BigInt(payload[4]),
+ );
+ const ResponseMessage = protoRoot.lookupType(protoInit.responseType);
+ return ResponseMessage.decode(payload.slice(5, 5 + length));
+ }) as ReturnType;
+};
diff --git a/src/libs/storage.ts b/src/lib/storage.ts
similarity index 100%
rename from src/libs/storage.ts
rename to src/lib/storage.ts
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..30f5dbd
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,36 @@
+import { clsx, type ClassValue } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+/**
+ * Merges Tailwind CSS classes with clsx
+ */
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
+
+/**
+ * Checks if a URL is absolute
+ */
+export const isUrlAbsolute = (url: string) => {
+ if (url) {
+ if (url.indexOf('//') === 0) {
+ return true;
+ } // URL is protocol-relative (= absolute)
+ if (url.indexOf('://') === -1) {
+ return false;
+ } // URL has no protocol (= relative)
+ if (url.indexOf('.') === -1) {
+ return false;
+ } // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
+ if (url.indexOf('/') === -1) {
+ return false;
+ } // URL does not contain a single slash (= relative)
+ if (url.indexOf(':') > url.indexOf('/')) {
+ return false;
+ } // The first colon comes after the first slash (= relative)
+ if (url.indexOf('://') < url.indexOf('.')) {
+ return true;
+ } // Protocol is defined before first dot (= absolute)
+ }
+ return false; // Anything else must be relative
+};
diff --git a/src/libs/defaultCover.ts b/src/libs/defaultCover.ts
index 6052d11..f02172e 100644
--- a/src/libs/defaultCover.ts
+++ b/src/libs/defaultCover.ts
@@ -1,2 +1,5 @@
-export const defaultCover =
- 'https://github.com/LNReader/lnreader-plugins/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
+/**
+ * Backward compatibility for 3.0.0 - Re-exports from new location
+ * TODO: Remove in 4.0.0
+ */
+export { defaultCover } from '../types/constants';
diff --git a/src/libs/fetch.ts b/src/libs/fetch.ts
index 401d2b6..8d63d60 100644
--- a/src/libs/fetch.ts
+++ b/src/libs/fetch.ts
@@ -1,156 +1,5 @@
-/* global Buffer, RequestInit */
-
-import { parse as parseProto } from 'protobufjs';
-
-type FetchInit = {
- headers?: Record | Headers;
- method?: string;
- body?: FormData | string;
- [x: string]:
- | string
- | Record
- | undefined
- | FormData
- | Headers;
-};
-
-const makeInit = async (init?: FetchInit) => {
- const defaultHeaders: Record = {
- 'Connection': 'keep-alive',
- 'Accept': '*/*',
- 'Accept-Language': '*',
- 'Sec-Fetch-Mode': 'cors',
- 'Accept-Encoding': 'gzip, deflate',
- };
- if (init?.headers) {
- if (init.headers instanceof Headers) {
- for (const [name, value] of Object.entries(defaultHeaders)) {
- if (!init.headers.get(name)) init.headers.set(name, value);
- }
- } else {
- init.headers = {
- ...defaultHeaders,
- ...init.headers,
- };
- }
- } else {
- init = {
- ...init,
- headers: defaultHeaders,
- };
- }
- return init;
-};
-
/**
- * Fetch with (Android) User Agent
- * @param url
- * @param init
- * @returns response as normal fetch
+ * Backward compatibility for 3.0.0 - Re-exports from new location
+ * TODO: Remove in 4.0.0
*/
-export async function fetchApi(url: string, init?: FetchInit) {
- init = await makeInit(init);
- console.log(url, init);
- return await fetch(url, init as RequestInit);
-}
-
-/**
- *
- * @param url
- * @param init
- * @returns base64 string of file
- * @example fetchFile('https://avatars.githubusercontent.com/u/81222734?s=48&v=4');
- */
-export const fetchFile = async function (url: string, init?: FetchInit) {
- init = await makeInit(init);
- console.log(url, init);
- try {
- const res = await fetch(url, init as RequestInit);
- if (!res.ok) return '';
- const arrayBuffer = await res.arrayBuffer();
- return Buffer.from(arrayBuffer).toString('base64');
- } catch (e) {
- return '';
- }
-};
-
-/**
- *
- * @param url
- * @param init
- * @param encoding default: `utf-8`. link: https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/encoding
- * @returns plain text
- * @example fetchText('https://github.com/LNReader/lnreader', {}, 'gbk');
- */
-export const fetchText = async function (
- url: string,
- init?: FetchInit,
- encoding?: string,
-): Promise {
- init = await makeInit(init);
- console.log(url, init);
- try {
- const res = await fetch(url, init as RequestInit);
- if (!res.ok) return '';
- const arrayBuffer = await res.arrayBuffer();
- const decoder = new TextDecoder(encoding);
- return decoder.decode(arrayBuffer);
- } catch (e) {
- return '';
- }
-};
-
-type ProtoRequestInit = {
- // merged .proto file
- proto: string;
- requestType: string;
- requestData?: any;
- responseType: string;
-};
-
-const BYTE_MARK = BigInt((1 << 8) - 1);
-
-export const fetchProto = async function (
- protoInit: ProtoRequestInit,
- url: string,
- init?: FetchInit,
-) {
- const protoRoot = parseProto(protoInit.proto).root;
- const RequestMessge = protoRoot.lookupType(protoInit.requestType);
- if (RequestMessge.verify(protoInit.requestData)) {
- throw new Error('Invalid Proto');
- }
- // encode request data
- const encodedrequest = RequestMessge.encode(protoInit.requestData).finish();
- const requestLength = BigInt(encodedrequest.length);
- const headers = new Uint8Array(
- Array(5)
- .fill(0)
- .map((v, idx) => {
- if (idx === 0) return 0;
- return Number((requestLength >> BigInt(8 * (5 - idx - 1))) & BYTE_MARK);
- }),
- );
- init = await makeInit(init);
- const bodyArray = new Uint8Array(headers.length + encodedrequest.length);
- bodyArray.set(headers, 0);
- bodyArray.set(encodedrequest, headers.length);
- return fetch(url, {
- method: 'POST',
- ...init,
- body: bodyArray,
- } as RequestInit)
- .then(r => r.arrayBuffer())
- .then(arr => {
- // decode response data
- const payload = new Uint8Array(arr);
- const length = Number(
- BigInt(payload[1] << 24) |
- BigInt(payload[2] << 16) |
- BigInt(payload[3] << 8) |
- BigInt(payload[4]),
- );
- const ResponseMessage = protoRoot.lookupType(protoInit.responseType);
- return ResponseMessage.decode(payload.slice(5, 5 + length));
- }) as ReturnType;
-};
+export { fetchApi, fetchText, fetchProto, fetchFile } from '../lib/fetch';
diff --git a/src/libs/filterInputs.ts b/src/libs/filterInputs.ts
index 8cc7eeb..94f150c 100644
--- a/src/libs/filterInputs.ts
+++ b/src/libs/filterInputs.ts
@@ -1,130 +1,6 @@
/**
- * Filter's Options user can choose from
+ * Backward compatibility for 3.0.0 - Re-exports from new location
+ * TODO: Remove in 4.0.0
*/
-export type FilterOption = {
- readonly label: string;
- readonly value: string;
-};
-
-/**
- * Every currently implemented FilterType
- */
-export enum FilterTypes {
- TextInput = 'Text',
- Picker = 'Picker',
- CheckboxGroup = 'Checkbox',
- Switch = 'Switch',
- ExcludableCheckboxGroup = 'XCheckbox',
-}
-
-type SwitchFilter = {
- type: FilterTypes.Switch;
- /** Default value */
- value: boolean;
-};
-
-type TextFilter = {
- type: FilterTypes.TextInput;
- /** Default value */
- value: string;
-};
-
-type CheckboxFilter = {
- type: FilterTypes.CheckboxGroup;
- options: readonly FilterOption[];
- /** Default value */
- value: string[];
-};
-type PickerFilter = {
- type: FilterTypes.Picker;
- options: readonly FilterOption[];
- /** Default value */
- value: string;
-};
-
-type ExcludableCheckboxFilter = {
- type: FilterTypes.ExcludableCheckboxGroup;
- options: readonly FilterOption[];
- /** Default value */
- value: {
- /** Checkboxes marked as included */
- include?: string[];
- /** Checkboxes marked as excluded */
- exclude?: string[];
- };
-};
-
-/**
- * key - filter pairs
- */
-export type Filters = Record>;
-
-/** Mapping of each FilterType to a Filter */
-type FilterFromType = {
- [FilterTypes.CheckboxGroup]: CheckboxFilter;
- [FilterTypes.ExcludableCheckboxGroup]: ExcludableCheckboxFilter;
- [FilterTypes.Picker]: PickerFilter;
- [FilterTypes.Switch]: SwitchFilter;
- [FilterTypes.TextInput]: TextFilter;
-};
-
-/**
- * Get type of a single filter type from the {@link FilterType}
- */
-export type Filter = {
- label: string;
-} & FilterFromType[Type];
-
-/**
- * Strip {@link FilterObject} object from 'label' and 'options' to get key - filter_value pairs
- * @see {@link ValueOfFilter}
- */
-export type FilterToValues<
- FilterObject extends Record | undefined,
-> = FilterObject extends undefined
- ? undefined
- : {
- // copy the Filters object, but just get {value,type} pairs instead of the whole Filter object
- [SingleFilter in keyof FilterObject]: FilterValueWithType<
- FilterType[SingleFilter]>
- >;
- };
-
-/**
- * Get value type for a {@link Filter} given it's FilterType
- * @see {@link FilterTypes}
- */
-export type ValueOfFilter =
- T extends FilterTypes.CheckboxGroup
- ? CheckboxFilter['value']
- : T extends FilterTypes.Picker
- ? PickerFilter['value']
- : T extends FilterTypes.Switch
- ? SwitchFilter['value']
- : T extends FilterTypes.TextInput
- ? TextFilter['value']
- : T extends FilterTypes.ExcludableCheckboxGroup
- ? ExcludableCheckboxFilter['value']
- : never;
-
-/** Get {@link Filter}'s type */
-export type FilterType = T extends {
- type: infer K;
-}
- ? K extends FilterTypes
- ? K
- : never
- : never;
-
-/** Get {type, value} types for given FilterType
- * @see {@link ValueOfFilter}
- */
-export type FilterValueWithType = {
- type: T;
- value: ValueOfFilter;
-};
-
-/**
- * Any possible filter value
- */
-export type AnyFilterValue = ValueOfFilter;
+export { FilterTypes } from '../types/filters';
+export type { Filters, Filter } from '../types/filters';
diff --git a/src/libs/isAbsoluteUrl.ts b/src/libs/isAbsoluteUrl.ts
index 5f47249..2c97083 100644
--- a/src/libs/isAbsoluteUrl.ts
+++ b/src/libs/isAbsoluteUrl.ts
@@ -1,23 +1,5 @@
-export const isUrlAbsolute = (url: string) => {
- if (url) {
- if (url.indexOf('//') === 0) {
- return true;
- } // URL is protocol-relative (= absolute)
- if (url.indexOf('://') === -1) {
- return false;
- } // URL has no protocol (= relative)
- if (url.indexOf('.') === -1) {
- return false;
- } // URL does not contain a dot, i.e. no TLD (= relative, possibly REST)
- if (url.indexOf('/') === -1) {
- return false;
- } // URL does not contain a single slash (= relative)
- if (url.indexOf(':') > url.indexOf('/')) {
- return false;
- } // The first colon comes after the first slash (= relative)
- if (url.indexOf('://') < url.indexOf('.')) {
- return true;
- } // Protocol is defined before first dot (= absolute)
- }
- return false; // Anything else must be relative
-};
+/**
+ * Backward compatibility for 3.0.0 - Re-exports from new location
+ * TODO: Remove in 4.0.0
+ */
+export { isUrlAbsolute } from '../lib/utils';
diff --git a/src/libs/novelStatus.ts b/src/libs/novelStatus.ts
index b638dd3..688bb38 100644
--- a/src/libs/novelStatus.ts
+++ b/src/libs/novelStatus.ts
@@ -1,9 +1,5 @@
-export const NovelStatus = {
- Unknown: 'Unknown',
- Ongoing: 'Ongoing',
- Completed: 'Completed',
- Licensed: 'Licensed',
- PublishingFinished: 'Publishing Finished',
- Cancelled: 'Cancelled',
- OnHiatus: 'On Hiatus',
-} as const;
+/**
+ * Backward compatibility for 3.0.0 - Re-exports from new location
+ * TODO: Remove in 4.0.0
+ */
+export { NovelStatus } from '../types/constants';
diff --git a/src/main.tsx b/src/main.tsx
index c5e24aa..97a1db2 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,17 +1,16 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import '@fontsource/roboto/300.css';
-import '@fontsource/roboto/400.css';
-import '@fontsource/roboto/500.css';
-import '@fontsource/roboto/700.css';
import 'cheerio';
import 'htmlparser2';
import 'dayjs';
import 'protobufjs';
+import './index.css';
+
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+
+import App from './App';
const { fetch: originalFetch } = window;
+
window.fetch = async (...args) => {
const [resource, config] = args;
if (resource.toString().includes('localhost'))
diff --git a/src/pages/home.tsx b/src/pages/home.tsx
new file mode 100644
index 0000000..d4fcb94
--- /dev/null
+++ b/src/pages/home.tsx
@@ -0,0 +1,160 @@
+import React, { useMemo, useState } from 'react';
+
+import { BookOpen, Search, Settings, Zap } from 'lucide-react';
+import PluginHeader from '../components/plugin-header';
+
+import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
+import { Input } from '@/components/ui/input';
+
+import plugins from '@plugins/index';
+import { useAppStore } from '@/store';
+import PopularNovelsSection from '@/components/popular-novels';
+import SearchNovelsSection from '@/components/search-novels';
+import ParseNovelSection from '@/components/parse-novel';
+import SettingsSection from '@/components/settings';
+import ParseChapterSection from '@/components/parse-chapter';
+
+function Home() {
+ const { plugin, selectPlugin } = useAppStore(state => state);
+ const [searchQuery, setSearchQuery] = useState('');
+
+ const [activeTab, setActiveTab] = useState('popular');
+
+ const filteredPlugins = useMemo(
+ () =>
+ plugins.filter(plugin =>
+ plugin.name.toLowerCase().includes(searchQuery.toLowerCase()),
+ ),
+ [searchQuery],
+ );
+
+ return (
+
+
+
+
+
+
+
+ Plugins
+
+
+ {filteredPlugins.length}
+
+
+
+
+ setSearchQuery(e.target.value)}
+ className="pl-10 h-9"
+ />
+
+
+
+
+ {filteredPlugins.map(filteredPlugin => (
+ selectPlugin(filteredPlugin)}
+ className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${
+ filteredPlugin.id === plugin?.id
+ ? 'bg-primary text-primary-foreground'
+ : 'text-foreground hover:bg-muted'
+ }`}
+ >
+ {filteredPlugin.name}
+
+ ))}
+
+
+
+
+ {/* Main Content */}
+
+
+
+
+ Plugin Playground
+
+
+ Explore and test {plugin?.name || 'plugin'} features
+
+
+
+ {/* Tabs */}
+
+
+
+
+ Popular
+
+
+
+ Search
+
+
+
+ Parse Novel
+
+
+
+ Parse Chapter
+
+
+
+ Settings
+
+
+
+
+ setActiveTab('parse-novel')}
+ />
+
+
+
+ setActiveTab('parse-novel')}
+ />
+
+
+
+ setActiveTab('parse-chapter')}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Home;
diff --git a/src/plugins/index.d.ts b/src/plugins/index.d.ts
deleted file mode 100644
index 3421420..0000000
--- a/src/plugins/index.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { Plugin } from '../types/plugin';
-
-declare const PLUGINS: Plugin.PluginItem[];
-export default PLUGINS;
diff --git a/src/provider/DialogProvider/index.tsx b/src/provider/DialogProvider/index.tsx
deleted file mode 100644
index 1a14d02..0000000
--- a/src/provider/DialogProvider/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react';
-// import { useAppStore } from '@store';
-
-export default function DialogProvider() {
- // const _activeDialogs = useAppStore(state => state.activeDialogs);
-
- return <>>;
-}
diff --git a/src/provider/index.tsx b/src/provider/index.tsx
deleted file mode 100644
index 8dbb044..0000000
--- a/src/provider/index.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import DialogProvider from './DialogProvider';
-import { Backdrop, Box, CircularProgress, Container } from '@mui/material';
-import { useAppStore } from '@store';
-
-export default function AppProvider() {
- const loading = useAppStore(state => state.loading);
- return (
-
- theme.zIndex.appBar + 1 }}
- >
-
-
-
-
-
-
- );
-}
diff --git a/src/provider/plugins.ts b/src/provider/plugins.ts
index 1b84a33..fd1822d 100644
--- a/src/provider/plugins.ts
+++ b/src/provider/plugins.ts
@@ -1,4 +1,4 @@
-import plugins from '../plugins';
+import plugins from '@plugins/index';
export const searchPlugins = (keyword: string) => {
return plugins.filter(
diff --git a/src/store/index.ts b/src/store/index.ts
index 35babcf..3ef2700 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -2,10 +2,15 @@ import { create, StateCreator } from 'zustand';
import { PluginStore } from './pluginStore';
import { DialogStore } from './dialogStore';
import { OverlayStore } from './overlayStore';
+import { NavigationStore } from './navigationStore';
export type AppStore = DialogStore &
OverlayStore &
- PluginStore & { useSwitches: boolean; setUseSwitches(value: boolean): void };
+ PluginStore &
+ NavigationStore & {
+ useSwitches: boolean;
+ setUseSwitches(value: boolean): void;
+ };
// Helper types to use "slicing" like in Redux... We could just not use slicing, but eh
export type SetStore = Parameters>[0];
@@ -16,6 +21,7 @@ export const useAppStore = create((set: SetStore, get: GetStore) => ({
...DialogStore(set, get),
...OverlayStore(set, get),
...PluginStore(set, get),
+ ...NavigationStore(set, get),
useSwitches: !!localStorage.getItem('useSwitches'),
setUseSwitches(uS: boolean) {
set(state => ({
diff --git a/src/store/navigationStore.ts b/src/store/navigationStore.ts
new file mode 100644
index 0000000..460da11
--- /dev/null
+++ b/src/store/navigationStore.ts
@@ -0,0 +1,55 @@
+import { StoreCreator } from '.';
+
+export type NavigationStore = {
+ parseNovelPath?: string;
+ parseChapterPath?: string;
+ shouldAutoSubmitNovel: boolean;
+ shouldAutoSubmitChapter: boolean;
+ setParseNovelPath(path: string, autoSubmit?: boolean): void;
+ clearParseNovelPath(): void;
+ setParseChapterPath(path: string, autoSubmit?: boolean): void;
+ clearParseChapterPath(): void;
+};
+
+/**
+ * @param set State setter for use inside actions
+ * @param get State getter for use inside actions, outside of State setter
+ */
+export const NavigationStore: StoreCreator = set => ({
+ parseNovelPath: undefined,
+ parseChapterPath: undefined,
+ shouldAutoSubmitNovel: false,
+ shouldAutoSubmitChapter: false,
+
+ setParseNovelPath(path: string, autoSubmit = true) {
+ set(state => ({
+ ...state,
+ parseNovelPath: path,
+ shouldAutoSubmitNovel: autoSubmit,
+ }));
+ },
+
+ clearParseNovelPath() {
+ set(state => ({
+ ...state,
+ parseNovelPath: undefined,
+ shouldAutoSubmitNovel: false,
+ }));
+ },
+
+ setParseChapterPath(path: string, autoSubmit = true) {
+ set(state => ({
+ ...state,
+ parseChapterPath: path,
+ shouldAutoSubmitChapter: autoSubmit,
+ }));
+ },
+
+ clearParseChapterPath() {
+ set(state => ({
+ ...state,
+ parseChapterPath: undefined,
+ shouldAutoSubmitChapter: false,
+ }));
+ },
+});
diff --git a/src/store/pluginStore.ts b/src/store/pluginStore.ts
index c154e1d..f6afb14 100644
--- a/src/store/pluginStore.ts
+++ b/src/store/pluginStore.ts
@@ -1,11 +1,27 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
import { StoreCreator } from '.';
-import { getPlugin } from '@provider/plugins';
+import { getPlugin } from '@/provider/plugins';
+import plugins from '@plugins/index';
export type PluginStore = {
pluginItem?: Plugin.PluginItem;
plugin?: Plugin.PluginBase;
- selectPlugin(plugin: Plugin.PluginItem): void;
+ selectPlugin(plugin: Plugin.PluginItem, updateURL?: boolean): void;
+};
+
+const loadPluginFromURL = () => {
+ const urlParams = new URLSearchParams(window.location.search);
+ const pluginId = urlParams.get('plugin');
+ if (pluginId) {
+ const pluginItem = plugins.find(p => p.id === pluginId);
+ if (pluginItem) {
+ return {
+ pluginItem,
+ plugin: getPlugin(pluginItem.id),
+ };
+ }
+ }
+ return {};
};
/**
@@ -13,15 +29,19 @@ export type PluginStore = {
* @param get State getter for use inside actions, outside of State setter
*/
export const PluginStore: StoreCreator = set => ({
- // this is initial state
- // selectedPlugin: undefined,
+ ...loadPluginFromURL(),
- // those are actions
- selectPlugin(pluginItem) {
+ selectPlugin(pluginItem, updateURL = true) {
set(state => ({
...state,
pluginItem,
plugin: getPlugin(pluginItem.id),
}));
+
+ if (updateURL) {
+ const url = new URL(window.location.href);
+ url.searchParams.set('plugin', pluginItem.id);
+ window.history.pushState({}, '', url);
+ }
},
});
diff --git a/src/types/constants.ts b/src/types/constants.ts
new file mode 100644
index 0000000..b81c50c
--- /dev/null
+++ b/src/types/constants.ts
@@ -0,0 +1,12 @@
+export const NovelStatus = {
+ Unknown: 'Unknown',
+ Ongoing: 'Ongoing',
+ Completed: 'Completed',
+ Licensed: 'Licensed',
+ PublishingFinished: 'Publishing Finished',
+ Cancelled: 'Cancelled',
+ OnHiatus: 'On Hiatus',
+} as const;
+
+export const defaultCover =
+ 'https://github.com/LNReader/lnreader-plugins/blob/main/icons/src/coverNotAvailable.jpg?raw=true';
diff --git a/src/types/filters.ts b/src/types/filters.ts
new file mode 100644
index 0000000..8cc7eeb
--- /dev/null
+++ b/src/types/filters.ts
@@ -0,0 +1,130 @@
+/**
+ * Filter's Options user can choose from
+ */
+export type FilterOption = {
+ readonly label: string;
+ readonly value: string;
+};
+
+/**
+ * Every currently implemented FilterType
+ */
+export enum FilterTypes {
+ TextInput = 'Text',
+ Picker = 'Picker',
+ CheckboxGroup = 'Checkbox',
+ Switch = 'Switch',
+ ExcludableCheckboxGroup = 'XCheckbox',
+}
+
+type SwitchFilter = {
+ type: FilterTypes.Switch;
+ /** Default value */
+ value: boolean;
+};
+
+type TextFilter = {
+ type: FilterTypes.TextInput;
+ /** Default value */
+ value: string;
+};
+
+type CheckboxFilter = {
+ type: FilterTypes.CheckboxGroup;
+ options: readonly FilterOption[];
+ /** Default value */
+ value: string[];
+};
+type PickerFilter = {
+ type: FilterTypes.Picker;
+ options: readonly FilterOption[];
+ /** Default value */
+ value: string;
+};
+
+type ExcludableCheckboxFilter = {
+ type: FilterTypes.ExcludableCheckboxGroup;
+ options: readonly FilterOption[];
+ /** Default value */
+ value: {
+ /** Checkboxes marked as included */
+ include?: string[];
+ /** Checkboxes marked as excluded */
+ exclude?: string[];
+ };
+};
+
+/**
+ * key - filter pairs
+ */
+export type Filters = Record>;
+
+/** Mapping of each FilterType to a Filter */
+type FilterFromType = {
+ [FilterTypes.CheckboxGroup]: CheckboxFilter;
+ [FilterTypes.ExcludableCheckboxGroup]: ExcludableCheckboxFilter;
+ [FilterTypes.Picker]: PickerFilter;
+ [FilterTypes.Switch]: SwitchFilter;
+ [FilterTypes.TextInput]: TextFilter;
+};
+
+/**
+ * Get type of a single filter type from the {@link FilterType}
+ */
+export type Filter = {
+ label: string;
+} & FilterFromType[Type];
+
+/**
+ * Strip {@link FilterObject} object from 'label' and 'options' to get key - filter_value pairs
+ * @see {@link ValueOfFilter}
+ */
+export type FilterToValues<
+ FilterObject extends Record | undefined,
+> = FilterObject extends undefined
+ ? undefined
+ : {
+ // copy the Filters object, but just get {value,type} pairs instead of the whole Filter object
+ [SingleFilter in keyof FilterObject]: FilterValueWithType<
+ FilterType[SingleFilter]>
+ >;
+ };
+
+/**
+ * Get value type for a {@link Filter} given it's FilterType
+ * @see {@link FilterTypes}
+ */
+export type ValueOfFilter =
+ T extends FilterTypes.CheckboxGroup
+ ? CheckboxFilter['value']
+ : T extends FilterTypes.Picker
+ ? PickerFilter['value']
+ : T extends FilterTypes.Switch
+ ? SwitchFilter['value']
+ : T extends FilterTypes.TextInput
+ ? TextFilter['value']
+ : T extends FilterTypes.ExcludableCheckboxGroup
+ ? ExcludableCheckboxFilter['value']
+ : never;
+
+/** Get {@link Filter}'s type */
+export type FilterType = T extends {
+ type: infer K;
+}
+ ? K extends FilterTypes
+ ? K
+ : never
+ : never;
+
+/** Get {type, value} types for given FilterType
+ * @see {@link ValueOfFilter}
+ */
+export type FilterValueWithType = {
+ type: T;
+ value: ValueOfFilter;
+};
+
+/**
+ * Any possible filter value
+ */
+export type AnyFilterValue = ValueOfFilter;
diff --git a/src/types/types.ts b/src/types/types.ts
index a6917da..2fc7ca7 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -1,4 +1,4 @@
-import { Plugin } from '@typings/plugin';
+import { Plugin } from '@/types/plugin';
export type PluginList = Record;
@@ -8,11 +8,11 @@ export enum FetchMode {
CURL,
}
-export interface ServerSetting {
+export type ServerSetting = {
CLIENT_HOST: string;
fetchMode: FetchMode;
cookies?: string;
disAllowedRequestHeaders: string[];
disAllowResponseHeaders: string[];
useUserAgent: boolean;
-}
+};
diff --git a/tsconfig.json b/tsconfig.json
index d27f2c2..2b36321 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -33,18 +33,11 @@
"module": "ES2020" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */,
- "baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
+ "baseUrl": "." /* Specify the base directory to resolve non-relative module names. */,
"paths": {
- "@libs/*": ["./src/libs/*"],
- "@icons/*": ["./src/icons/*"],
- "@components/*": ["./src/components/*"],
- "@redux/*": ["./src/redux/*"],
- "@provider/*": ["./src/provider/*"],
- "@plugins/*": ["./src/plugins/*"],
- "@hooks/*": ["./src/hooks/*"],
- "@scripts/*": ["./scripts/*"],
- "@typings/*": ["./src/types/*"],
- "@store": ["./src/store"]
+ "@/*": ["./src/*"],
+ "@plugins/*": ["./plugins/*"],
+ "@libs/*": ["./src/libs/*"]
} /* Specify a set of entries that re-map imports to additional lookup locations. */,
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
@@ -125,5 +118,5 @@
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
- "exclude": ["./src/plugins/**/*.broken.ts", "./.js/**/*", "scripts", "docs"]
+ "exclude": ["./plugins/**/*.broken.ts", "./.js/**/*", "scripts", "docs"]
}
diff --git a/tsconfig.production.json b/tsconfig.production.json
index 3250b6e..f611c99 100644
--- a/tsconfig.production.json
+++ b/tsconfig.production.json
@@ -1,159 +1,127 @@
{
- "compilerOptions": {
- "jsx": "react",
- /* Visit https://aka.ms/tsconfig to read more about this file */
- /* Projects */
- // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
- // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
- // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
- // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
- // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
- // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
- /* Language and Environment */
- "target": "ES5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
- // "lib": [
- // "es2016",
- // "dom",
- // "es5"
- // ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
- // "jsx": "preserve", /* Specify what JSX code is generated. */
- // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
- // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
- // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
- // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
- // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
- // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
- // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
- // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
- // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
- /* Modules */
- "module": "CommonJS" /* Specify what module code is generated. */,
- // "rootDir": "./", /* Specify the root folder within your source files. */
- "moduleResolution": "node10" /* Specify how TypeScript looks up a file from a given module specifier. */,
- "baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */,
- "paths": {
- "@libs/*": [
- "./src/libs/*"
- ],
- "@icons/*": [
- "./src/icons/*"
- ],
- "@components/*": [
- "./src/components/*"
- ],
- "@redux/*": [
- "./src/redux/*"
- ],
- "@provider/*": [
- "./src/provider/*"
- ],
- "@plugins/*": [
- "./src/plugins/*"
- ],
- "@hooks/*": [
- "./src/hooks/*"
- ],
- "@scripts/*": [
- "./scripts/*"
- ],
- "@typings/*": [
- "./src/types/*"
- ],
- "@store": [
- "./src/store"
- ]
- } /* Specify a set of entries that re-map imports to additional lookup locations. */,
- // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
- // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
- // "types": [], /* Specify type package names to be included without being referenced in a source file. */
- // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
- // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
- // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
- // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
- // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
- // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
- "resolveJsonModule": true /* Enable importing .json files. */,
- // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
- // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
- /* JavaScript Support */
- // "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
- // "checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
- // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
- /* Emit */
- // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
- // "declarationMap": true, /* Create sourcemaps for d.ts files. */
- // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
- // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
- // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
- // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
- "outDir": "./.js/src/plugins" /* Specify an output folder for all emitted files. */,
- // "removeComments": true, /* Disable emitting comments. */
- // "noEmit": true, /* Disable emitting files from a compilation. */
- // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
- // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
- // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
- // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
- // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
- // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
- // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
- // "newLine": "crlf", /* Set the newline character for emitting files. */
- // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
- // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
- // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
- // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
- // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
- // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
- "allowJs": true,
- "checkJs": false,
- /* Interop Constraints */
- // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
- // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
- // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
- "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
- // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
- "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
- /* Type Checking */
- "strict": true /* Enable all strict type-checking options. */,
- // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
- // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
- // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
- // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
- // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
- // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
- // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
- // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
- // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
- // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
- // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
- // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
- // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
- // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
- // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
- // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
- // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
- // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
- /* Completeness */
- // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
- "skipLibCheck": true /* Skip type checking all .d.ts files. */,
- "noCheck": true,
- "noResolve": true,
- },
- "exclude": [
- "./src/plugins/**/*.broken.ts",
- "./.js/**/*",
- "scripts/**",
- "docs/**",
- "./src/*.*",
- "./*.*",
- "public/**",
- ".github/**",
- ".husky/**",
- "node_modules/**",
- "./src/components/**",
- "./src/hooks/**",
- "./src/libs/**",
- "./src/provider/**",
- "./src/store/**",
- "./src/types/**"
- ],
-}
\ No newline at end of file
+ "compilerOptions": {
+ "jsx": "react",
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+ /* Projects */
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+ /* Language and Environment */
+ "target": "ES5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
+ // "lib": [
+ // "es2016",
+ // "dom",
+ // "es5"
+ // ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+ /* Modules */
+ "module": "CommonJS" /* Specify what module code is generated. */,
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ "moduleResolution": "node10" /* Specify how TypeScript looks up a file from a given module specifier. */,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"],
+ "@plugins/*": ["./plugins/*"],
+ "@libs/*": ["./src/libs/*"]
+ } /* Specify a set of entries that re-map imports to additional lookup locations. */,
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
+ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
+ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
+ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
+ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
+ "resolveJsonModule": true /* Enable importing .json files. */,
+ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
+ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
+ /* JavaScript Support */
+ // "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
+ // "checkJs": true /* Enable error reporting in type-checked JavaScript files. */,
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+ "outDir": "./.js/plugins" /* Specify an output folder for all emitted files. */,
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+ "allowJs": true,
+ "checkJs": false,
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
+ /* Type Checking */
+ "strict": true /* Enable all strict type-checking options. */,
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */,
+ "noCheck": true,
+ "noResolve": true
+ },
+ "exclude": [
+ "./plugins/**/*.broken.ts",
+ "./.js/**/*",
+ "scripts/**",
+ "docs/**",
+ "./src/*.*",
+ "./*.*",
+ "public/**",
+ ".github/**",
+ ".husky/**",
+ "node_modules/**",
+ "./src/**"
+ ]
+}
diff --git a/vite.config.ts b/vite.config.ts
index 17aa199..be79628 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react-swc';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import path from 'path';
import { fileURLToPath } from 'url';
+import tailwindcss from '@tailwindcss/vite';
import { proxyHandlerMiddle, proxySettingMiddleware } from './proxy';
const dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -10,6 +11,7 @@ const dirname = path.dirname(fileURLToPath(import.meta.url));
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
+ tailwindcss(),
nodePolyfills(),
react({ devTarget: 'es5' }),
{
@@ -22,16 +24,9 @@ export default defineConfig({
],
resolve: {
alias: {
+ '@': path.resolve(dirname, './src'),
+ '@plugins': path.resolve(dirname, './plugins'),
'@libs': path.resolve(dirname, './src/libs'),
- '@icons': path.resolve(dirname, './src/icons'),
- '@components': path.resolve(dirname, './src/components'),
- '@redux': path.resolve(dirname, './src/redux'),
- '@provider': path.resolve(dirname, './src/provider'),
- '@plugins': path.resolve(dirname, './src/plugins'),
- '@hooks': path.resolve(dirname, './src/hooks'),
- '@typings': path.resolve(dirname, './src/types'),
- '@scripts': path.resolve(dirname, './scripts'),
- '@store': path.resolve(dirname, './src/store'),
},
},
server: {