Migrate to oxlint + oxfmt
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ build/*
|
||||
dev-dist/*
|
||||
|
||||
src/lib/graphql/schema.json
|
||||
.oxlintrc.jsonc
|
||||
10
.oxfmtrc.json
Normal file
10
.oxfmtrc.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"ignorePatterns": ["src/lib/graphql/generated/**", ".github/**"]
|
||||
}
|
||||
483
.oxlintrc.jsonc
Normal file
483
.oxlintrc.jsonc
Normal file
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"plugins": [
|
||||
"react",
|
||||
"typescript",
|
||||
"import",
|
||||
"jsx-a11y"
|
||||
],
|
||||
"jsPlugins": [
|
||||
"eslint-plugin-lingui",
|
||||
"eslint-plugin-no-relative-import-paths"
|
||||
],
|
||||
"categories": {
|
||||
"correctness": "off"
|
||||
},
|
||||
"rules": {
|
||||
// ── Core JS: correctness (from js.configs.recommended) ──
|
||||
"constructor-super": "error",
|
||||
"for-direction": "error",
|
||||
"getter-return": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-case-declarations": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-compare-neg-zero": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-constant-binary-expression": "error",
|
||||
"no-constant-condition": "error",
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "error",
|
||||
"no-delete-var": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty": "error",
|
||||
"no-empty-character-class": "error",
|
||||
"no-empty-pattern": "error",
|
||||
"no-empty-static-block": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-global-assign": "error",
|
||||
"no-import-assign": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-new-native-nonconstructor": "error",
|
||||
"no-nonoctal-decimal-escape": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-self-assign": "error",
|
||||
"no-setter-return": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-this-before-super": "error",
|
||||
"no-undef": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-unused-private-class-members": "error",
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"vars": "all",
|
||||
"args": "after-used",
|
||||
"ignoreRestSiblings": true,
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"caughtErrorsIgnorePattern": "^_|^e$|^error$"
|
||||
}
|
||||
],
|
||||
"no-useless-backreference": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-with": "error",
|
||||
"require-yield": "error",
|
||||
"use-isnan": "error",
|
||||
"valid-typeof": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-unused-expressions": "error",
|
||||
|
||||
// ── Core JS: Airbnb-style rules ──
|
||||
"no-console": "warn",
|
||||
"no-nested-ternary": "error",
|
||||
"no-else-return": [
|
||||
"error",
|
||||
{
|
||||
"allowElseIf": false
|
||||
}
|
||||
],
|
||||
"no-lonely-if": "error",
|
||||
"no-unneeded-ternary": [
|
||||
"error",
|
||||
{
|
||||
"defaultAssignment": false
|
||||
}
|
||||
],
|
||||
"no-multi-assign": "error",
|
||||
"no-return-assign": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-sequences": "error",
|
||||
"no-new": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-eval": "error",
|
||||
"no-script-url": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-proto": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-caller": "error",
|
||||
"no-alert": "warn",
|
||||
"no-void": "error",
|
||||
"no-bitwise": "error",
|
||||
"no-continue": "error",
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
"isFinite",
|
||||
"isNaN"
|
||||
],
|
||||
"no-await-in-loop": "error",
|
||||
"no-promise-executor-return": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-constructor-return": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-return": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-rename": "error",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "ignore"
|
||||
}
|
||||
],
|
||||
"guard-for-in": "error",
|
||||
"default-case": [
|
||||
"error",
|
||||
{
|
||||
"commentPattern": "^no default$"
|
||||
}
|
||||
],
|
||||
"default-case-last": "error",
|
||||
"radix": "error",
|
||||
"yoda": "error",
|
||||
"max-classes-per-file": [
|
||||
"error",
|
||||
1
|
||||
],
|
||||
"prefer-template": "error",
|
||||
"prefer-destructuring": [
|
||||
"error",
|
||||
{
|
||||
"VariableDeclarator": {
|
||||
"array": false,
|
||||
"object": true
|
||||
},
|
||||
"AssignmentExpression": {
|
||||
"array": true,
|
||||
"object": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"enforceForRenamedProperties": false
|
||||
}
|
||||
],
|
||||
"prefer-exponentiation-operator": "error",
|
||||
"prefer-object-spread": "error",
|
||||
"prefer-promise-reject-errors": [
|
||||
"error",
|
||||
{
|
||||
"allowEmptyReject": true
|
||||
}
|
||||
],
|
||||
"no-param-reassign": [
|
||||
"error",
|
||||
{
|
||||
"props": true,
|
||||
"ignorePropertyModificationsForRegex": [
|
||||
"^draft"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-plusplus": [
|
||||
"error",
|
||||
{
|
||||
"allowForLoopAfterthoughts": true
|
||||
}
|
||||
],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"@mui/*",
|
||||
"!@mui/material/",
|
||||
"!@mui/icons-material/",
|
||||
"!@mui/x-date-pickers/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": [
|
||||
"@mui/*/*/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
// ── TypeScript rules (non-type-checked) ──
|
||||
"no-shadow": "error",
|
||||
"no-loop-func": "error",
|
||||
"no-use-before-define": [
|
||||
"error",
|
||||
{
|
||||
"functions": false,
|
||||
"classes": true,
|
||||
"variables": true
|
||||
}
|
||||
],
|
||||
"default-param-last": "error",
|
||||
|
||||
// ── TypeScript rules from recommended ──
|
||||
"typescript/no-duplicate-enum-values": "error",
|
||||
"typescript/no-extra-non-null-assertion": "error",
|
||||
"typescript/no-misused-new": "error",
|
||||
"typescript/no-namespace": "error",
|
||||
"typescript/no-non-null-asserted-optional-chain": "error",
|
||||
"typescript/no-require-imports": "error",
|
||||
"typescript/no-this-alias": "error",
|
||||
"typescript/no-unnecessary-type-constraint": "error",
|
||||
"typescript/no-unsafe-declaration-merging": "error",
|
||||
"typescript/no-wrapper-object-types": "error",
|
||||
"typescript/prefer-as-const": "error",
|
||||
"typescript/prefer-namespace-keyword": "error",
|
||||
"typescript/triple-slash-reference": "error",
|
||||
|
||||
// ── TypeScript rules (type-checked) ──
|
||||
"typescript/no-implied-eval": "error",
|
||||
"typescript/only-throw-error": "error",
|
||||
"typescript/dot-notation": "error",
|
||||
"typescript/return-await": [
|
||||
"error",
|
||||
"in-try-catch"
|
||||
],
|
||||
|
||||
// ── Import rules ──
|
||||
"import/namespace": "error",
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/no-duplicates": "warn",
|
||||
"import/no-mutable-exports": "error",
|
||||
"import/first": "error",
|
||||
"import/no-amd": "error",
|
||||
"import/no-absolute-path": "error",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-default-export": "error",
|
||||
|
||||
// ── Lingui (via jsPlugin) ──
|
||||
"lingui/t-call-in-function": "error",
|
||||
"lingui/no-single-tag-to-translate": "warn",
|
||||
"lingui/no-single-variables-to-translate": "warn",
|
||||
"lingui/no-trans-inside-trans": "warn",
|
||||
"lingui/no-expression-in-message": "off",
|
||||
|
||||
// ── Header — handled by minimal ESLint fallback ──
|
||||
|
||||
// ── No relative import paths (via jsPlugin) ──
|
||||
"no-relative-import-paths/no-relative-import-paths": [
|
||||
"error",
|
||||
{
|
||||
"rootDir": "src",
|
||||
"prefix": "@"
|
||||
}
|
||||
],
|
||||
|
||||
// ── React rules ──
|
||||
"react/jsx-key": "error",
|
||||
"react/jsx-no-comment-textnodes": "error",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-no-undef": "error",
|
||||
"react/no-children-prop": "error",
|
||||
"react/no-danger-with-children": "error",
|
||||
"react/no-direct-mutation-state": "error",
|
||||
"react/no-find-dom-node": "error",
|
||||
"react/no-is-mounted": "error",
|
||||
"react/no-render-return-value": "error",
|
||||
"react/no-string-refs": "error",
|
||||
"react/no-unescaped-entities": "error",
|
||||
"react/no-unknown-property": "error",
|
||||
"react/require-render-return": "error",
|
||||
"react/rules-of-hooks": "error",
|
||||
"react/no-array-index-key": "error",
|
||||
"react/jsx-no-useless-fragment": "error",
|
||||
"react/jsx-no-constructed-context-values": "error",
|
||||
"react/self-closing-comp": "error",
|
||||
"react/jsx-boolean-value": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"react/jsx-pascal-case": [
|
||||
"error",
|
||||
{
|
||||
"allowAllCaps": true
|
||||
}
|
||||
],
|
||||
"react/button-has-type": "error",
|
||||
"react/jsx-curly-brace-presence": [
|
||||
"error",
|
||||
{
|
||||
"props": "never",
|
||||
"children": "never"
|
||||
}
|
||||
],
|
||||
"react/jsx-fragments": [
|
||||
"error",
|
||||
"syntax"
|
||||
],
|
||||
"react/jsx-no-script-url": "error",
|
||||
"react/style-prop-object": "error",
|
||||
"react/void-dom-elements-no-children": "error",
|
||||
"react/no-danger": "warn",
|
||||
"react/no-this-in-sfc": "error",
|
||||
"react/state-in-constructor": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
|
||||
// ── jsx-a11y rules ──
|
||||
"jsx_a11y/alt-text": "error",
|
||||
"jsx_a11y/anchor-has-content": "error",
|
||||
"jsx_a11y/anchor-is-valid": "error",
|
||||
"jsx_a11y/aria-activedescendant-has-tabindex": "error",
|
||||
"jsx_a11y/aria-props": "error",
|
||||
"jsx_a11y/aria-proptypes": "error",
|
||||
"jsx_a11y/aria-role": "error",
|
||||
"jsx_a11y/aria-unsupported-elements": "error",
|
||||
"jsx_a11y/autocomplete-valid": "error",
|
||||
"jsx_a11y/click-events-have-key-events": "error",
|
||||
"jsx_a11y/heading-has-content": "error",
|
||||
"jsx_a11y/html-has-lang": "error",
|
||||
"jsx_a11y/iframe-has-title": "error",
|
||||
"jsx_a11y/img-redundant-alt": "error",
|
||||
"jsx_a11y/label-has-associated-control": "error",
|
||||
"jsx_a11y/media-has-caption": "error",
|
||||
"jsx_a11y/mouse-events-have-key-events": "error",
|
||||
"jsx_a11y/no-access-key": "error",
|
||||
"jsx_a11y/no-autofocus": [
|
||||
"error",
|
||||
{
|
||||
"ignoreNonDOM": true
|
||||
}
|
||||
],
|
||||
"jsx_a11y/no-distracting-elements": "error",
|
||||
"jsx_a11y/no-noninteractive-tabindex": [
|
||||
"error",
|
||||
{
|
||||
"tags": [],
|
||||
"roles": [
|
||||
"tabpanel"
|
||||
],
|
||||
"allowExpressionValues": true
|
||||
}
|
||||
],
|
||||
"jsx_a11y/no-redundant-roles": "error",
|
||||
"jsx_a11y/no-static-element-interactions": [
|
||||
"error",
|
||||
{
|
||||
"allowExpressionValues": true,
|
||||
"handlers": [
|
||||
"onClick",
|
||||
"onMouseDown",
|
||||
"onMouseUp",
|
||||
"onKeyPress",
|
||||
"onKeyDown",
|
||||
"onKeyUp"
|
||||
]
|
||||
}
|
||||
],
|
||||
"jsx_a11y/role-has-required-aria-props": "error",
|
||||
"jsx_a11y/role-supports-aria-props": "error",
|
||||
"jsx_a11y/scope": "error",
|
||||
"jsx_a11y/tabindex-no-positive": "error"
|
||||
},
|
||||
"settings": {
|
||||
"jsx-a11y": {
|
||||
"components": {},
|
||||
"attributes": {}
|
||||
},
|
||||
"next": {
|
||||
"rootDir": []
|
||||
},
|
||||
"react": {
|
||||
"formComponents": [],
|
||||
"linkComponents": [],
|
||||
"version": "19.2.0",
|
||||
"componentWrapperFunctions": []
|
||||
},
|
||||
"jsdoc": {
|
||||
"ignorePrivate": false,
|
||||
"ignoreInternal": false,
|
||||
"ignoreReplacesDocs": true,
|
||||
"overrideReplacesDocs": true,
|
||||
"augmentsExtendsReplacesDocs": false,
|
||||
"implementsReplacesDocs": false,
|
||||
"exemptDestructuredRootsFromChecks": false,
|
||||
"tagNamePreference": {}
|
||||
},
|
||||
"vitest": {
|
||||
"typecheck": false
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"builtin": true
|
||||
},
|
||||
"globals": {},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"src/base/components/settings/NumberSetting.tsx",
|
||||
"src/base/utils/MediaQuery.tsx",
|
||||
"src/features/authentication/AuthManager.ts",
|
||||
"src/features/browse/extensions/components/ExtensionCard.tsx",
|
||||
"src/features/chapter/services/Chapters.ts",
|
||||
"src/features/extension/info/components/ActionButton.tsx",
|
||||
"src/features/manga/components/TrackMangaButton.tsx",
|
||||
"src/features/manga/services/Mangas.ts",
|
||||
"src/features/metadata/services/MetadataMigrations.ts",
|
||||
"src/features/migration/components/MigrateDialog.tsx",
|
||||
"src/features/navigation-bar/components/MobileBottomBar.tsx",
|
||||
"src/features/reader/services/ReaderControls.ts",
|
||||
"src/features/reader/services/ReaderService.ts",
|
||||
"src/features/settings/screens/ImageProcessingSetting.tsx",
|
||||
"src/features/source/browse/components/SourceOptions.tsx",
|
||||
"src/features/source/browse/components/filters/SelectFilter.tsx",
|
||||
"src/features/source/services/Sources.ts",
|
||||
"src/lib/dayjs/LocaleImporter.ts",
|
||||
"src/lib/dnd-kit/DndKitUtil.ts",
|
||||
"src/lib/requests/RequestManager.ts",
|
||||
"src/lib/requests/client/GraphQLClient.ts",
|
||||
"src/lib/service-worker/ImageCache.ts",
|
||||
"src/lib/virtuoso/Virtuoso.util.tsx"
|
||||
],
|
||||
"rules": {
|
||||
"react/rules-of-hooks": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/*.config.ts",
|
||||
"**/*.config.js"
|
||||
],
|
||||
"rules": {
|
||||
"import/no-default-export": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"tools/scripts/**/*"
|
||||
],
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-relative-import-paths/no-relative-import-paths": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"src/lib/graphql/generated/**"
|
||||
]
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"semi": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
55
CHANGELOG.md
55
CHANGELOG.md
@@ -7,12 +7,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
## [Unreleased] (Preview)
|
||||
|
||||
### Added
|
||||
|
||||
- (**Theme**) Add an option to save the dynamic color theme on the manga page as a custom theme
|
||||
- (**WebUI Update**) Add an option to (partially) disable showing information when the webUI got updated
|
||||
- (**Server Update**) Add an option to disable showing information when the server got updated
|
||||
- (**Manga**) Add an option to include client data during migration
|
||||
|
||||
### Changed
|
||||
|
||||
- (**General**) Preserve refresh token (UI Login) over sessions
|
||||
- (**General**) Reduce base font size
|
||||
- (**General**) Save selected app language on the server
|
||||
@@ -24,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- (**Browse**) Merge languages filter of the sources and extensions into one
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix saving large client data on the server (e.g., custom source filters)
|
||||
- (**Library**) Fix total library size chip color in light mode
|
||||
- (**Browse**) Fix missing pinned sources in the source language filter
|
||||
@@ -34,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
## [20251230.01] (r2937) - 2025-12-30
|
||||
|
||||
### Added
|
||||
|
||||
- (**Navigation**) Show extension update information in app navigation
|
||||
- (**General**) Add support for "ui login" authentication mode
|
||||
- (**General**) Add support for hosting on subpaths
|
||||
@@ -50,6 +54,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- (**Browse**) Add "open in webview" button in source browse page
|
||||
|
||||
### Changed
|
||||
|
||||
- (**General**) Improve loading of images
|
||||
- (**Category**) Prevent creating categories without a name
|
||||
- (**WebUI Update**) Do not require a forced page refresh when an update has been detected in case the app just got opened
|
||||
@@ -57,6 +62,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- (**Settings**) Move "Clear cache" setting to new "Images" setting page
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix tooltips sometimes causing a layout shift
|
||||
- (**General**) Fix back button under some specific conditions (e.g., `library category X` → `mange` → `reader` → `manga` → back button → `library`; should have opened `library category X`)
|
||||
- (**Manga**) Fix failing migration with disabled "tracking" data
|
||||
@@ -79,14 +85,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
- (**Reader**) Fix broken scrolling in continuous horizontal reading mode
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Added
|
||||
|
||||
- Russian (by Micka149)
|
||||
|
||||
#### Updated
|
||||
|
||||
- Tamil (by தமிழ்நேரம்)
|
||||
- Polish (by UnknownSkyrimPasserby)
|
||||
- Korean (by Kim KKAng, jun)
|
||||
@@ -102,6 +111,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- Turkish (by Metin)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@schroda, @github-actions[bot], @weblate, @cpiber, @ginocic, @infyProductions, @Metincloup, @Micka149, @dejavui, @TheRay82, @plum7x, @aizhimoran, @zeedif, @AdrianRSouza, @ritma-bws, @CBujeda, @rogervc, @UnknownSkyrimPasserby, @mrintrepide, @q1114938967, @sksper1-stack, @renjfk, @Smileskun, @bornav, @9811pc, @imammansyur, @cho558, @marimo-nekomimi, @Dusky-dev
|
||||
@@ -109,9 +119,11 @@ Thanks to everyone that contributed to this release
|
||||
## [20250801.01] (r2717) - 2025-08-01
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix white screen on page load
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@schroda
|
||||
@@ -119,6 +131,7 @@ Thanks to everyone that contributed to this release
|
||||
## [20250731.01] (r2715) - 2025-07-31
|
||||
|
||||
### Added
|
||||
|
||||
- (**General**) Add support for the suwayomi WebView
|
||||
- (**Settings**) Add new OPDS server settings
|
||||
- (**Settings**) Add new "simple login" authentication setting
|
||||
@@ -128,6 +141,7 @@ Thanks to everyone that contributed to this release
|
||||
- (**Manga**) Add support for private track bindings
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix drag and drop on touch devices
|
||||
- (**Reader**) Fix auto scrolling with static overlay
|
||||
- (**Extension**) Fix clicking on action button (install, uninstall, update, ...) opening the extension info page
|
||||
@@ -136,11 +150,13 @@ Thanks to everyone that contributed to this release
|
||||
- (**Chapter**) Fix updating read status of already read chapters when using the mark previous as read option
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Updated
|
||||
|
||||
- Vietnamese (by Nguyễn Trung Đức)
|
||||
- Chinese (Simplified) (by 清水汐音)
|
||||
- Japanese (by 9811pc)
|
||||
@@ -148,6 +164,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- German (by Constantin Piber)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@weblate, @cpiber, @EugeneCage, @dejavui, @UnknownSkyrimPasserby, @aizhimoran, @schroda, @9811pc, @AlirezaGh1993, @gianlucalauro, @junmusk, @JiPaix, @leollo98, @LycusCoder, @Sawadikhap, @yutthaphon, @Oxara, @Mamotromico, @plum7x, @jintaxi, @TamilNeram, @shirishsaxena
|
||||
@@ -155,6 +172,7 @@ Thanks to everyone that contributed to this release
|
||||
## [20250703.01] (r2643) - 2025-07-03
|
||||
|
||||
### Added
|
||||
|
||||
- (**Manga**) Add functionality to click on title/artist/author/genre to trigger library/source/global search
|
||||
- (**Library**) Add option to perform current search globally
|
||||
- (**Source**) Add option to disable sources of an extension
|
||||
@@ -174,6 +192,7 @@ Thanks to everyone that contributed to this release
|
||||
- (**Chapter**) Show missing chapters info between chapters in the chapter list
|
||||
|
||||
### Changed
|
||||
|
||||
- (**Manga**) Require confirmation before removing an entry from your library
|
||||
- (**Chapter**) Require confirmation for the following actions
|
||||
- Download
|
||||
@@ -200,9 +219,11 @@ Thanks to everyone that contributed to this release
|
||||
- (**Setting**) Prevent setting up basic auth with both an empty username and password. This is an issue on iOS whose native basic auth prompt disables the "login" button in case both fields are empty.
|
||||
|
||||
### Removed
|
||||
|
||||
- (**Source**) Remove "popular" button on source card
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix custom long press causing native mobile long press menu to get opened
|
||||
- (**General**) Fix refreshing data after importing a backup
|
||||
- (**Reader**) Fix each key press triggering a keybind (example: "n" → next page, "ctrl+n" → next chapter - previously "ctrl+n" would have triggered both keybinds)
|
||||
@@ -221,14 +242,17 @@ Thanks to everyone that contributed to this release
|
||||
- (**Download**) Fix downloads start/stop button not updating
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Added
|
||||
|
||||
- Portuguese (Brazil) (by Psico, Jorge Adriano Cavalcante Alves)
|
||||
|
||||
#### Updated
|
||||
|
||||
- Chinese (Traditional) (by plum7x)
|
||||
- Vietnamese (by Nguyễn Trung Đức)
|
||||
- Italian (by xAizawa)
|
||||
@@ -242,6 +266,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- German (by Constantin Piber)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@weblate, @9811pc, @cpiber, @yutthaphon, @dejavui, @UnknownSkyrimPasserby, @dpkass, @marimo-nekomimi, @TamilNeram, @aizhimoran, @schroda, @junmusk, @adriano1816, @Zereef, @plum7x, @FedericoRossiIT, @Well2333, @ketw09, @IDika31, @kosmik7, @letroll, @KrachDev, @MageSneaky, @Tankudoraiba, @tizio04, @xAizawa
|
||||
@@ -249,17 +274,21 @@ Thanks to everyone that contributed to this release
|
||||
## [1.5.1] (r2467) - 2025-04-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**Server update**) Fix detection of available server update
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Updated
|
||||
|
||||
- Polish (by UnknownSkyrimPasserby)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@schroda, @weblate, @UnknownSkyrimPasserby
|
||||
@@ -267,13 +296,16 @@ Thanks to everyone that contributed to this release
|
||||
## [1.5.0] (r2461) - 2025-04-05
|
||||
|
||||
> ### Required action
|
||||
>
|
||||
> - If you have installed the web app as a PWA you need to reinstall the app after it has been updated to the latest version
|
||||
|
||||
### Highlights
|
||||
|
||||
- Completely new reader
|
||||
- Use predefined UI themes or create your own
|
||||
|
||||
### Added
|
||||
|
||||
- (**General**) Add labels to the navigation side bar icons
|
||||
- (**General**) Add option to expand and collapse the navigation side bar
|
||||
- (**General**) Update app styling
|
||||
@@ -336,6 +368,7 @@ Thanks to everyone that contributed to this release
|
||||
- (**Migrate**) Add sort options for migratable sources (by source name, manga count; order ascending/descending)
|
||||
|
||||
### Changed
|
||||
|
||||
- (**General**) Introduce "More" page
|
||||
- Remove "Settings" from navigation bar
|
||||
- Remove "Downloads" from mobile navigation bar
|
||||
@@ -350,9 +383,11 @@ Thanks to everyone that contributed to this release
|
||||
- (**Settings**) Move link to "Category settings" to "library settings" and "More" page
|
||||
|
||||
### Removed
|
||||
|
||||
- (**Settings**) Remove "graphql debug level" setting (was removed by the server)
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix setting browser locale for used date library (some supported browser locales were not correctly detected)
|
||||
- (**General**) Fix server subscriptions not updating to new server after changing the server address
|
||||
- (**General**) Fix missing polyfill to support older browsers
|
||||
@@ -417,15 +452,18 @@ Thanks to everyone that contributed to this release
|
||||
- (**Category**) Fix missing error message on category update/creation failure
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Added
|
||||
|
||||
- Tamil (by தமிழ்நேரம்)
|
||||
- Polish (by UnknownSkyrimPasserby)
|
||||
|
||||
#### Updated
|
||||
|
||||
- Chinese (Simplified) (by 清水汐音, Joshua Astray)
|
||||
- Chinese (Traditional) (by plum7x, aaron mo)
|
||||
- French (by Jean-Philippe ALLEGRO, Tycoon3819)
|
||||
@@ -437,6 +475,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- Vietnamese (by Nguyễn Trung Đức, PandaKewt)
|
||||
|
||||
#### Removed (less than 75% translated)
|
||||
|
||||
- "Arabic (ar)" (71.7%)
|
||||
- "Bengali (bn)" (1.8%)
|
||||
- "Danish (da)" (13.6%)
|
||||
@@ -455,6 +494,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- "Cantonese (Traditional Han script) (yue-Hant)" (0%)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@schroda, @weblate, @cpiber, @infyProductions, @leollo98, @dejavui, @UnknownSkyrimPasserby, @plum7x, @aizhimoran, @ykxkykx, @HanJoJ, @jicedtea, @Daviid-P, @kalebC, @TamilNeram, @Duoduo12138, @crystailx, @Banchon999, @jesusFx, @Runkandel, @lengzero, @tizio04, @zeedif, @Wybxc, @Mamotromico, @CladZo91, @senseimon1, @krizopraz, @mipo89-dev, @Robonau, @Meliodas-Sama, @991n1nd12, @RikCost, @JiPaix, @LycusCoder, @Oxara, @PandaKewt, @BrutuZ, @Yinr, @leqord, @RickyLam11, @Hada45, @gianlucalauro, @lucaschristofaro, @marimo-nekomimi
|
||||
@@ -462,12 +502,14 @@ Thanks to everyone that contributed to this release
|
||||
## [1.1.0] (r1689) - 2024-06-14
|
||||
|
||||
### Highlights
|
||||
|
||||
- Tracking support
|
||||
- Different UI settings per device (e.g. reader settings)
|
||||
- Save searches in source browse
|
||||
- Chapter download selection improvement
|
||||
|
||||
### Added
|
||||
|
||||
- (**Internationalization**) Apply right to left styling for languages that are read right to left
|
||||
- (**Library**) New setting to remove manga from categories when removing them from the library
|
||||
- (**Library**) Filter library for manga that have bookmarked chapters
|
||||
@@ -484,7 +526,7 @@ Thanks to everyone that contributed to this release
|
||||
- From library
|
||||
- (**Manga**) Copy manga title on long press in manga page
|
||||
- (**Settings**) UI specific settings that are stored on the server are now saved per device (devices can be managed in the settings)
|
||||
- A device name is allowed to have 16 chars (a-Z, 0-9, -, _) (e.g. "My_Phone-1")
|
||||
- A device name is allowed to have 16 chars (a-Z, 0-9, -, \_) (e.g. "My_Phone-1")
|
||||
- Device specific settings
|
||||
- Reader
|
||||
- Default settings
|
||||
@@ -527,12 +569,14 @@ Thanks to everyone that contributed to this release
|
||||
- Refreshes the tab on close
|
||||
|
||||
### Changed
|
||||
|
||||
- (**Library**) The category selection dialog is not shown when adding a manga to the library without having created categories
|
||||
- (**Library**) The current library manga selection now gets unselected after triggering an action
|
||||
- (**Manga**) The continue read/resume button now uses the first unread chapter as the resume point
|
||||
- (**Download**) The download queue clear button is now always enabled
|
||||
|
||||
### Fixed
|
||||
|
||||
- (**General**) Fix white screen on older browsers
|
||||
- (**General**) Fix old data still being shown after
|
||||
- Changing the server url
|
||||
@@ -564,11 +608,13 @@ Thanks to everyone that contributed to this release
|
||||
- (**Manga grid**) Fix jittering/flickering of manga grid items
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Added
|
||||
|
||||
- Norwegian Bokmål (by VR Kek)
|
||||
- Swedish (by Alexander)
|
||||
- Turkish (by Efe Devirgen)
|
||||
@@ -576,6 +622,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- Bengali (by Akhlak Ur Rahman)
|
||||
|
||||
#### Updated
|
||||
|
||||
- Chinese (Simplified) (by 清水汐音, Kouki Kitamura)
|
||||
- Italian (by tizio04, Roberto Palmese)
|
||||
- Japanese (by marimo, Siamese)
|
||||
@@ -589,6 +636,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- Indonesian (by Axel C)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@leollo98, @kiritsumafuyu, @marimo-nekomimi, @tizio04, @aizhimoran, @schroda, @akhlakurrahman1011, @xxx1SET1xxx, @jesusFx, @SySen04, @dejavui, @JoHena, @jintaxi, @okpo2188513, @axlchr12, @Lafrend, @EfeDevirgen, @HugoLeBoennec, @PandaKewt, @rpalmese, @ZerOri, @Xsrt251, @plum7x, @GR2066878693, @taos15, @Topru333, @chancez, @MageSneaky, @Azokul01, @gabrielssevero, @0QwQ0, @Rintan, @zyzz8520, @guohuageng
|
||||
@@ -596,6 +644,7 @@ Thanks to everyone that contributed to this release
|
||||
## [1.0.0] (r1411) - 2024-02-23
|
||||
|
||||
### Added
|
||||
|
||||
- (**General**) Added internationalization (help translating on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/))
|
||||
- (**General**) Get notified when a new server version has been released
|
||||
- (**General**) Manually check for new versions (server and webUI)
|
||||
@@ -629,14 +678,17 @@ Thanks to everyone that contributed to this release
|
||||
- (**Settings**) Server settings can now be changed from the UI
|
||||
|
||||
### Fixed
|
||||
|
||||
- A lot (and added new ones for the future, lul)
|
||||
|
||||
### Translations
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/).
|
||||
|
||||
Thanks to everyone that contributed to the translation of this project.
|
||||
|
||||
#### Added
|
||||
|
||||
- Arabic (by abdelbasset jabrane, Bander AL-shreef)
|
||||
- Chinese (Simplified) (by misaka10843, 蓝云Reyes, Nite07, 志明, ccms, 宮河ひより, 清水汐音, DevCoz)
|
||||
- Chinese (Traditional) (by plum7x, 蓝云Reyes)
|
||||
@@ -652,6 +704,7 @@ Thanks to everyone that contributed to the translation of this project.
|
||||
- Vietnamese (by xconkhi9x)
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to everyone that contributed to this release
|
||||
|
||||
@schroda, @jesusFx, @QuietBlade, @anvstin, @guohuageng, @plum7x, @HiyoriTUK, @aizhimoran, @JiPaix, @Yuhyeong, @a18ccms, @chancez, @rickymcmuffin, @zmmx, @alexandrejournet, @ibaraki-douji, @nitezs, @misaka10843, @Becods, @skrewde, @xconkhi9x, @cnmorocho, @Wip-Sama, @Kefir2105, @RafieHardinur, @SuperMario229, @Alexandre-P-J, @AriaMoradi, @NathanBnm, @FumoVite, @JoHena, @bandysharif, @DevCoz, @comradekingu, @Zereef, @akabhirav
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
# Contributing
|
||||
|
||||
## Where should I start?
|
||||
|
||||
Everything from https://github.com/Suwayomi/Suwayomi-Server/blob/master/CONTRIBUTING.md#where-should-i-start applies here.
|
||||
|
||||
## About this project
|
||||
|
||||
### Building the app
|
||||
|
||||
See [BUILDING.md](./BUILDING.md) for more information
|
||||
|
||||
## WebUI to [Server](https://github.com/Suwayomi/Suwayomi-Server) mapping
|
||||
|
||||
### Explanation
|
||||
|
||||
For the server to be able to automatically download the latest compatible WebUI version, the [version to server version mapping file](versionToServerVersionMapping.json) has to be provided.<br/>
|
||||
|
||||
The order of the version mapping is important and has to be sorted by latest WebUI version to the oldest version.<br/>
|
||||
The latest version will always be `PREVIEW`.
|
||||
|
||||
### When to update
|
||||
|
||||
- changes get added that require a new minimum server version
|
||||
- **update:** the mapped server version for the `PREVIEW` version
|
||||
- releasing a new version
|
||||
@@ -23,7 +29,9 @@ The latest version will always be `PREVIEW`.
|
||||
- changed: add a new entry below the `PREVIEW` version with the mapped server version from `PREVIEW`
|
||||
|
||||
## Coding Style Guide
|
||||
|
||||
**Note:** Some of the bellow are new, refactor the code to match the style guide where you see inconsistency.
|
||||
|
||||
- Don't use relative imports.
|
||||
- We are using MUI v5, the all stylings must be applied with the new system.
|
||||
- Never use the `style` prop, there's always a cleaner solution with `sx` or `styled`.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# Suwayomi-WebUI
|
||||
|
||||
This is the repository of the default client of [Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server).
|
||||
|
||||
The server has this web app bundled by default and is able to automatically update to the latest versions.
|
||||
Thus, there is no need to manually download any builds unless you want to host the app yourself instead of having it hosted by the Suwayomi-Server.
|
||||
|
||||
## Features
|
||||
|
||||
- Library management
|
||||
- Library page - manga management
|
||||
- Filter/Sort/Search your manga
|
||||
@@ -47,6 +49,7 @@ Thus, there is no need to manually download any builds unless you want to host t
|
||||
- Dynamic theme on manga pages
|
||||
|
||||
## Preview
|
||||
|
||||
An ongoing changelog of all relevant changes since the last stable release can be found [here](https://github.com/Suwayomi/Suwayomi-WebUI/issues/749)
|
||||
|
||||
To use the preview version you can select the PREVIEW channel in the settings of your Suwayomi-Server.
|
||||
@@ -58,12 +61,14 @@ In case your server is outdated, it will automatically downgrade to the latest c
|
||||
Minified builds of WebUI can be found here [Suwayomi-WebUI-preview](https://github.com/Suwayomi/Suwayomi-WebUI-preview).
|
||||
|
||||
Additionally, there is an online build of the WebUI preview version that is available [here](https://suwayomi-webui-preview.github.io/).
|
||||
*Make sure to set your Suwayomi-Server hostname in Settings or you'll get infinite loading.* Also note that its the **latest** revision of WebUI and might not work correctly if you connect to a stable build of Suwayomi-Server.
|
||||
_Make sure to set your Suwayomi-Server hostname in Settings or you'll get infinite loading._ Also note that its the **latest** revision of WebUI and might not work correctly if you connect to a stable build of Suwayomi-Server.
|
||||
|
||||
## Contributing and Technical info
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Translation
|
||||
|
||||
Feel free to translate the project on [Weblate](https://hosted.weblate.org/projects/suwayomi/suwayomi-webui/)
|
||||
|
||||
<details><summary>Translation Progress</summary>
|
||||
|
||||
310
eslint.config.js
310
eslint.config.js
@@ -1,187 +1,23 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
/*
|
||||
* Minimal ESLint config — only rules not yet supported natively in oxlint.
|
||||
* The bulk of linting is done by oxlint (.oxlintrc.json).
|
||||
*/
|
||||
import tseslint from 'typescript-eslint';
|
||||
import reactPlugin from 'eslint-plugin-react';
|
||||
import reactHooksPlugin from 'eslint-plugin-react-hooks';
|
||||
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
||||
import importX, { importXResolverCompat } from 'eslint-plugin-import-x';
|
||||
import * as tsResolver from 'eslint-import-resolver-typescript';
|
||||
import unusedImports from 'eslint-plugin-unused-imports';
|
||||
import noRelativeImportPaths from 'eslint-plugin-no-relative-import-paths';
|
||||
import header from '@tony.ganchev/eslint-plugin-header';
|
||||
import lingui from 'eslint-plugin-lingui';
|
||||
import prettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['src/lib/graphql/generated/**'] },
|
||||
{ ignores: ['src/lib/graphql/generated/**', 'eslint.config.js'] },
|
||||
|
||||
// Base configs
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
reactPlugin.configs.flat.recommended,
|
||||
reactPlugin.configs.flat['jsx-runtime'],
|
||||
reactHooksPlugin.configs['recommended-latest'],
|
||||
jsxA11y.flatConfigs.recommended,
|
||||
importX.flatConfigs.recommended,
|
||||
lingui.configs['flat/recommended'],
|
||||
|
||||
// Main rules
|
||||
{
|
||||
files: ['**/*.{ts,tsx,js,jsx}'],
|
||||
languageOptions: {
|
||||
globals: { ...globals.browser },
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
react: { version: 'detect' },
|
||||
'import-x/extensions': ['.ts', '.tsx', '.js', '.jsx'],
|
||||
'import-x/external-module-folders': ['node_modules', 'node_modules/@types'],
|
||||
'import-x/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts', '.tsx'],
|
||||
},
|
||||
'import-x/resolver-next': [
|
||||
importXResolverCompat(tsResolver, {
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx'],
|
||||
}),
|
||||
],
|
||||
parser: tseslint.parser,
|
||||
},
|
||||
plugins: {
|
||||
'unused-imports': unusedImports,
|
||||
'no-relative-import-paths': noRelativeImportPaths,
|
||||
header,
|
||||
},
|
||||
rules: {
|
||||
// Lingui
|
||||
'lingui/no-expression-in-message': 'off',
|
||||
|
||||
// Core JS rules from Airbnb
|
||||
'no-console': 'warn',
|
||||
'no-nested-ternary': 'error',
|
||||
'no-else-return': ['error', { allowElseIf: false }],
|
||||
'no-lonely-if': 'error',
|
||||
'no-unneeded-ternary': ['error', { defaultAssignment: false }],
|
||||
'no-multi-assign': 'error',
|
||||
'no-return-assign': ['error', 'always'],
|
||||
'no-sequences': 'error',
|
||||
'no-new': 'error',
|
||||
'no-new-func': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-script-url': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-caller': 'error',
|
||||
'no-alert': 'warn',
|
||||
'no-void': 'error',
|
||||
'no-bitwise': 'error',
|
||||
'no-continue': 'error',
|
||||
'no-restricted-globals': ['error', 'isFinite', 'isNaN'],
|
||||
'no-await-in-loop': 'error',
|
||||
'no-promise-executor-return': 'error',
|
||||
'no-template-curly-in-string': 'error',
|
||||
'no-constructor-return': 'error',
|
||||
'no-unreachable-loop': 'error',
|
||||
'no-useless-concat': 'error',
|
||||
'no-useless-return': 'error',
|
||||
'no-useless-computed-key': 'error',
|
||||
'no-useless-rename': 'error',
|
||||
'no-underscore-dangle': 'error',
|
||||
'no-restricted-exports': ['error', { restrictedNamedExports: ['default', 'then'] }],
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
'consistent-return': 'error',
|
||||
'guard-for-in': 'error',
|
||||
'default-case': ['error', { commentPattern: '^no default$' }],
|
||||
'default-case-last': 'error',
|
||||
radix: 'error',
|
||||
yoda: 'error',
|
||||
'one-var': ['error', 'never'],
|
||||
'max-classes-per-file': ['error', 1],
|
||||
'prefer-template': 'error',
|
||||
'prefer-destructuring': [
|
||||
'error',
|
||||
{
|
||||
VariableDeclarator: { array: false, object: true },
|
||||
AssignmentExpression: { array: true, object: false },
|
||||
},
|
||||
{ enforceForRenamedProperties: false },
|
||||
],
|
||||
'prefer-exponentiation-operator': 'error',
|
||||
'prefer-object-spread': 'error',
|
||||
'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
|
||||
'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }],
|
||||
'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true }],
|
||||
'no-param-reassign': ['error', { props: true, ignorePropertyModificationsForRegex: ['^draft'] }],
|
||||
'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
|
||||
'class-methods-use-this': 'off',
|
||||
|
||||
// TypeScript rules (non-type-checked)
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'no-loop-func': 'off',
|
||||
'@typescript-eslint/no-loop-func': 'error',
|
||||
'@typescript-eslint/no-use-before-define': ['error', { functions: false, classes: true, variables: true }],
|
||||
'default-param-last': 'off',
|
||||
'@typescript-eslint/default-param-last': 'error',
|
||||
|
||||
// TypeScript rules (type-checked)
|
||||
'no-implied-eval': 'off',
|
||||
'@typescript-eslint/no-implied-eval': 'error',
|
||||
'@typescript-eslint/only-throw-error': 'error',
|
||||
'dot-notation': 'off',
|
||||
'@typescript-eslint/dot-notation': 'error',
|
||||
'@typescript-eslint/return-await': ['error', 'in-try-catch'],
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{ selector: 'variable', format: ['camelCase', 'PascalCase', 'UPPER_CASE'] },
|
||||
{ selector: 'function', format: ['camelCase', 'PascalCase'] },
|
||||
{ selector: 'typeLike', format: ['PascalCase'] },
|
||||
],
|
||||
|
||||
// TypeScript — relax rules not effectively enforced in old config
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
vars: 'all',
|
||||
args: 'after-used',
|
||||
ignoreRestSiblings: true,
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_|^e$|^error$',
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
|
||||
// Unused imports
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
|
||||
// Import rules from Airbnb
|
||||
'import-x/no-cycle': 'off', // TODO: enable after resolving circular dependencies
|
||||
'import-x/no-mutable-exports': 'error',
|
||||
'import-x/first': 'error',
|
||||
'import-x/newline-after-import': 'error',
|
||||
'import-x/no-amd': 'error',
|
||||
'import-x/no-absolute-path': 'error',
|
||||
'import-x/no-self-import': 'error',
|
||||
'import-x/no-useless-path-segments': ['error', { noUselessIndex: true }],
|
||||
'import-x/no-extraneous-dependencies': 'error',
|
||||
'import-x/order': ['error', { groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'] }],
|
||||
|
||||
// Import rules (import → import-x)
|
||||
'import-x/prefer-default-export': 'off',
|
||||
'import-x/no-default-export': 'error',
|
||||
'import-x/extensions': 'off',
|
||||
'import-x/no-named-as-default': 'off',
|
||||
'import-x/no-named-as-default-member': 'off',
|
||||
'import-x/named': 'off',
|
||||
'import-x/no-unresolved': ['error', { ignore: ['^@dnd-kit/core/dist', '^i18next$', '^public/'] }],
|
||||
|
||||
// Header
|
||||
// MPL 2.0 license header
|
||||
'header/header': [
|
||||
'error',
|
||||
'block',
|
||||
@@ -196,136 +32,6 @@ export default tseslint.config(
|
||||
],
|
||||
2,
|
||||
],
|
||||
|
||||
// Prettier
|
||||
'prettier/prettier': 'error',
|
||||
|
||||
// React hooks — relax rules that are stricter in v5
|
||||
'react-hooks/exhaustive-deps': 'off',
|
||||
|
||||
// React rules from Airbnb
|
||||
'react/destructuring-assignment': ['error', 'always'],
|
||||
'react/no-unused-prop-types': 'error',
|
||||
'react/no-array-index-key': 'error',
|
||||
'react/jsx-no-useless-fragment': 'error',
|
||||
'react/jsx-no-constructed-context-values': 'error',
|
||||
'react/self-closing-comp': 'error',
|
||||
'react/jsx-boolean-value': ['error', 'never'],
|
||||
'react/jsx-pascal-case': ['error', { allowAllCaps: true }],
|
||||
'react/button-has-type': 'error',
|
||||
'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
|
||||
'react/jsx-fragments': ['error', 'syntax'],
|
||||
'react/jsx-no-script-url': 'error',
|
||||
'react/style-prop-object': 'error',
|
||||
'react/void-dom-elements-no-children': 'error',
|
||||
'react/no-danger': 'warn',
|
||||
'react/no-this-in-sfc': 'error',
|
||||
'react/state-in-constructor': ['error', 'always'],
|
||||
|
||||
// React — match Airbnb overrides
|
||||
'react/jsx-uses-react': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
'react/jsx-no-bind': 'off',
|
||||
'react/jsx-props-no-spreading': 'off',
|
||||
'react/require-default-props': 'off',
|
||||
'react/function-component-definition': 'off',
|
||||
'react/display-name': 'off',
|
||||
'react/no-unstable-nested-components': ['error', { allowAsProps: true }],
|
||||
|
||||
// jsx-a11y — match Airbnb (allow autoFocus on non-DOM elements)
|
||||
'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
|
||||
|
||||
// Restricted imports (MUI pattern)
|
||||
'no-restricted-imports': [
|
||||
'error',
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
group: ['@mui/*', '!@mui/material/', '!@mui/icons-material/', '!@mui/x-date-pickers/'],
|
||||
},
|
||||
{
|
||||
group: ['@mui/*/*/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
// Restricted syntax (SxProps check)
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSTypeReference[typeName.name="SxProps"]:not([typeArguments])',
|
||||
message: 'SxProps must have Theme parameter to avoid significant compiler slowdown.',
|
||||
},
|
||||
],
|
||||
|
||||
// No relative import paths
|
||||
'no-relative-import-paths/no-relative-import-paths': [
|
||||
'error',
|
||||
{
|
||||
rootDir: 'src',
|
||||
prefix: '@',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
// Files using hooks in class static methods (valid namespace pattern, flagged by react-hooks v5)
|
||||
{
|
||||
files: [
|
||||
'src/base/components/settings/NumberSetting.tsx',
|
||||
'src/base/utils/MediaQuery.tsx',
|
||||
'src/features/authentication/AuthManager.ts',
|
||||
'src/features/browse/extensions/components/ExtensionCard.tsx',
|
||||
'src/features/chapter/services/Chapters.ts',
|
||||
'src/features/extension/info/components/ActionButton.tsx',
|
||||
'src/features/manga/components/TrackMangaButton.tsx',
|
||||
'src/features/manga/services/Mangas.ts',
|
||||
'src/features/metadata/services/MetadataMigrations.ts',
|
||||
'src/features/migration/components/MigrateDialog.tsx',
|
||||
'src/features/navigation-bar/components/MobileBottomBar.tsx',
|
||||
'src/features/reader/services/ReaderControls.ts',
|
||||
'src/features/reader/services/ReaderService.ts',
|
||||
'src/features/settings/screens/ImageProcessingSetting.tsx',
|
||||
'src/features/source/browse/components/SourceOptions.tsx',
|
||||
'src/features/source/browse/components/filters/SelectFilter.tsx',
|
||||
'src/features/source/services/Sources.ts',
|
||||
'src/lib/dayjs/LocaleImporter.ts',
|
||||
'src/lib/dnd-kit/DndKitUtil.ts',
|
||||
'src/lib/requests/RequestManager.ts',
|
||||
'src/lib/requests/client/GraphQLClient.ts',
|
||||
'src/lib/service-worker/ImageCache.ts',
|
||||
'src/lib/virtuoso/Virtuoso.util.tsx',
|
||||
],
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Tools/scripts override
|
||||
{
|
||||
files: ['tools/scripts/**/*'],
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'no-relative-import-paths/no-relative-import-paths': 'off',
|
||||
'import-x/no-extraneous-dependencies': ['error', { devDependencies: true }],
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Config files — not part of tsconfig, disable type-checked linting and project-specific rules
|
||||
{
|
||||
files: ['eslint.config.js'],
|
||||
...tseslint.configs.disableTypeChecked,
|
||||
rules: {
|
||||
...tseslint.configs.disableTypeChecked.rules,
|
||||
'header/header': 'off',
|
||||
'import-x/no-default-export': 'off',
|
||||
'import-x/no-extraneous-dependencies': 'off',
|
||||
'import-x/default': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Prettier must be last
|
||||
prettierRecommended,
|
||||
);
|
||||
|
||||
45
index.html
45
index.html
@@ -1,29 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<script>
|
||||
(() => {
|
||||
if (document.querySelector('base')) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const base = document.createElement('base');
|
||||
base.href = '/';
|
||||
document.head.prepend(base);
|
||||
})()
|
||||
})();
|
||||
</script>
|
||||
<title>Suwayomi</title>
|
||||
<meta name="apple-mobile-web-app-title" content="Suwayomi" />
|
||||
<meta
|
||||
name="description"
|
||||
content="A manga reader that runs tachiyomi's extensions"
|
||||
/>
|
||||
<meta name="description" content="A manga reader that runs tachiyomi's extensions" />
|
||||
|
||||
<meta charset="utf-8"/>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<meta name='viewport' content='minimum-scale=1, initial-scale=1, viewport-fit=cover, width=device-width'>
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="viewport" content="minimum-scale=1, initial-scale=1, viewport-fit=cover, width=device-width" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
|
||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
@@ -34,18 +31,18 @@
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="/site.webmanifest" crossorigin="use-credentials" />
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./src/index.tsx"></script>
|
||||
<script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./src/index.tsx"></script>
|
||||
<script>
|
||||
const backgroundColor = (() => {
|
||||
const storageValue = window.localStorage.getItem("theme_background")
|
||||
const storageValue = window.localStorage.getItem('theme_background');
|
||||
try {
|
||||
return JSON.parse(storageValue)
|
||||
return JSON.parse(storageValue);
|
||||
} catch (e) {
|
||||
return storageValue
|
||||
return storageValue;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -62,8 +59,8 @@
|
||||
themeColorMeta.setAttribute('content', backgroundColor);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!--
|
||||
</script>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
@@ -73,5 +70,5 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
43
package.json
43
package.json
@@ -13,7 +13,9 @@
|
||||
"test": "node -e \"console.log('imagine')\"",
|
||||
"build-md5": "find build -type f | sort | xargs md5sum | awk '{ print $1 }' | tr -d '\n' | md5sum| awk '{ print $1 }' > buildZip/md5sum ",
|
||||
"build-zip": "cd build && rev=$(git rev-list HEAD --count) && echo r$rev > revision && zip -9 -r ../buildZip/Suwayomi-WebUI-r$rev *",
|
||||
"lint": "eslint src tools --max-warnings=0 --cache",
|
||||
"lint": "oxlint src tools && eslint src tools --max-warnings=0",
|
||||
"format": "oxfmt --write .",
|
||||
"format:check": "oxfmt --check .",
|
||||
"createCommitChangelog": "tsx tools/scripts/release/createCommitChangelog.ts",
|
||||
"createTranslationChangelog": "tsx tools/scripts/release/createTranslationChangelog.ts",
|
||||
"createReleaseChangelog": "tsx tools/scripts/release/createReleaseChangelog.ts",
|
||||
@@ -31,15 +33,6 @@
|
||||
"tsc:legacy": "tsc",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx}": "eslint --fix"
|
||||
},
|
||||
"resolutions": {
|
||||
"@swc/core": "1.15.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "4.1.6",
|
||||
"@dnd-kit/core": "6.3.1",
|
||||
@@ -102,6 +95,7 @@
|
||||
"@lingui/format-po": "5.9.2",
|
||||
"@lingui/swc-plugin": "5.11.0",
|
||||
"@lingui/vite-plugin": "5.9.2",
|
||||
"@tony.ganchev/eslint-plugin-header": "3.2.6",
|
||||
"@types/node": "24.10.1",
|
||||
"@types/react": "19.2.14",
|
||||
"@types/react-beautiful-dnd": "13.1.8",
|
||||
@@ -110,29 +104,20 @@
|
||||
"@types/stylis": "4.2.7",
|
||||
"@types/webfontloader": "1.6.38",
|
||||
"@types/yargs": "17.0.35",
|
||||
"@tony.ganchev/eslint-plugin-header": "3.2.6",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260309.1",
|
||||
"@vitejs/plugin-legacy": "7.2.1",
|
||||
"@vitejs/plugin-react-swc": "4.2.3",
|
||||
"dotenv": "17.3.1",
|
||||
"eslint": "9.39.4",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-typescript": "4.4.4",
|
||||
"eslint-plugin-import-x": "4.16.1",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-lingui": "0.11.0",
|
||||
"eslint-plugin-no-relative-import-paths": "1.6.1",
|
||||
"eslint-plugin-prettier": "5.5.5",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "5.2.0",
|
||||
"eslint-plugin-unused-imports": "4.4.1",
|
||||
"globals": "15.15.0",
|
||||
"husky": "9.1.7",
|
||||
"lint-staged": "16.3.2",
|
||||
"prettier": "3.8.1",
|
||||
"oxfmt": "0.37.0",
|
||||
"oxlint": "1.52.0",
|
||||
"syncyarnlock": "1.0.19",
|
||||
"terser": "5.46.0",
|
||||
"tsx": "4.21.0",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260309.1",
|
||||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.57.0",
|
||||
"vite": "7.3.1",
|
||||
@@ -142,5 +127,19 @@
|
||||
"workbox-build": "7.4.0",
|
||||
"workbox-window": "7.4.0",
|
||||
"yargs": "18.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@swc/core": "1.15.11"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx,js,jsx}": [
|
||||
"oxfmt --write",
|
||||
"oxlint --fix",
|
||||
"eslint --fix"
|
||||
],
|
||||
"*.{json,md,yml,yaml,css,scss,html,graphql}": "oxfmt --write"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
}
|
||||
}
|
||||
|
||||
1
src/apollo-upload-client.d.ts
vendored
1
src/apollo-upload-client.d.ts
vendored
@@ -10,7 +10,6 @@ declare module 'apollo-upload-client/UploadHttpLink.mjs' {
|
||||
import { ApolloLink } from '@apollo/client';
|
||||
import type { BaseHttpLink } from '@apollo/client/link/http';
|
||||
|
||||
// eslint-disable-next-line import-x/no-default-export
|
||||
export default class UploadHttpLink extends ApolloLink {
|
||||
constructor(options?: BaseHttpLink.ConstructorOptions);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ interface State {
|
||||
}
|
||||
|
||||
class RealErrorBoundary extends Component<Props, State> {
|
||||
// eslint-disable-next-line react/state-in-constructor
|
||||
// oxlint-disable-next-line react/state-in-constructor
|
||||
public state: State = { error: null };
|
||||
|
||||
private prevPath: string = '';
|
||||
@@ -45,10 +45,9 @@ class RealErrorBoundary extends Component<Props, State> {
|
||||
}
|
||||
|
||||
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.error('Uncaught error:', error, errorInfo);
|
||||
|
||||
// eslint-disable-next-line react/destructuring-assignment
|
||||
this.props.setTrackPathChange(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export class AuthManager {
|
||||
private static refreshingToken: boolean = false;
|
||||
|
||||
private static subscribe(callback: () => void): () => void {
|
||||
// eslint-disable-next-line no-plusplus
|
||||
// oxlint-disable-next-line no-plusplus
|
||||
const key = AuthManager.subscribedCount++;
|
||||
this.subscribers.set(key, callback);
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ export const ChapterCard = memo((props: IProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
// oxlint-disable-next-line no-param-reassign
|
||||
event.shiftKey = true;
|
||||
handleClick(event);
|
||||
});
|
||||
|
||||
@@ -76,10 +76,7 @@ const querySearchManga = (
|
||||
{ title, genre: genres, description, artist, author, source, sourceId }: TMangaQueryFilter,
|
||||
): boolean =>
|
||||
performSearch([query], [title]) ||
|
||||
performSearch(
|
||||
query?.split(','),
|
||||
genres.map((genre) => enhancedCleanup(genre)),
|
||||
) ||
|
||||
performSearch(query?.split(','), genres.map((genre) => enhancedCleanup(genre))) ||
|
||||
performSearch([query], [description]) ||
|
||||
performSearch([query], [artist]) ||
|
||||
performSearch([query], [author]) ||
|
||||
|
||||
@@ -158,7 +158,7 @@ export const SOURCES_BY_MANGA_TYPE: Record<MangaType, string[]> = {
|
||||
* The actual matching data is in {@link MANGA_TAGS_BY_MANGA_TYPE} below.
|
||||
*/
|
||||
// @ts-ignore - see comment
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line no-unused-vars
|
||||
const MANGA_TAG_DESCRIPTORS_BY_MANGA_TYPE: Record<MangaType, MessageDescriptor[]> = {
|
||||
[MangaType.MANGA]: [msg`Manga`],
|
||||
[MangaType.COMIC]: [msg`Comic`],
|
||||
|
||||
@@ -169,7 +169,7 @@ const VerticalGrid = ({
|
||||
/>
|
||||
</Box>
|
||||
{/* render div to prevent UI jumping around when showing/hiding loading placeholder */}
|
||||
{/* eslint-disable no-nested-ternary */}
|
||||
{/* oxlint-disable no-nested-ternary */}
|
||||
{isSelectModeActive && gridLayout === GridLayout.List ? (
|
||||
<Box sx={{ paddingBottom: DEFAULT_FULL_FAB_HEIGHT }} />
|
||||
) : isLoading ? (
|
||||
@@ -177,7 +177,7 @@ const VerticalGrid = ({
|
||||
) : hasNextPage ? (
|
||||
<div style={{ height: '75px' }} />
|
||||
) : null}
|
||||
{/* eslint-enable no-nested-ternary */}
|
||||
{/* oxlint-enable no-nested-ternary */}
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
||||
const longPressBind = useLongPress(
|
||||
useCallback(
|
||||
(e: any, { context }: any) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
// oxlint-disable-next-line no-param-reassign
|
||||
e.shiftKey = true;
|
||||
handleClick(e, context as () => {});
|
||||
},
|
||||
|
||||
@@ -549,7 +549,7 @@ export class Mangas {
|
||||
// the migration actions (copy, cleanup) are supposed to be run sequentially to ensure that the cleanup
|
||||
// only happens in case the copy succeeded
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
// oxlint-disable-next-line no-await-in-loop
|
||||
await performMigrationAction(migrationAction, ...actions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import deepmerge from '@mui/utils/deepmerge';
|
||||
import { AppMetadataKeys, IMetadataMigration } from '@/features/metadata/Metadata.types.ts';
|
||||
import {
|
||||
|
||||
@@ -120,7 +120,7 @@ export class ReaderTapZoneService {
|
||||
|
||||
context.beginPath();
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* oxlint-disable no-param-reassign */
|
||||
context.rect(x, y, width, height);
|
||||
context.fillStyle = color;
|
||||
context.strokeStyle = color;
|
||||
@@ -141,7 +141,7 @@ export class ReaderTapZoneService {
|
||||
context.lineWidth = 1;
|
||||
context.fillStyle = 'white';
|
||||
context.fillText(text, rectCenterX, rectCenterY);
|
||||
/* eslint-enable no-param-reassign */
|
||||
/* oxlint-enable no-param-reassign */
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ const BaseReaderChapterViewer = ({
|
||||
|
||||
isCurrentChapterRef.current = isCurrentChapter;
|
||||
if (isCurrentChapter) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
// oxlint-disable-next-line no-param-reassign
|
||||
globalImageRefs.current = imageRefs.current;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ const BaseReaderTransitionPage = ({
|
||||
handleBack,
|
||||
}: Pick<NavbarContextType, 'readerNavBarWidth'> & {
|
||||
// gets used in the "source props creators" of the "withPropsFrom" call
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
chapterId: ChapterIdInfo['id'];
|
||||
currentChapterName?: ChapterType['name'];
|
||||
currentChapterScanlator?: ChapterType['scanlator'];
|
||||
|
||||
@@ -87,7 +87,7 @@ const BaseBasePager = ({
|
||||
|
||||
const setRef = useCallback(
|
||||
(pagesIndex: number, element: HTMLElement | null) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
// oxlint-disable-next-line no-param-reassign
|
||||
imageRefs.current[pagesIndex] = element;
|
||||
},
|
||||
[imageRefs],
|
||||
|
||||
@@ -123,7 +123,7 @@ export const addStableIdToKeyValueItems = (
|
||||
items: (SettingsDownloadConversionHeader | TSettingsDownloadConversionKeyValueItem)[],
|
||||
): TSettingsDownloadConversionKeyValueItem[] =>
|
||||
items.map((item) => ({
|
||||
// eslint-disable-next-line no-plusplus
|
||||
// oxlint-disable-next-line no-plusplus
|
||||
id: (item as TSettingsDownloadConversionKeyValueItem).id ?? COUNTER++,
|
||||
...item,
|
||||
}));
|
||||
@@ -132,7 +132,7 @@ export const addStableIdToConversions = (
|
||||
conversions: (SettingsDownloadConversion | TSettingsDownloadConversion)[],
|
||||
): TSettingsDownloadConversion[] =>
|
||||
conversions.map((conversion) => ({
|
||||
// eslint-disable-next-line no-plusplus
|
||||
// oxlint-disable-next-line no-plusplus
|
||||
id: (conversion as TSettingsDownloadConversion).id ?? COUNTER++,
|
||||
...conversion,
|
||||
mode: getTargetMode(normalizeMimeType(conversion.target)),
|
||||
|
||||
@@ -51,7 +51,6 @@ export const getMetadataServerSettings = async (): Promise<MetadataServerSetting
|
||||
const { data, error } = await requestManager.getGlobalMeta().response;
|
||||
|
||||
if (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/only-throw-error
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export const TriStateFilter: React.FC<Props> = (props) => {
|
||||
const [val, setval] = React.useState(convertTriStateToNumber(state));
|
||||
|
||||
const handleChange = (checked: boolean | null | undefined) => {
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
// oxlint-disable-next-line no-nested-ternary
|
||||
const newState = checked === undefined ? 0 : checked ? 1 : 2;
|
||||
setval(newState);
|
||||
const upd = update.filter(
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
useTheme,
|
||||
} from '@mui/material/styles';
|
||||
import { useCallback } from 'react';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
// oxlint-disable-next-line no-restricted-imports
|
||||
import { deepmerge } from '@mui/utils';
|
||||
import { complement, hsl, parseToHsl } from 'polished';
|
||||
import { HslaColor, HslColor } from 'polished/lib/types/color';
|
||||
|
||||
@@ -87,7 +87,7 @@ export class ThemeFontLoader {
|
||||
result[font] = new Set([...(result[font] ?? []), ...weights].toSorted((a, b) => a - b));
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-continue
|
||||
// oxlint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,6 @@ export const defaultPromiseErrorHandler =
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// oxlint-disable-next-line no-console
|
||||
console.error(`${name} failed due to`, error);
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ export const importDayJsLocale = async (locale: string): Promise<DayJsLocale> =>
|
||||
const dayjsLocale = getDayJsLocale(locale);
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
// oxlint-disable-next-line no-use-before-define
|
||||
await localesToImport[dayjsLocale]();
|
||||
} catch (e) {
|
||||
// ignore - dayjs falls back to "en" by default
|
||||
|
||||
@@ -103,7 +103,7 @@ export abstract class BaseClient<Client, ClientConfig, Fetcher> {
|
||||
return SubpathUtil.getApiBaseUrl(serverBaseURL);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
// oxlint-disable-next-line no-unused-vars
|
||||
protected shouldQueueRequest(operationName?: string): boolean {
|
||||
return AuthManager.shouldQueueRequests();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
/* oxlint-disable max-classes-per-file */
|
||||
import { jsonSaveParse } from '@/lib/HelperFunctions.ts';
|
||||
|
||||
export class Storage {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": [
|
||||
"./**/*"
|
||||
],
|
||||
"include": ["./**/*"],
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": [
|
||||
"ESNEXT",
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"lib": ["ESNEXT", "ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
@@ -31,9 +24,7 @@
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules"],
|
||||
"references": [
|
||||
{
|
||||
|
||||
@@ -6,9 +6,5 @@
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"gql_codegen.ts",
|
||||
"lingui.config.ts"
|
||||
]
|
||||
"include": ["vite.config.ts", "gql_codegen.ts", "lingui.config.ts"]
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* eslint-disable import-x/no-extraneous-dependencies */
|
||||
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react-swc';
|
||||
@@ -18,7 +16,6 @@ import { lingui } from '@lingui/vite-plugin';
|
||||
import 'dotenv/config';
|
||||
import { d } from 'koration';
|
||||
|
||||
// eslint-disable-next-line import-x/no-default-export
|
||||
export default defineConfig(({ command }) => ({
|
||||
base: command === 'serve' ? process.env.VITE_SUBPATH || './' : './',
|
||||
build: {
|
||||
|
||||
Reference in New Issue
Block a user