diff --git a/.gitignore b/.gitignore index 879d147..34b9002 100644 --- a/.gitignore +++ b/.gitignore @@ -61,4 +61,5 @@ next-env.d.ts .VSCodeCounter # ──────────────── Contributor generated files ──────────────── -scripts/contributors/*.html \ No newline at end of file +scripts/contributors/*.html.env.local +.env.*.local diff --git a/app/(core)/components/AuthStatus.tsx b/app/(core)/components/AuthStatus.tsx new file mode 100644 index 0000000..41fcc3f --- /dev/null +++ b/app/(core)/components/AuthStatus.tsx @@ -0,0 +1,102 @@ +"use client"; +import React, { useEffect, useState } from "react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faGithub } from "@fortawesome/free-brands-svg-icons"; +import { faSignOutAlt } from "@fortawesome/free-solid-svg-icons"; + +type AuthState = { + authenticated: boolean; + username?: string; + avatarUrl?: string; +}; + +const AUTH_ERROR_MESSAGES: Record = { + state_mismatch: "Sign-in failed a security check. Please try again.", + missing_code: "GitHub didn't return an authorization code. Please try again.", + server_not_configured: "GitHub sign-in isn't configured on this server yet.", + token_exchange_failed: + "Couldn't complete sign-in with GitHub. Please try again.", + unexpected: "Something went wrong during sign-in. Please try again.", +}; + +export default function AuthStatus({ + onAuthChange, +}: { + onAuthChange?: (state: AuthState) => void; +}) { + const [auth, setAuth] = useState({ authenticated: false }); + const [loading, setLoading] = useState(true); + const [authError, setAuthError] = useState(null); + + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const errorCode = params.get("auth_error"); + if (errorCode) { + setAuthError( + AUTH_ERROR_MESSAGES[errorCode] || "Sign-in failed. Please try again." + ); + // Clean the error out of the URL so a refresh doesn't re-show it. + params.delete("auth_error"); + const newSearch = params.toString(); + window.history.replaceState( + {}, + "", + window.location.pathname + (newSearch ? `?${newSearch}` : "") + ); + } + + fetch("/api/auth/me") + .then((res) => res.json()) + .then((data: AuthState) => { + setAuth(data); + onAuthChange?.(data); + }) + .catch(() => setAuth({ authenticated: false })) + .finally(() => setLoading(false)); + }, []); + + const handleSignOut = async () => { + await fetch("/api/auth/github/logout", { method: "POST" }); + setAuth({ authenticated: false }); + onAuthChange?.({ authenticated: false }); + }; + + if (loading) return null; + + if (!auth.authenticated) { + return ( +
+ {authError &&

{authError}

} + + Sign in with GitHub to publish + +
+ ); + } + + return ( +
+ {auth.avatarUrl && ( + // eslint-disable-next-line @next/next/no-img-element + {auth.username} + )} + + Publishing as @{auth.username} + + +
+ ); +} diff --git a/app/(core)/lib/githubSession.ts b/app/(core)/lib/githubSession.ts new file mode 100644 index 0000000..b6a11cf --- /dev/null +++ b/app/(core)/lib/githubSession.ts @@ -0,0 +1,47 @@ +import { cookies } from "next/headers"; + +const SESSION_COOKIE = "gh_session"; + +// The cookie value is just the GitHub access token. It's set as an +// httpOnly, secure, sameSite=lax cookie so it's never readable from +// client-side JS, but is still sent on the top-level OAuth redirect. +export async function getSessionToken(): Promise { + const store = await cookies(); + return store.get(SESSION_COOKIE)?.value ?? null; +} + +export async function setSessionToken(token: string) { + const store = await cookies(); + store.set(SESSION_COOKIE, token, { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax", + path: "/", + maxAge: 60 * 60 * 8, // 8 hours + }); +} + +export async function clearSessionToken() { + const store = await cookies(); + store.delete(SESSION_COOKIE); +} + +const OAUTH_STATE_COOKIE = "gh_oauth_state"; + +export async function setOAuthState(state: string) { + const store = await cookies(); + store.set(OAUTH_STATE_COOKIE, state, { + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax", + path: "/", + maxAge: 60 * 10, // 10 minutes — just long enough for the OAuth round trip + }); +} + +export async function consumeOAuthState(): Promise { + const store = await cookies(); + const value = store.get(OAUTH_STATE_COOKIE)?.value ?? null; + store.delete(OAUTH_STATE_COOKIE); + return value; +} diff --git a/app/(core)/styles/index.css b/app/(core)/styles/index.css index 839895e..88b3fd9 100644 --- a/app/(core)/styles/index.css +++ b/app/(core)/styles/index.css @@ -3275,6 +3275,42 @@ footer { font-weight: 600; } +.auth-status-banner { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + margin-bottom: 1.5rem; + border: 1px solid var(--border-color); + border-radius: var(--border-radius); + background: color-mix(in oklab, var(--accent-color), transparent 94%); + font-size: 0.9rem; +} + +.auth-status-signed-in { + justify-content: flex-start; +} + +.auth-status-avatar { + width: 24px; + height: 24px; + border-radius: 50%; +} + +.auth-status-signout { + margin-left: auto; +} + +.auth-status-error { + color: var(--danger-color, #e53e3e); + font-size: 0.85rem; + margin: 0; +} + +.auth-status-signin { + text-decoration: none; +} + .blog-editor-area { padding: 0; } diff --git a/app/(pages)/blog/create/page.tsx b/app/(pages)/blog/create/page.tsx index 8d0ff03..25780d5 100644 --- a/app/(pages)/blog/create/page.tsx +++ b/app/(pages)/blog/create/page.tsx @@ -34,6 +34,7 @@ import { arrayMove, } from "@dnd-kit/sortable"; import { BlogContent } from "../../../(core)/components/theory/types"; +import AuthStatus from "../../../(core)/components/AuthStatus"; // --- INTERFACCE TYPESCRIPT --- @@ -391,6 +392,7 @@ export default function CreateBlogPage() { const [viewMode, setViewMode] = useState<"Editor" | "JS" | "Preview">( "Editor" ); + const [isAuthenticated, setIsAuthenticated] = useState(false); const dataContentString = useMemo( () => objectToJSString(dataContent), @@ -487,6 +489,9 @@ export default function CreateBlogPage() { t("Request sent successfully! The blog will be online after review.") ); router.push("/blog"); // Torna alla lista + } else if (result.requiresAuth) { + alert("Please sign in with GitHub first, then try saving again."); + window.location.href = "/api/auth/github"; } else { throw new Error(result.error); } @@ -564,11 +569,19 @@ export default function CreateBlogPage() { onClick={handleSave} className="ph-btn ph-btn--primary cursor-pointer save-button-top" type="button" + disabled={!isAuthenticated} + title={ + !isAuthenticated ? "Sign in with GitHub to publish" : undefined + } > {t("Save")} + setIsAuthenticated(state.authenticated)} + /> +
{ diff --git a/app/api/auth/github/callback/route.ts b/app/api/auth/github/callback/route.ts new file mode 100644 index 0000000..5037cf4 --- /dev/null +++ b/app/api/auth/github/callback/route.ts @@ -0,0 +1,68 @@ +import { NextResponse } from "next/server"; +import { + setSessionToken, + consumeOAuthState, +} from "../../../../(core)/lib/githubSession"; + +export async function GET(req: Request) { + const url = new URL(req.url); + const code = url.searchParams.get("code"); + const state = url.searchParams.get("state"); + const returnTo = "/blog/create"; + + const expectedState = await consumeOAuthState(); + if (!state || !expectedState || state !== expectedState) { + return NextResponse.redirect( + new URL(`${returnTo}?auth_error=state_mismatch`, req.url) + ); + } + + if (!code) { + return NextResponse.redirect( + new URL(`${returnTo}?auth_error=missing_code`, req.url) + ); + } + + const clientId = process.env.GITHUB_CLIENT_ID; + const clientSecret = process.env.GITHUB_CLIENT_SECRET; + if (!clientId || !clientSecret) { + return NextResponse.redirect( + new URL(`${returnTo}?auth_error=server_not_configured`, req.url) + ); + } + + try { + const tokenRes = await fetch( + "https://github.com/login/oauth/access_token", + { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ + client_id: clientId, + client_secret: clientSecret, + code, + }), + } + ); + + const tokenData = await tokenRes.json(); + + if (!tokenData.access_token) { + console.error("GitHub OAuth token exchange failed:", tokenData); + return NextResponse.redirect( + new URL(`${returnTo}?auth_error=token_exchange_failed`, req.url) + ); + } + + await setSessionToken(tokenData.access_token); + return NextResponse.redirect(new URL(returnTo, req.url)); + } catch (error) { + console.error("GitHub OAuth callback error:", error); + return NextResponse.redirect( + new URL(`${returnTo}?auth_error=unexpected`, req.url) + ); + } +} diff --git a/app/api/auth/github/logout/route.ts b/app/api/auth/github/logout/route.ts new file mode 100644 index 0000000..9048957 --- /dev/null +++ b/app/api/auth/github/logout/route.ts @@ -0,0 +1,7 @@ +import { NextResponse } from "next/server"; +import { clearSessionToken } from "../../../../(core)/lib/githubSession"; + +export async function POST() { + await clearSessionToken(); + return NextResponse.json({ success: true }); +} diff --git a/app/api/auth/github/route.ts b/app/api/auth/github/route.ts new file mode 100644 index 0000000..2dfb26a --- /dev/null +++ b/app/api/auth/github/route.ts @@ -0,0 +1,31 @@ +import { NextResponse } from "next/server"; +import { randomBytes } from "crypto"; +import { setOAuthState } from "../../../(core)/lib/githubSession"; + +export async function GET(req: Request) { + const clientId = process.env.GITHUB_CLIENT_ID; + if (!clientId) { + return NextResponse.json( + { + error: + "GitHub OAuth is not configured on this server (missing GITHUB_CLIENT_ID).", + }, + { status: 500 } + ); + } + + // CSRF protection: generate a random state, store it server-side, + // and verify it matches on the callback before exchanging the code. + const state = randomBytes(16).toString("hex"); + await setOAuthState(state); + + const redirectUri = new URL("/api/auth/github/callback", req.url).toString(); + + const authorizeUrl = new URL("https://github.com/login/oauth/authorize"); + authorizeUrl.searchParams.set("client_id", clientId); + authorizeUrl.searchParams.set("redirect_uri", redirectUri); + authorizeUrl.searchParams.set("scope", "public_repo"); + authorizeUrl.searchParams.set("state", state); + + return NextResponse.redirect(authorizeUrl.toString()); +} diff --git a/app/api/auth/me/route.ts b/app/api/auth/me/route.ts new file mode 100644 index 0000000..f971226 --- /dev/null +++ b/app/api/auth/me/route.ts @@ -0,0 +1,24 @@ +import { NextResponse } from "next/server"; +import { Octokit } from "@octokit/rest"; +import { getSessionToken } from "../../../(core)/lib/githubSession"; + +export async function GET() { + const token = await getSessionToken(); + if (!token) { + return NextResponse.json({ authenticated: false }); + } + + try { + const octokit = new Octokit({ auth: token }); + const { data: user } = await octokit.users.getAuthenticated(); + return NextResponse.json({ + authenticated: true, + username: user.login, + avatarUrl: user.avatar_url, + }); + } catch (error) { + // Token is invalid or expired — treat as signed out rather than erroring. + console.error("Failed to fetch authenticated GitHub user:", error); + return NextResponse.json({ authenticated: false }); + } +} diff --git a/app/api/publish/route.ts b/app/api/publish/route.ts index c451d81..f2de277 100644 --- a/app/api/publish/route.ts +++ b/app/api/publish/route.ts @@ -1,8 +1,57 @@ import { NextResponse } from "next/server"; import { Octokit } from "@octokit/rest"; import prettier from "prettier"; +import { getSessionToken } from "../../(core)/lib/githubSession"; + +const UPSTREAM_OWNER = "physicshub"; +const REPO = "physicshub.github.io"; + +// Forking is asynchronous on GitHub's side — right after createFork(), +// the fork may not be immediately ready to accept getRef()/createRef() calls. +// Poll briefly until it's available rather than failing outright. +async function waitForForkReady( + octokit: Octokit, + owner: string, + repo: string, + attempts = 6 +) { + for (let i = 0; i < attempts; i++) { + try { + await octokit.git.getRef({ owner, repo, ref: "heads/main" }); + return; // fork is ready + } catch { + await new Promise((resolve) => setTimeout(resolve, 1500)); + } + } + throw new Error( + "Timed out waiting for your fork to become ready. Please try again in a moment." + ); +} + +async function ensureForkExists(octokit: Octokit, username: string) { + try { + await octokit.repos.get({ owner: username, repo: REPO }); + // Fork already exists, nothing to do. + } catch { + await octokit.repos.createFork({ owner: UPSTREAM_OWNER, repo: REPO }); + await waitForForkReady(octokit, username, REPO); + } +} + export async function POST(req: Request) { try { + const token = await getSessionToken(); + if (!token) { + return NextResponse.json( + { + success: false, + error: "You need to sign in with GitHub before publishing.", + requiresAuth: true, + }, + { status: 401 } + ); + } + const body = await req.json(); const { jsonContent } = body; if ( @@ -22,10 +71,14 @@ export async function POST(req: Request) { } const { title } = jsonContent; - const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); + const octokit = new Octokit({ auth: token }); - const owner = "AgnibhaDebnath"; // TODO: Replace with authenticated GitHub username once OAuth is implemented - const repo = "physicshub.github.io"; + // Determine the contributor's own GitHub identity from their token, + // rather than a hardcoded username. + const { data: authenticatedUser } = await octokit.users.getAuthenticated(); + const owner = authenticatedUser.login; + + await ensureForkExists(octokit, owner); // Generate a clean slug const slug = title @@ -48,39 +101,40 @@ export async function POST(req: Request) { parser: "json", }); - // 1. Get the reference to the main branch - const { data: mainBranch } = await octokit.git.getRef({ - owner, - repo, + // 1. Get the latest commit from upstream's main, so the proposal branches + // from fresh code rather than a potentially stale fork. + const { data: upstreamMain } = await octokit.git.getRef({ + owner: UPSTREAM_OWNER, + repo: REPO, ref: "heads/main", }); - // 2. Create a new branch for the proposal + // 2. Create a new branch in the contributor's fork await octokit.git.createRef({ owner, - repo, + repo: REPO, ref: `refs/heads/${branchName}`, - sha: mainBranch.object.sha, + sha: upstreamMain.object.sha, }); // 3. Create the file in the new branch await octokit.repos.createOrUpdateFileContents({ owner, - repo, + repo: REPO, path: fileName, message: `New blog proposal: ${title}`, content: Buffer.from(formattedContent).toString("base64"), branch: branchName, }); - // 4. Open the Pull Request + // 4. Open the Pull Request against upstream const { data: pr } = await octokit.pulls.create({ - owner: "physicshub", - repo, + owner: UPSTREAM_OWNER, + repo: REPO, title: `📝 Blog Proposal: ${title}`, head: `${owner}:${branchName}`, base: "main", - body: `New blog proposal submitted through the website editor.\n\nTitle: ${title}`, + body: `New blog proposal submitted through the website editor by @${owner}.\n\nTitle: ${title}`, }); return NextResponse.json({ success: true, url: pr.html_url }); diff --git a/next.config.js b/next.config.js index a216c29..2082b38 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,21 @@ import packageJson from "./package.json" with { type: "json" }; +// GitHub Pages needs a fully static export (no server, no API routes). +// Vercel needs the opposite — a normal Next.js app so API routes like +// /api/auth/* and /api/publish actually run server-side. Vercel sets the +// VERCEL env var automatically on every build, so we use that to decide +// which mode to build in, rather than needing a second config file. +// +// Also exclude local dev (`next dev`, NODE_ENV=development) — contributors +// need working API routes to test locally, and only `next build` (used by +// both the GitHub Pages CI job and Vercel) should ever produce a static +// export in the first place. +const isVercelBuild = !!process.env.VERCEL; +const isProductionBuild = process.env.NODE_ENV === "production"; +const shouldStaticExport = isProductionBuild && !isVercelBuild; + const nextConfig = { - output: "export", + ...(shouldStaticExport ? { output: "export" } : {}), env: { NEXT_PUBLIC_APP_VERSION: packageJson.version, }, diff --git a/package.json b/package.json index c95fb9b..6011099 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "next dev & nodemon --watch src/routes.js --watch public/index.html --exec \"npm run generate:sitemap\"", "build": "npm run generate:sitemap && next build", + "build:static": "npm run generate:sitemap && node scripts/strip-api-for-static-export.js && next build", "preview": "npm run build && npx serve@latest out", "predeploy": "npm run build && npm run contributors", "deploy": "gh-pages -d out", diff --git a/public/sitemap.xml b/public/sitemap.xml index 082efe5..c1a5a06 100644 --- a/public/sitemap.xml +++ b/public/sitemap.xml @@ -3,193 +3,193 @@ https://physicshub.github.io/ - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 1.0 https://physicshub.github.io/contribute - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/simulations - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.9 https://physicshub.github.io/about - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.7 https://physicshub.github.io/blog - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.9 https://physicshub.github.io/blog/create - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.7 https://physicshub.github.io/blog/what-is-physics - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/class-12-physics-complete-guide - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/physics-bouncing-ball-comprehensive-educational-guide - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/comprehensive-guide-to-vector-operations - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/ball-uniformly-accelerated-motion - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/ball-free-fall-comprehensive-guide - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/spring-connection - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/physics-of-pendulum-explained - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/projectile-parabolic-motion - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/physics-behind-three-body-problem - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/blog/pi-from-block-collisions-explained - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z monthly 0.8 https://physicshub.github.io/simulations/BouncingBall - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/VectorsOperations - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/BallAcceleration - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/BallGravity - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/SpringConnection - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/SimplePendulum - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/ParabolicMotion - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/InclinedPlane - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/CircularMotion - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/ThreeBody - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/HorizontalSpring - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/DoublePendulum - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/CollisionSimulation - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/test - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 https://physicshub.github.io/simulations/PiCollisions - 2026-07-04T00:00:00.000Z + 2026-07-12T00:00:00.000Z weekly 0.7 diff --git a/routes.js b/routes.js index 30222b2..b1737cb 100644 --- a/routes.js +++ b/routes.js @@ -39,156 +39,156 @@ export const routes = [ path: "/blog/what-is-physics", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/class-12-physics-complete-guide", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/physics-bouncing-ball-comprehensive-educational-guide", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/comprehensive-guide-to-vector-operations", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/ball-uniformly-accelerated-motion", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/ball-free-fall-comprehensive-guide", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/spring-connection", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/physics-of-pendulum-explained", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/projectile-parabolic-motion", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/physics-behind-three-body-problem", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/blog/pi-from-block-collisions-explained", changefreq: "monthly", priority: 0.8, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/BouncingBall", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/VectorsOperations", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/BallAcceleration", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/BallGravity", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/SpringConnection", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/SimplePendulum", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/ParabolicMotion", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/InclinedPlane", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/CircularMotion", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/ThreeBody", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/HorizontalSpring", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/DoublePendulum", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/CollisionSimulation", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/test", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, { path: "/simulations/PiCollisions", changefreq: "weekly", priority: 0.7, - lastmod: "2026-07-04", + lastmod: "2026-07-12", }, ]; diff --git a/scripts/contributors/contributors.html b/scripts/contributors/contributors.html index cbf8f59..00c1213 100644 --- a/scripts/contributors/contributors.html +++ b/scripts/contributors/contributors.html @@ -1,1864 +1,2049 @@ - - - -
    + + + + + + +
    • - mattqdev + mattqdev

      mattqdev

      -
      -
      - + 93139 -
      -
      - 45.62% -
      -
      -
      -
      - 270 commits -
      -
      - 41.79% -
      -
      -
      -
      - - 36374 -
      -
      - 28.61% -
      +
      +
      + + 93139
      +
      + 45.62% +
      +
      +
      +
      + 270 commits +
      +
      + 41.79% +
      +
      +
      +
      + - 36374 +
      +
      + 28.61% +
      +
    • - dependabot[bot] + dependabot[bot]

      dependabot[bot]

      -
      -
      - + 48096 -
      -
      - 23.56% -
      -
      -
      -
      - 90 commits -
      -
      - 7.58% -
      -
      -
      -
      - - 6975 -
      -
      - 5.49% -
      +
      +
      + + 48096 +
      +
      + 23.56% +
      +
      +
      +
      + 90 commits +
      +
      + 7.58% +
      +
      +
      +
      + - 6975 +
      +
      + 5.49%
      +
    • - github-actions[bot] + github-actions[bot]

      github-actions[bot]

      -
      -
      - + 21842 -
      -
      - 10.70% -
      -
      -
      -
      - 217 commits -
      -
      - 18.28% -
      -
      -
      -
      - - 63486 -
      -
      - 49.93% -
      +
      +
      + + 21842
      +
      + 10.70% +
      +
      +
      +
      + 217 commits +
      +
      + 18.28% +
      +
      +
      +
      + - 63486 +
      +
      + 49.93% +
      +
    • - YuSuBH + YuSuBH

      YuSuBH

      -
      -
      - + 8496 -
      -
      - 4.16% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 3482 -
      -
      - 2.74% -
      +
      +
      + + 8496 +
      +
      + 4.16% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 3482
      +
      + 2.74% +
      +
    • - maaviah17 + maaviah17

      maaviah17

      -
      -
      - + 5768 -
      -
      - 2.83% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 5749 -
      -
      - 4.52% -
      +
      +
      + + 5768 +
      +
      + 2.83% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 5749
      +
      + 4.52% +
      +
    • - prashantchauhan-12 + prashantchauhan-12

      prashantchauhan-12

      -
      -
      - + 5467 -
      -
      - 2.68% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 376 -
      -
      - 0.30% -
      +
      +
      + + 5467 +
      +
      + 2.68% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 376
      +
      + 0.30% +
      +
    • - akshatj0630 + akshatj0630

      akshatj0630

      -
      -
      - + 5018 -
      -
      - 2.46% -
      -
      -
      -
      - 5 commits -
      -
      - 0.59% -
      -
      -
      -
      - - 4995 -
      -
      - 3.93% -
      +
      +
      + + 5018 +
      +
      + 2.46% +
      +
      +
      +
      + 5 commits +
      +
      + 0.59% +
      +
      +
      +
      + - 4995
      +
      + 3.93% +
      +
    • - FaresAyadi055 + FaresAyadi055

      FaresAyadi055

      -
      -
      - + 1753 -
      -
      - 0.86% -
      -
      -
      -
      - 8 commits -
      -
      - 1.18% -
      -
      -
      -
      - - 112 -
      -
      - 0.09% -
      +
      +
      + + 1753 +
      +
      + 0.86% +
      +
      +
      +
      + 8 commits +
      +
      + 1.18%
      +
      +
      +
      + - 112 +
      +
      + 0.09% +
      +
    • - neelavradutta + neelavradutta

      neelavradutta

      -
      -
      - + 1311 -
      -
      - 0.64% -
      -
      -
      -
      - 3 commits -
      -
      - 0.34% -
      -
      -
      -
      - - 109 -
      -
      - 0.09% -
      +
      +
      + + 1311 +
      +
      + 0.64% +
      +
      +
      +
      + 3 commits +
      +
      + 0.34%
      +
      +
      +
      + - 109 +
      +
      + 0.09% +
      +
    • - AgnibhaDebnath + AgnibhaDebnath

      AgnibhaDebnath

      -
      -
      - + 1210 -
      -
      - 0.59% -
      -
      -
      -
      - 15 commits -
      -
      - 1.26% -
      -
      -
      -
      - - 263 -
      -
      - 0.21% -
      +
      +
      + + 1210 +
      +
      + 0.59% +
      +
      +
      +
      + 15 commits +
      +
      + 1.26%
      +
      +
      +
      + - 263 +
      +
      + 0.21% +
      +
    • - czjzpz + czjzpz

      czjzpz

      -
      -
      - + 989 -
      -
      - 0.48% -
      -
      -
      -
      - 6 commits -
      -
      - 0.51% -
      -
      -
      -
      - - 255 -
      -
      - 0.20% -
      +
      +
      + + 989 +
      +
      + 0.48% +
      +
      +
      +
      + 6 commits +
      +
      + 0.51%
      +
      +
      +
      + - 255 +
      +
      + 0.20% +
      +
    • - meet-shah820 + meet-shah820

      meet-shah820

      -
      -
      - + 958 -
      -
      - 0.47% -
      -
      -
      -
      - 5 commits -
      -
      - 0.59% -
      -
      -
      -
      - - 524 -
      -
      - 0.41% -
      +
      +
      + + 958 +
      +
      + 0.47% +
      +
      +
      +
      + 5 commits
      +
      + 0.59% +
      +
      +
      +
      + - 524 +
      +
      + 0.41% +
      +
    • - Bechiir69 + Bechiir69

      Bechiir69

      -
      -
      - + 944 -
      -
      - 0.46% -
      -
      -
      -
      - 6 commits -
      -
      - 0.76% -
      -
      -
      -
      - - 814 -
      -
      - 0.64% -
      +
      +
      + + 944 +
      +
      + 0.46% +
      +
      +
      +
      + 6 commits
      +
      + 0.76% +
      +
      +
      +
      + - 814 +
      +
      + 0.64% +
      +
    • - Ninja3031 + Ninja3031

      Ninja3031

      -
      -
      - + 855 -
      -
      - 0.42% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 524 -
      -
      - 0.41% -
      +
      +
      + + 855 +
      +
      + 0.42% +
      +
      +
      +
      + 2 commits
      +
      + 0.17% +
      +
      +
      +
      + - 524 +
      +
      + 0.41% +
      +
    • - txgh25 + txgh25

      txgh25

      -
      -
      - + 840 -
      -
      - 0.41% -
      -
      -
      -
      - 15 commits -
      -
      - 1.35% -
      -
      -
      -
      - - 150 -
      -
      - 0.12% -
      +
      +
      + + 840 +
      +
      + 0.41% +
      +
      +
      +
      + 15 commits
      +
      + 1.35% +
      +
      +
      +
      + - 150 +
      +
      + 0.12% +
      +
    • - Axestein + Axestein

      Axestein

      -
      -
      - + 767 -
      -
      - 0.38% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 341 -
      -
      - 0.27% -
      +
      +
      + + 767 +
      +
      + 0.38%
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 341 +
      +
      + 0.27% +
      +
    • - TechGenius-Karan + TechGenius-Karan

      TechGenius-Karan

      -
      -
      - + 735 -
      -
      - 0.36% -
      -
      -
      -
      - 17 commits -
      -
      - 1.43% -
      -
      -
      -
      - - 551 -
      -
      - 0.43% -
      +
      +
      + + 735 +
      +
      + 0.36%
      +
      +
      +
      + 17 commits +
      +
      + 1.43% +
      +
      +
      +
      + - 551 +
      +
      + 0.43% +
      +
    • - petercr + petercr

      petercr

      -
      -
      - + 732 -
      -
      - 0.36% -
      -
      -
      -
      - 7 commits -
      -
      - 0.93% -
      -
      -
      -
      - - 187 -
      -
      - 0.15% -
      +
      +
      + + 732 +
      +
      + 0.36%
      +
      +
      +
      + 7 commits +
      +
      + 0.93% +
      +
      +
      +
      + - 187 +
      +
      + 0.15% +
      +
    • - joaomenkdev-cloud + joaomenkdev-cloud

      joaomenkdev-cloud

      -
      -
      - + 703 -
      -
      - 0.34% -
      -
      -
      -
      - 4 commits -
      -
      - 0.34% -
      -
      -
      -
      - - 102 -
      -
      - 0.08% -
      +
      +
      + + 703 +
      +
      + 0.34% +
      +
      +
      +
      + 4 commits +
      +
      + 0.34% +
      +
      +
      +
      + - 102 +
      +
      + 0.08%
      +
    • - mandeep-webdev + mandeep-webdev

      mandeep-webdev

      -
      -
      - + 691 -
      -
      - 0.34% -
      -
      -
      -
      - 6 commits -
      -
      - 0.51% -
      -
      -
      -
      - - 132 -
      -
      - 0.10% -
      +
      +
      + + 691
      +
      + 0.34% +
      +
      +
      +
      + 6 commits +
      +
      + 0.51% +
      +
      +
      +
      + - 132 +
      +
      + 0.10% +
      +
    • - allcontributors[bot] + allcontributors[bot]

      allcontributors[bot]

      -
      -
      - + 497 -
      -
      - 0.24% -
      -
      -
      -
      - 74 commits -
      -
      - 6.23% -
      -
      -
      -
      - - 76 -
      -
      - 0.06% -
      +
      +
      + + 497 +
      +
      + 0.24% +
      +
      +
      +
      + 74 commits +
      +
      + 6.23% +
      +
      +
      +
      + - 76 +
      +
      + 0.06%
      +
    • - DevxNadeem + DevxNadeem

      DevxNadeem

      -
      -
      - + 443 -
      -
      - 0.22% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 190 -
      -
      - 0.15% -
      +
      +
      + + 443
      +
      + 0.22% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 190 +
      +
      + 0.15% +
      +
    • - arjav007 + arjav007

      arjav007

      -
      -
      - + 282 -
      -
      - 0.14% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 235 -
      -
      - 0.18% -
      +
      +
      + + 282 +
      +
      + 0.14% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 235
      +
      + 0.18% +
      +
    • - Yukesh-30 + Yukesh-30

      Yukesh-30

      -
      -
      - + 267 -
      -
      - 0.13% -
      -
      -
      -
      - 5 commits -
      -
      - 0.51% -
      -
      -
      -
      - - 17 -
      -
      - 0.01% -
      +
      +
      + + 267 +
      +
      + 0.13% +
      +
      +
      +
      + 5 commits +
      +
      + 0.51% +
      +
      +
      +
      + - 17
      +
      + 0.01% +
      +
    • - Vamshavardhan50 + Vamshavardhan50

      Vamshavardhan50

      -
      -
      - + 266 -
      -
      - 0.13% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 50 -
      -
      - 0.04% -
      +
      +
      + + 266 +
      +
      + 0.13% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 50
      +
      + 0.04% +
      +
    • - Abmarne + Abmarne

      Abmarne

      -
      -
      - + 214 -
      -
      - 0.10% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 242 -
      -
      - 0.19% -
      +
      +
      + + 214 +
      +
      + 0.10% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 242
      +
      + 0.19% +
      +
    • - shivanshpathak01 + shivanshpathak01

      shivanshpathak01

      -
      -
      - + 194 -
      -
      - 0.10% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 137 -
      -
      - 0.11% -
      +
      +
      + + 194 +
      +
      + 0.10% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17%
      +
      +
      +
      + - 137 +
      +
      + 0.11% +
      +
    • - abhijeetnardele24-hash + abhijeetnardele24-hash

      abhijeetnardele24-hash

      -
      -
      - + 180 -
      -
      - 0.09% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 2 -
      -
      - 0.00% -
      +
      +
      + + 180 +
      +
      + 0.09% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17%
      +
      +
      +
      + - 2 +
      +
      + 0.00% +
      +
    • - physicshub + physicshub

      physicshub

      -
      -
      - + 177 -
      -
      - 0.09% -
      -
      -
      -
      - 10 commits -
      -
      - 8.51% -
      -
      -
      -
      - - 20 -
      -
      - 0.02% -
      +
      +
      + + 177 +
      +
      + 0.09% +
      +
      +
      +
      + 10 commits
      +
      + 8.51% +
      +
      +
      +
      + - 20 +
      +
      + 0.02% +
      +
    • - Sindhuu-B + Sindhuu-B

      Sindhuu-B

      -
      -
      - + 170 -
      -
      - 0.08% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 49 -
      -
      - 0.04% -
      +
      +
      + + 170 +
      +
      + 0.08% +
      +
      +
      +
      + 2 commits
      +
      + 0.17% +
      +
      +
      +
      + - 49 +
      +
      + 0.04% +
      +
    • - praria + praria

      praria

      -
      -
      - + 157 -
      -
      - 0.08% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 20 -
      -
      - 0.02% -
      +
      +
      + + 157 +
      +
      + 0.08%
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 20 +
      +
      + 0.02% +
      +
    • - Talos0248 + Talos0248

      Talos0248

      -
      -
      - + 82 -
      -
      - 0.04% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 43 -
      -
      - 0.03% -
      +
      +
      + + 82 +
      +
      + 0.04%
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 43 +
      +
      + 0.03% +
      +
    • - RiriLab17 + RiriLab17

      RiriLab17

      -
      -
      - + 73 -
      -
      - 0.04% -
      -
      -
      -
      - 3 commits -
      -
      - 0.34% -
      -
      -
      -
      - - 109 -
      -
      - 0.09% -
      +
      +
      + + 73 +
      +
      + 0.04%
      +
      +
      +
      + 3 commits +
      +
      + 0.34% +
      +
      +
      +
      + - 109 +
      +
      + 0.09% +
      +
    • - ankitkr104 + ankitkr104

      ankitkr104

      -
      -
      - + 72 -
      -
      - 0.04% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 77 -
      -
      - 0.06% -
      +
      +
      + + 72 +
      +
      + 0.04% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 77 +
      +
      + 0.06%
      +
    • - Atharv1507 + Atharv1507

      Atharv1507

      -
      -
      - + 71 -
      -
      - 0.03% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 33 -
      -
      - 0.03% -
      +
      +
      + + 71
      +
      + 0.03% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 33 +
      +
      + 0.03% +
      +
    • - Sahitya3105 + Sahitya3105

      Sahitya3105

      -
      -
      - + 71 -
      -
      - 0.03% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 21 -
      -
      - 0.02% -
      +
      +
      + + 71 +
      +
      + 0.03% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 21 +
      +
      + 0.02%
      +
    • - nicolaszmarzagao + nicolaszmarzagao

      nicolaszmarzagao

      -
      -
      - + 59 -
      -
      - 0.03% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 16 -
      -
      - 0.01% -
      +
      +
      + + 59
      +
      + 0.03% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 16 +
      +
      + 0.01% +
      +
    • - pabrams + pabrams

      pabrams

      -
      -
      - + 57 -
      -
      - 0.03% -
      -
      -
      -
      - 5 commits -
      -
      - 0.42% -
      -
      -
      -
      - - 25 -
      -
      - 0.02% -
      +
      +
      + + 57 +
      +
      + 0.03% +
      +
      +
      +
      + 5 commits +
      +
      + 0.42% +
      +
      +
      +
      + - 25
      +
      + 0.02% +
      +
    • - GigaWHATT + GigaWHATT

      GigaWHATT

      -
      -
      - + 47 -
      -
      - 0.02% -
      -
      -
      -
      - 5 commits -
      -
      - 0.59% -
      -
      -
      -
      - - 4 -
      -
      - 0.00% -
      +
      +
      + + 47 +
      +
      + 0.02% +
      +
      +
      +
      + 5 commits +
      +
      + 0.59% +
      +
      +
      +
      + - 4
      +
      + 0.00% +
      +
    • - supertutto + supertutto

      supertutto

      -
      -
      - + 43 -
      -
      - 0.02% -
      -
      -
      -
      - 3 commits -
      -
      - 0.34% -
      -
      -
      -
      - - 66 -
      -
      - 0.05% -
      +
      +
      + + 43 +
      +
      + 0.02% +
      +
      +
      +
      + 3 commits +
      +
      + 0.34% +
      +
      +
      +
      + - 66
      +
      + 0.05% +
      +
    • - AhmadAnzar + AhmadAnzar

      AhmadAnzar

      -
      -
      - + 42 -
      -
      - 0.02% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 37 -
      -
      - 0.03% -
      +
      +
      + + 42 +
      +
      + 0.02% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 37
      +
      + 0.03% +
      +
    • - shauryakushwaha08 + shauryakushwaha08

      shauryakushwaha08

      -
      -
      - + 38 -
      -
      - 0.02% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 9 -
      -
      - 0.01% -
      +
      +
      + + 38 +
      +
      + 0.02% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08%
      +
      +
      +
      + - 9 +
      +
      + 0.01% +
      +
    • - Stratos-Kass + Stratos-Kass

      Stratos-Kass

      -
      -
      - + 37 -
      -
      - 0.02% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 33 -
      -
      - 0.03% -
      +
      +
      + + 37 +
      +
      + 0.02% +
      +
      +
      +
      + 3 commits +
      +
      + 0.25%
      +
      +
      +
      + - 33 +
      +
      + 0.03% +
      +
    • - iamjaysingh + iamjaysingh

      iamjaysingh

      -
      -
      - + 35 -
      -
      - 0.02% -
      -
      -
      -
      - 4 commits -
      -
      - 0.34% -
      -
      -
      -
      - - 32 -
      -
      - 0.03% -
      +
      +
      + + 35 +
      +
      + 0.02% +
      +
      +
      +
      + 4 commits
      +
      + 0.34% +
      +
      +
      +
      + - 32 +
      +
      + 0.03% +
      +
    • - ElshadHu + ElshadHu

      ElshadHu

      -
      -
      - + 35 -
      -
      - 0.02% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 9 -
      -
      - 0.01% -
      +
      +
      + + 35 +
      +
      + 0.02% +
      +
      +
      +
      + 1 commits
      +
      + 0.08% +
      +
      +
      +
      + - 9 +
      +
      + 0.01% +
      +
    • - devrajbando + devrajbando

      devrajbando

      -
      -
      - + 33 -
      -
      - 0.02% -
      -
      -
      -
      - 3 commits -
      -
      - 0.25% -
      -
      -
      -
      - - 13 -
      -
      - 0.01% -
      +
      +
      + + 33 +
      +
      + 0.02%
      +
      +
      +
      + 3 commits +
      +
      + 0.25% +
      +
      +
      +
      + - 13 +
      +
      + 0.01% +
      +
    • - koderka2020 + koderka2020

      koderka2020

      -
      -
      - + 22 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 19 -
      -
      - 0.01% -
      +
      +
      + + 22 +
      +
      + 0.01%
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 19 +
      +
      + 0.01% +
      +
    • - D1e4H + D1e4H

      D1e4H

      -
      -
      - + 22 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 6 -
      -
      - 0.00% -
      +
      +
      + + 22 +
      +
      + 0.01%
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 6 +
      +
      + 0.00% +
      +
    • - OleksandraKordonets + OleksandraKordonets

      OleksandraKordonets

      -
      -
      - + 21 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 10 -
      -
      - 0.01% -
      +
      +
      + + 21 +
      +
      + 0.01% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 10 +
      +
      + 0.01%
      +
    • - Adibayuluthfiansyah + Adibayuluthfiansyah

      Adibayuluthfiansyah

      -
      -
      - + 19 -
      -
      - 0.01% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 7 -
      -
      - 0.01% -
      +
      +
      + + 19
      +
      + 0.01% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 7 +
      +
      + 0.01% +
      +
    • - Nitin23123 + Nitin23123

      Nitin23123

      -
      -
      - + 19 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 4 -
      -
      - 0.00% -
      +
      +
      + + 19 +
      +
      + 0.01% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 4 +
      +
      + 0.00%
      +
    • - kakarot2905 + kakarot2905

      kakarot2905

      -
      -
      - + 18 -
      -
      - 0.01% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 14 -
      -
      - 0.01% -
      +
      +
      + + 18
      +
      + 0.01% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 14 +
      +
      + 0.01% +
      +
    • - Ahmed-Bardhek + Ahmed-Bardhek

      Ahmed-Bardhek

      -
      -
      - + 17 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 3 -
      -
      - 0.00% -
      +
      +
      + + 17 +
      +
      + 0.01% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 3
      +
      + 0.00% +
      +
    • - NACHO9999 + NACHO9999

      NACHO9999

      -
      -
      - + 13 -
      -
      - 0.01% -
      -
      -
      -
      - 2 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 10 -
      -
      - 0.01% -
      +
      +
      + + 13 +
      +
      + 0.01% +
      +
      +
      +
      + 2 commits +
      +
      + 0.17% +
      +
      +
      +
      + - 10
      +
      + 0.01% +
      +
    • - codeurluce + codeurluce

      codeurluce

      -
      -
      - + 13 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 0 -
      -
      - 0.00% -
      +
      +
      + + 13 +
      +
      + 0.01% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 0
      +
      + 0.00% +
      +
    • - Vaishnavi-Raykar + Vaishnavi-Raykar

      Vaishnavi-Raykar

      -
      -
      - + 11 -
      -
      - 0.01% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 8 -
      -
      - 0.01% -
      +
      +
      + + 11 +
      +
      + 0.01% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08% +
      +
      +
      +
      + - 8
      +
      + 0.01% +
      +
    • - I-had-a-bad-idea + I-had-a-bad-idea

      I-had-a-bad-idea

      -
      -
      - + 6 -
      -
      - 0.00% -
      -
      -
      -
      - 1 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 1 -
      -
      - 0.00% -
      +
      +
      + + 6 +
      +
      + 0.00% +
      +
      +
      +
      + 1 commits +
      +
      + 0.17%
      +
      +
      +
      + - 1 +
      +
      + 0.00% +
      +
    • - Siddhant52 + Siddhant52

      Siddhant52

      -
      -
      - + 6 -
      -
      - 0.00% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 3 -
      -
      - 0.00% -
      +
      +
      + + 6 +
      +
      + 0.00% +
      +
      +
      +
      + 1 commits +
      +
      + 0.08%
      +
      +
      +
      + - 3 +
      +
      + 0.00% +
      +
    • - sanketshinde3001 + sanketshinde3001

      sanketshinde3001

      -
      -
      - + 5 -
      -
      - 0.00% -
      -
      -
      -
      - 1 commits -
      -
      - 0.08% -
      -
      -
      -
      - - 2 -
      -
      - 0.00% -
      +
      +
      + + 5 +
      +
      + 0.00% +
      +
      +
      +
      + 1 commits
      +
      + 0.08% +
      +
      +
      +
      + - 2 +
      +
      + 0.00% +
      +
    • - Abdulgafar4 + Abdulgafar4

      Abdulgafar4

      -
      -
      - + 3 -
      -
      - 0.00% -
      -
      -
      -
      - 1 commits -
      -
      - 0.17% -
      -
      -
      -
      - - 0 -
      -
      - 0.00% -
      +
      +
      + + 3 +
      +
      + 0.00% +
      +
      +
      +
      + 1 commits
      +
      + 0.17% +
      +
      +
      +
      + - 0 +
      +
      + 0.00% +
      +
      -
    - \ No newline at end of file + +
+ + diff --git a/scripts/strip-api-for-static-export.js b/scripts/strip-api-for-static-export.js new file mode 100644 index 0000000..f97c1c0 --- /dev/null +++ b/scripts/strip-api-for-static-export.js @@ -0,0 +1,43 @@ +// scripts/strip-api-for-static-export.js +// +// GitHub Pages serves this site as a fully static export (output: "export" +// in next.config.js) — there's no live Node server to run API route +// handlers. Next.js's static export will hard-fail the build if any +// dynamic (GET-based) route handler exists under app/api, since it can't +// produce static output for them. +// +// The actual API routes (OAuth, blog publishing) are deployed separately +// to Vercel, which DOES run a real server and needs these files present. +// See next.config.js for the corresponding VERCEL env var check. +// +// This script temporarily removes app/api before the static export build +// runs. It's only invoked by `npm run build:static` (used in CI for the +// GitHub Pages deploy) — the regular `npm run build` (used by Vercel) +// never calls this, so app/api stays intact there. + +import { rm, cp, mkdir } from "fs/promises"; +import { existsSync } from "fs"; +import path from "path"; + +const apiDir = path.resolve("app/api"); +const backupDir = path.resolve(".api-backup-during-static-build"); + +async function main() { + if (!existsSync(apiDir)) { + console.log("No app/api directory found — nothing to strip."); + return; + } + + console.log("Temporarily removing app/api for the static export build..."); + await mkdir(backupDir, { recursive: true }); + await cp(apiDir, backupDir, { recursive: true }); + await rm(apiDir, { recursive: true, force: true }); + console.log( + "Done. (Backed up to .api-backup-during-static-build in case a restore script is added later.)" + ); +} + +main().catch((err) => { + console.error("Failed to strip app/api:", err); + process.exit(1); +}); diff --git a/tsconfig.json b/tsconfig.json index 012ebf4..1045bf8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "allowImportingTsExtensions": true, "plugins": [