From 612c6610ce1fb50a43e1ce1c11e0385e971ac208 Mon Sep 17 00:00:00 2001
From: zhom <2717306+zhom@users.noreply.github.com>
Date: Sat, 28 Mar 2026 23:31:20 +0400
Subject: [PATCH] chore: linting
---
.claude/skills/ui-ux-pro-max/SKILL.md | 5 ++
CONTRIBUTING.md | 2 +
donut-sync/README.md | 20 ++++----
donut-sync/src/auth/auth.guard.ts | 4 +-
donut-sync/src/sync/sync.controller.ts | 2 +-
src/app/page.tsx | 10 ++--
src/components/cookie-copy-dialog.tsx | 20 ++++----
src/components/cookie-management-dialog.tsx | 18 +++----
src/components/create-profile-dialog.tsx | 26 +++++-----
src/components/custom-toast.tsx | 10 ++--
src/components/data-table-action-bar.tsx | 2 +-
src/components/group-assignment-dialog.tsx | 2 +-
src/components/multiple-selector.tsx | 6 +--
src/components/profile-data-table.tsx | 18 +++++--
src/components/profile-info-dialog.tsx | 2 +-
src/components/settings-dialog.tsx | 23 ++++-----
.../shared-camoufox-config-form.tsx | 12 ++---
src/components/sync-follower-dialog.tsx | 4 +-
src/components/traffic-details-dialog.tsx | 4 +-
src/components/ui/color-picker.tsx | 2 +-
src/components/ui/highlight.tsx | 4 +-
src/components/wayfern-config-form.tsx | 2 +-
src/hooks/use-auto-height.tsx | 19 +++-----
src/hooks/use-browser-download.ts | 4 +-
src/hooks/use-cloud-auth.ts | 2 +-
src/hooks/use-controlled-state.tsx | 2 +-
src/hooks/use-proxy-events.ts | 2 +-
src/hooks/use-vpn-events.ts | 2 +-
src/i18n/locales/en.json | 48 +++++++++----------
src/i18n/locales/es.json | 48 +++++++++----------
src/i18n/locales/fr.json | 48 +++++++++----------
src/i18n/locales/ja.json | 48 +++++++++----------
src/i18n/locales/pt.json | 48 +++++++++----------
src/i18n/locales/ru.json | 48 +++++++++----------
src/i18n/locales/zh.json | 48 +++++++++----------
src/types.ts | 4 +-
36 files changed, 284 insertions(+), 285 deletions(-)
diff --git a/.claude/skills/ui-ux-pro-max/SKILL.md b/.claude/skills/ui-ux-pro-max/SKILL.md
index a937fb2..4b2ec8f 100644
--- a/.claude/skills/ui-ux-pro-max/SKILL.md
+++ b/.claude/skills/ui-ux-pro-max/SKILL.md
@@ -197,6 +197,7 @@ These are frequently overlooked issues that make UI look unprofessional:
Before delivering UI code, verify these items:
### Visual Quality
+
- [ ] No emojis used as icons (use SVG instead)
- [ ] All icons from consistent icon set (Heroicons/Lucide)
- [ ] Brand logos are correct (verified from Simple Icons)
@@ -204,24 +205,28 @@ Before delivering UI code, verify these items:
- [ ] Use theme colors directly (bg-primary) not var() wrapper
### Interaction
+
- [ ] All clickable elements have `cursor-pointer`
- [ ] Hover states provide clear visual feedback
- [ ] Transitions are smooth (150-300ms)
- [ ] Focus states visible for keyboard navigation
### Light/Dark Mode
+
- [ ] Light mode text has sufficient contrast (4.5:1 minimum)
- [ ] Glass/transparent elements visible in light mode
- [ ] Borders visible in both modes
- [ ] Test both modes before delivery
### Layout
+
- [ ] Floating elements have proper spacing from edges
- [ ] No content hidden behind fixed navbars
- [ ] Responsive at 320px, 768px, 1024px, 1440px
- [ ] No horizontal scroll on mobile
### Accessibility
+
- [ ] All images have alt text
- [ ] Form inputs have labels
- [ ] Color is not the only indicator
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ad05943..6659250 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,6 +27,7 @@ Or enter the dev shell: `nix develop`
### Manual Setup
Requirements:
+
- Node.js (see `.node-version`)
- pnpm
- Rust + Cargo (latest stable)
@@ -47,6 +48,7 @@ pnpm format && pnpm lint && pnpm test
```
This runs:
+
- **Biome** — JS/TS linting and formatting
- **Clippy + rustfmt** — Rust linting and formatting
- **typos** — Spellcheck (allowlist in `_typos.toml`)
diff --git a/donut-sync/README.md b/donut-sync/README.md
index d30c946..bb15dfc 100644
--- a/donut-sync/README.md
+++ b/donut-sync/README.md
@@ -2,8 +2,6 @@
-[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
-[circleci-url]: https://circleci.com/gh/nestjs/nest
A progressive Node.js framework for building efficient and scalable server-side applications.
@@ -28,33 +26,33 @@
## Project setup
```bash
-$ pnpm install
+pnpm install
```
## Compile and run the project
```bash
# development
-$ pnpm run start
+pnpm run start
# watch mode
-$ pnpm run start:dev
+pnpm run start:dev
# production mode
-$ pnpm run start:prod
+pnpm run start:prod
```
## Run tests
```bash
# unit tests
-$ pnpm run test
+pnpm run test
# e2e tests
-$ pnpm run test:e2e
+pnpm run test:e2e
# test coverage
-$ pnpm run test:cov
+pnpm run test:cov
```
## Deployment
@@ -64,8 +62,8 @@ When you're ready to deploy your NestJS application to production, there are som
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
```bash
-$ pnpm install -g @nestjs/mau
-$ mau deploy
+pnpm install -g @nestjs/mau
+mau deploy
```
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
diff --git a/donut-sync/src/auth/auth.guard.ts b/donut-sync/src/auth/auth.guard.ts
index 3053527..e23088b 100644
--- a/donut-sync/src/auth/auth.guard.ts
+++ b/donut-sync/src/auth/auth.guard.ts
@@ -38,7 +38,7 @@ export class AuthGuard implements CanActivate {
// Try SYNC_TOKEN first (self-hosted mode)
const expectedToken = this.configService.get("SYNC_TOKEN");
if (expectedToken && token === expectedToken) {
- (request as any).user = {
+ (request as unknown as Record).user = {
mode: "self-hosted",
prefix: "",
teamPrefix: null,
@@ -55,7 +55,7 @@ export class AuthGuard implements CanActivate {
algorithms: ["RS256"],
}) as jwt.JwtPayload;
- (request as any).user = {
+ (request as unknown as Record).user = {
mode: "cloud",
prefix: decoded.prefix || `users/${decoded.sub}/`,
teamPrefix: decoded.teamPrefix || null,
diff --git a/donut-sync/src/sync/sync.controller.ts b/donut-sync/src/sync/sync.controller.ts
index 76df58c..1be8ad6 100644
--- a/donut-sync/src/sync/sync.controller.ts
+++ b/donut-sync/src/sync/sync.controller.ts
@@ -39,7 +39,7 @@ export class SyncController {
constructor(private readonly syncService: SyncService) {}
private getUserContext(req: Request): UserContext {
- return (req as any).user as UserContext;
+ return (req as unknown as Record).user as UserContext;
}
@Post("stat")
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 83a8875..5130abe 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -324,7 +324,7 @@ export default function Home() {
const currentUrl = await getCurrent();
if (currentUrl && currentUrl.length > 0) {
console.log("Startup URL detected:", currentUrl[0]);
- void handleUrlOpen(currentUrl[0]);
+ handleUrlOpen(currentUrl[0]);
}
} catch (error) {
console.error("Failed to check current URL:", error);
@@ -413,13 +413,13 @@ export default function Home() {
// Listen for URL open events from the deep link handler (when app is already running)
await listen("url-open-request", (event) => {
console.log("Received URL open request:", event.payload);
- void handleUrlOpen(event.payload);
+ handleUrlOpen(event.payload);
});
// Listen for show profile selector events
await listen("show-profile-selector", (event) => {
console.log("Received show profile selector request:", event.payload);
- void handleUrlOpen(event.payload);
+ handleUrlOpen(event.payload);
});
// Listen for show create profile dialog events
@@ -437,7 +437,7 @@ export default function Home() {
// Listen for custom logo click events
const handleLogoUrlEvent = (event: CustomEvent) => {
console.log("Received logo URL event:", event.detail);
- void handleUrlOpen(event.detail);
+ handleUrlOpen(event.detail);
};
window.addEventListener(
@@ -995,7 +995,7 @@ export default function Home() {
// Check permissions when they are initialized
useEffect(() => {
if (isInitialized) {
- void checkAllPermissions();
+ checkAllPermissions();
}
}, [isInitialized, checkAllPermissions]);
diff --git a/src/components/cookie-copy-dialog.tsx b/src/components/cookie-copy-dialog.tsx
index 0fa16fd..2532032 100644
--- a/src/components/cookie-copy-dialog.tsx
+++ b/src/components/cookie-copy-dialog.tsx
@@ -50,12 +50,13 @@ interface CookieCopyDialogProps {
onCopyComplete?: () => void;
}
-interface SelectionState {
- [domain: string]: {
+type SelectionState = Record<
+ string,
+ {
allSelected: boolean;
cookies: Set;
- };
-}
+ }
+>;
export function CookieCopyDialog({
isOpen,
@@ -148,7 +149,7 @@ export function CookieCopyDialog({
(domain: string, cookies: UnifiedCookie[]) => {
setSelection((prev) => {
const current = prev[domain];
- const allSelected = current.allSelected || false;
+ const allSelected = current.allSelected;
if (allSelected) {
const newSelection = { ...prev };
@@ -171,7 +172,7 @@ export function CookieCopyDialog({
const toggleCookie = useCallback(
(domain: string, cookieName: string, totalCookies: number) => {
setSelection((prev) => {
- const current = prev[domain] || {
+ const current = prev[domain] ?? {
allSelected: false,
cookies: new Set(),
};
@@ -503,8 +504,8 @@ function DomainRow({
onToggleExpand,
}: DomainRowProps) {
const domainSelection = selection[domain.domain];
- const isAllSelected = domainSelection.allSelected || false;
- const selectedCount = domainSelection.cookies.size || 0;
+ const isAllSelected = domainSelection.allSelected;
+ const selectedCount = domainSelection.cookies.size;
const isPartial =
selectedCount > 0 && selectedCount < domain.cookie_count && !isAllSelected;
@@ -539,8 +540,7 @@ function DomainRow({
{isExpanded && (
{domain.cookies.map((cookie) => {
- const isSelected =
- domainSelection.cookies.has(cookie.name) || false;
+ const isSelected = domainSelection.cookies.has(cookie.name);
return (
;
- };
-}
+ }
+>;
const countCookies = (content: string): number => {
const trimmed = content.trim();
@@ -329,7 +330,7 @@ export function CookieManagementDialog({
const toggleCookie = useCallback(
(domain: string, cookieName: string, totalCookies: number) => {
setExportSelection((prev) => {
- const current = prev[domain] || {
+ const current = prev[domain] ?? {
allSelected: false,
cookies: new Set
(),
};
@@ -591,8 +592,8 @@ function ExportDomainRow({
onToggleExpand,
}: ExportDomainRowProps) {
const domainSelection = selection[domain.domain];
- const isAllSelected = domainSelection.allSelected || false;
- const selectedCount = domainSelection.cookies.size || 0;
+ const isAllSelected = domainSelection.allSelected;
+ const selectedCount = domainSelection.cookies.size;
const isPartial =
selectedCount > 0 && selectedCount < domain.cookie_count && !isAllSelected;
@@ -627,8 +628,7 @@ function ExportDomainRow({
{isExpanded && (
{domain.cookies.map((cookie) => {
- const isSelected =
- domainSelection.cookies.has(cookie.name) || false;
+ const isSelected = domainSelection.cookies.has(cookie.name);
return (
handleDownload("wayfern")}
+ onClick={() => {
+ void handleDownload("wayfern");
+ }}
isLoading={isBrowserCurrentlyDownloading(
"wayfern",
)}
@@ -856,7 +858,9 @@ export function CreateProfileDialog({
})()}
handleDownload("camoufox")}
+ onClick={() => {
+ void handleDownload("camoufox");
+ }}
isLoading={isBrowserCurrentlyDownloading(
"camoufox",
)}
@@ -963,9 +967,9 @@ export function CreateProfileDialog({
})()}
- handleDownload(selectedBrowser)
- }
+ onClick={() => {
+ void handleDownload(selectedBrowser);
+ }}
isLoading={isBrowserCurrentlyDownloading(
selectedBrowser,
)}
@@ -1163,7 +1167,7 @@ export function CreateProfileDialog({
) : (