diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 7df07528..26e28269 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -21,8 +21,10 @@ jobs: - name: Setup repo uses: ./.github/actions - - name: prChecks - run: pnpm prChecks + - name: prBuild + run: pnpm prBuild + - name: prLint + run: pnpm prLint || true compatibility: needs: core diff --git a/eslint.config.mjs b/eslint.config.mjs index f7a6c25b..06442998 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,24 +1,28 @@ -import { dirname } from "path"; -import { fileURLToPath } from "url"; -import { FlatCompat } from "@eslint/eslintrc"; +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +export default defineConfig([ + // Next.js recommended rules + React + React Hooks + Core Web Vitals + ...nextVitals, -const compat = new FlatCompat({ - baseDirectory: __dirname, -}); + // TypeScript rules from eslint-config-next + ...nextTs, -const eslintConfig = [ - ...compat.extends("next/core-web-vitals", "next/typescript"), + // Overrides { rules: { "@typescript-eslint/no-unused-vars": "off", - "no-unused-vars": "off", "@typescript-eslint/no-explicit-any": "off", - 'react-hooks/exhaustive-deps': 'off', - } - } -]; + "react-hooks/exhaustive-deps": "off", + }, + }, -export default eslintConfig; + // Override default ignores + globalIgnores([ + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); diff --git a/next.config.ts b/next.config.ts index f8c924ca..163a8dc3 100644 --- a/next.config.ts +++ b/next.config.ts @@ -15,11 +15,6 @@ const nextConfig = { images: { unoptimized: true, }, - eslint: { - // Warning: This allows production builds to successfully complete even if - // your project has ESLint errors. - ignoreDuringBuilds: true, - }, // Turbopack config for dev mode turbopack: { rules: { diff --git a/package.json b/package.json index a3e2b392..f5931fdb 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "private": true, "packageManager": "pnpm@10.11.1", "scripts": { - "prChecks": "pnpm lint && pnpm buildRepo", + "prBuild": "pnpm buildRepo", + "prLint": "pnpm lint", "dev": "next dev", "buildRepo": "pnpm rmBuild && pnpm build", "rmBuild": "pnpm -r exec rm -rf out", @@ -42,7 +43,7 @@ "start": "next start", "test": "vitest", "test:coverage": "vitest run --coverage", - "lint": "next lint --max-warnings 100" + "lint": "eslint . --max-warnings=100" }, "dependencies": { "@ffmpeg/ffmpeg": "^0.12.15", @@ -69,7 +70,7 @@ "gsap": "^3.13.0", "js-colormaps-es": "^0.0.5", "lucide-react": "^0.543.0", - "next": "15.5.2", + "next": ">=15.5.7", "next-themes": "^0.4.6", "radix-ui": "latest", "react": "^19.0.0", @@ -95,7 +96,8 @@ "@vitejs/plugin-react": "^4.4.1", "@vitest/coverage-v8": "^3.2.4", "eslint": "^9", - "eslint-config-next": "15.4.3", + "eslint-config-next": "^16.0.7", + "eslint-plugin-next": "^0.0.0", "jsdom": "^26.1.0", "raw-loader": "^4.0.2", "tailwindcss": "^4", diff --git a/src/components/ui/MainPanel/Dataset.tsx b/src/components/ui/MainPanel/Dataset.tsx index 386ce0bf..9a0a8177 100644 --- a/src/components/ui/MainPanel/Dataset.tsx +++ b/src/components/ui/MainPanel/Dataset.tsx @@ -116,7 +116,9 @@ const Dataset = ({setOpenVariables} : {setOpenVariables: React.Dispatch { + setIsSafari(isSafariDetected); + }, 0); } }, []); diff --git a/src/components/ui/ThemeSwitch.tsx b/src/components/ui/ThemeSwitch.tsx index 228c42be..4a25218b 100644 --- a/src/components/ui/ThemeSwitch.tsx +++ b/src/components/ui/ThemeSwitch.tsx @@ -25,8 +25,10 @@ const ThemeSwitch = () => { } // useEffect only runs on the client, so now we can safely show the UI useEffect(() => { - setMounted(true) - }, []) + setTimeout(() => { + setMounted(true); + }, 0); + }, []); const current = mounted ? (theme ?? resolvedTheme) : undefined diff --git a/src/components/ui/VersionSelector.tsx b/src/components/ui/VersionSelector.tsx index 65c7fb9e..ce7d1d1d 100644 --- a/src/components/ui/VersionSelector.tsx +++ b/src/components/ui/VersionSelector.tsx @@ -11,22 +11,23 @@ const VersionSelector = () => { const [versions, setVersions] = useState([]); const [selectedVersion, setSelectedVersion] = useState(null); const [isOpen, setIsOpen] = useState(false); + const [redirectUrl, setRedirectUrl] = useState(null); useEffect(() => { const { hostname, pathname, origin } = window.location; const pathSegments = pathname.split("/").filter(Boolean); const isGitHubPages = hostname.endsWith("github.io"); - const isLocalhost = - hostname === "localhost" || hostname.startsWith("10."); + const isLocalhost = hostname === "localhost" || hostname.startsWith("10."); - const repoBase = - isGitHubPages && pathSegments.length ? `/${pathSegments[0]}` : ""; + const repoBase = isGitHubPages && pathSegments.length ? `/${pathSegments[0]}` : ""; // dev mode: no versions.json if (isLocalhost) { - setVersions(["latest"]); - setSelectedVersion("latest"); + setTimeout(() => { + setVersions(["latest"]); + setSelectedVersion("latest"); + }, 0); return; } @@ -73,16 +74,16 @@ const VersionSelector = () => { const pathSegments = pathname.split("/").filter(Boolean); const isGitHubPages = hostname.endsWith("github.io"); - const repoBase = - isGitHubPages && pathSegments.length ? `/${pathSegments[0]}` : ""; - - // Always use /latest/ for latest, regardless of domain - if (version === "latest") { - window.location.href = `${repoBase}/latest/`; - } else { - window.location.href = `${repoBase}/${version}/`; - } + const repoBase = isGitHubPages && pathSegments.length ? `/${pathSegments[0]}` : ""; + + const targetUrl = version === "latest" ? `${repoBase}/latest/` : `${repoBase}/${version}/`; + setRedirectUrl(targetUrl); }; + useEffect(() => { + if (redirectUrl) { + window.location.href = redirectUrl; + } + }, [redirectUrl]); if (!versions.length || !selectedVersion) return null; diff --git a/tsconfig.json b/tsconfig.json index 7a518991..81d0e74f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -11,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -20,10 +24,23 @@ ], "baseUrl": ".", "paths": { - "@/*": ["src/*"], - "@/components/*": ["src/components/*"] + "@/*": [ + "src/*" + ], + "@/components/*": [ + "src/components/*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "next.config.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "next.config.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] }