From ba62de355fb2d987d76eff949a85bccdb6e36b71 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Fri, 18 Apr 2025 18:48:08 -0400 Subject: [PATCH] add github activity graph to /projects --- app/contact/action.ts | 12 +- app/notes/[slug]/counter.tsx | 2 +- app/notes/[slug]/opengraph-image.tsx | 6 +- app/projects/calendar.module.css | 33 ++ app/projects/calendar.tsx | 59 +++ app/projects/page.module.css | 5 + app/projects/page.tsx | 221 ++++++++--- .../HorizontalRule/HorizontalRule.module.css | 3 +- package.json | 7 +- pnpm-lock.yaml | 352 +++++++++++++----- 10 files changed, 540 insertions(+), 160 deletions(-) create mode 100644 app/projects/calendar.module.css create mode 100644 app/projects/calendar.tsx diff --git a/app/contact/action.ts b/app/contact/action.ts index 06a0eef7..14085bed 100644 --- a/app/contact/action.ts +++ b/app/contact/action.ts @@ -30,8 +30,6 @@ const ContactSchema = v.object({ v.nonEmpty("Just do the stinkin CAPTCHA, human! 🤖"), // very rudimentary length check based on Cloudflare's docs // https://developers.cloudflare.com/turnstile/troubleshooting/testing/ - v.minLength("XXXX.DUMMY.TOKEN.XXXX".length), - // "A Turnstile token can have up to 2048 characters." // https://developers.cloudflare.com/turnstile/get-started/server-side-validation/ v.maxLength(2048), v.readonly() @@ -48,7 +46,7 @@ export type ContactState = { export const send = async (state: ContactState, payload: FormData): Promise => { // TODO: remove after debugging why automated spam entries are causing 500 errors - console.debug("[contact form] received payload:", payload); + console.debug("[/contact] received payload:", payload); try { const data = v.safeParse(ContactSchema, Object.fromEntries(payload)); @@ -80,7 +78,7 @@ export const send = async (state: ContactState, payload: FormData): Promise { ); } catch (error) { - console.error("[hit counter] fatal error:", error); + console.error("[/notes/[slug]/counter] fatal error:", error); return ?; } diff --git a/app/notes/[slug]/opengraph-image.tsx b/app/notes/[slug]/opengraph-image.tsx index c4f6182d..491bf352 100644 --- a/app/notes/[slug]/opengraph-image.tsx +++ b/app/notes/[slug]/opengraph-image.tsx @@ -34,7 +34,7 @@ const getLocalImage = async (src: string): Promise => { try { if (!fs.existsSync(imagePath)) { - console.error(`[og-image] couldn't find an image file located at "${imagePath}"`); + console.error(`[/notes/[slug]/opengraph-image] couldn't find an image file located at "${imagePath}"`); // return a 1x1 transparent gif if the image doesn't exist instead of crashing return NO_IMAGE; @@ -43,7 +43,7 @@ const getLocalImage = async (src: string): Promise => { // return the raw image data as a buffer return Uint8Array.from(await fs.promises.readFile(imagePath)).buffer; } catch (error) { - console.error(`[og-image] found "${imagePath}" but couldn't read it:`, error); + console.error(`[/notes/[slug]/opengraph-image] found "${imagePath}" but couldn't read it:`, error); // fail silently and return a 1x1 transparent gif instead of crashing return NO_IMAGE; @@ -256,7 +256,7 @@ const OpenGraphImage = async ({ params }: { params: Promise<{ slug: string }> }) } ); } catch (error) { - console.error("[og-image] error generating image:", error); + console.error("[/notes/[slug]/opengraph-image] error generating open graph image:", error); notFound(); } }; diff --git a/app/projects/calendar.module.css b/app/projects/calendar.module.css new file mode 100644 index 00000000..877b9575 --- /dev/null +++ b/app/projects/calendar.module.css @@ -0,0 +1,33 @@ +.calendar { + --activity-0: #ebedf0; + --activity-1: #9be9a8; + --activity-2: #40c463; + --activity-3: #30a14e; + --activity-4: #216e39; +} + +[data-theme="dark"] .calendar { + --activity-0: #252525; + --activity-1: #033a16; + --activity-2: #196c2e; + --activity-3: #2ea043; + --activity-4: #56d364; +} + +.calendar :global(.react-activity-calendar) { + margin: 1em auto; +} + +.calendar :global(.react-activity-calendar__count), +.calendar :global(.react-activity-calendar__legend-month) { + color: var(--colors-medium); +} + +.calendar :global(.react-activity-calendar__legend-colors) { + color: var(--colors-medium-light); +} + +.tooltip { + background-color: var(--colors-background-header); + color: var(--colors-text); +} diff --git a/app/projects/calendar.tsx b/app/projects/calendar.tsx new file mode 100644 index 00000000..c1f4ba3b --- /dev/null +++ b/app/projects/calendar.tsx @@ -0,0 +1,59 @@ +"use client"; + +import { cloneElement } from "react"; +import { ActivityCalendar } from "react-activity-calendar"; +import { Tooltip } from "react-tooltip"; +import clsx from "clsx"; +import { format } from "date-fns"; +import type { ComponentPropsWithoutRef } from "react"; +import type { Activity } from "react-activity-calendar"; + +import styles from "./calendar.module.css"; +import "react-tooltip/dist/react-tooltip.css"; + +export type CalendarProps = ComponentPropsWithoutRef<"div"> & { + data: Activity[]; +}; + +const Calendar = ({ data, className, ...rest }: CalendarProps) => { + // heavily inspired by https://github.com/grubersjoe/react-github-calendar + return ( + + ); +}; + +export default Calendar; diff --git a/app/projects/page.module.css b/app/projects/page.module.css index 9d0b40c8..7861bc81 100644 --- a/app/projects/page.module.css +++ b/app/projects/page.module.css @@ -1,3 +1,8 @@ +.heading { + font-weight: 400; + font-size: 1.4em; +} + .grid { display: flex; flex-flow: row wrap; diff --git a/app/projects/page.tsx b/app/projects/page.tsx index a8a42f34..ec2d34f1 100644 --- a/app/projects/page.tsx +++ b/app/projects/page.tsx @@ -1,13 +1,16 @@ import { env } from "../../lib/env"; +import { Suspense } from "react"; import { notFound } from "next/navigation"; import { graphql } from "@octokit/graphql"; +import * as cheerio from "cheerio"; import { GitForkIcon, StarIcon } from "lucide-react"; +import Calendar from "./calendar"; import PageTitle from "../../components/PageTitle"; import Link from "../../components/Link"; import RelativeTime from "../../components/RelativeTime"; import { addMetadata } from "../../lib/helpers/metadata"; import * as config from "../../lib/config"; -import type { User } from "@octokit/graphql-schema"; +import type { Repository, User } from "@octokit/graphql-schema"; import styles from "./page.module.css"; @@ -19,81 +22,185 @@ export const metadata = addMetadata({ }, }); -const getRepos = async () => { - // don't fail the entire site build if the required API key for this page is missing - if (!env.GITHUB_TOKEN) { - console.warn(`ERROR: I can't fetch any GitHub projects without "GITHUB_TOKEN" set! Disabling projects page.`); +const getContributions = async (): Promise< + Array<{ + date: string; + count: number; + level: number; + }> +> => { + // thanks @grubersjoe! :) https://github.com/grubersjoe/github-contributions-api/blob/main/src/scrape.ts + try { + const response = await fetch(`https://github.com/users/${config.authorSocial.github}/contributions`, { + headers: { + referer: `https://github.com/${config.authorSocial.github}`, + "x-requested-with": "XMLHttpRequest", + }, + cache: "force-cache", + next: { + revalidate: 43200, // 12 hours + tags: ["github-contributions"], + }, + }); - // just return a 404 since this page would be blank anyways - notFound(); + const $ = cheerio.load(await response.text()); + + const days = $(".js-calendar-graph-table .ContributionCalendar-day") + .get() + .sort((a, b) => { + const dateA = a.attribs["data-date"] ?? ""; + const dateB = b.attribs["data-date"] ?? ""; + + return dateA.localeCompare(dateB, "en"); + }); + + const dayTooltips = $(".js-calendar-graph tool-tip") + .toArray() + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .reduce>((map, elem) => { + map[elem.attribs["for"]] = elem; + return map; + }, {}); + + return days.map((day) => { + const attr = { + id: day.attribs["id"], + date: day.attribs["data-date"], + level: day.attribs["data-level"], + }; + + let count = 0; + if (dayTooltips[attr.id]) { + const text = dayTooltips[attr.id].firstChild; + if (text) { + const countMatch = text.data.trim().match(/^\d+/); + if (countMatch) { + count = parseInt(countMatch[0]); + } + } + } + + const level = parseInt(attr.level); + + return { + date: attr.date, + count, + level, + }; + }); + } catch (error) { + console.error("[/projects] Failed to fetch contributions:", error); + return []; } +}; - // https://docs.github.com/en/graphql/reference/objects#repository - const { user } = await graphql<{ user: User }>( - ` - query ($username: String!, $sort: RepositoryOrderField!, $limit: Int) { - user(login: $username) { - repositories( - first: $limit - isLocked: false - isFork: false - ownerAffiliations: OWNER - privacy: PUBLIC - orderBy: { field: $sort, direction: DESC } - ) { - edges { - node { - name - url - description - pushedAt - stargazerCount - forkCount - primaryLanguage { +const getRepos = async (): Promise => { + try { + // https://docs.github.com/en/graphql/reference/objects#repository + const { user } = await graphql<{ user: User }>( + ` + query ($username: String!, $sort: RepositoryOrderField!, $limit: Int) { + user(login: $username) { + repositories( + first: $limit + isLocked: false + isFork: false + ownerAffiliations: OWNER + privacy: PUBLIC + orderBy: { field: $sort, direction: DESC } + ) { + edges { + node { name - color + url + description + pushedAt + stargazerCount + forkCount + primaryLanguage { + name + color + } } } } } } - } - `, - { - username: config.authorSocial.github, - sort: "STARGAZERS", - limit: 12, - headers: { - accept: "application/vnd.github.v3+json", - authorization: `token ${env.GITHUB_TOKEN}`, - }, - request: { - // override fetch() to use next's extension to cache the response - // https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options - fetch: (url: string | URL | Request, options?: RequestInit) => { - return fetch(url, { - ...options, - cache: "force-cache", - next: { - revalidate: 600, // 10 minutes - tags: ["github-api"], - }, - }); + `, + { + username: config.authorSocial.github, + sort: "STARGAZERS", + limit: 12, + headers: { + accept: "application/vnd.github.v3+json", + authorization: `token ${env.GITHUB_TOKEN}`, }, - }, - } - ); + request: { + // override fetch() to use next's extension to cache the response + // https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options + fetch: (url: string | URL | Request, options?: RequestInit) => { + return fetch(url, { + ...options, + cache: "force-cache", + next: { + revalidate: 1800, // 30 minutes + tags: ["github-repos"], + }, + }); + }, + }, + } + ); - return user.repositories.edges?.map((edge) => edge!.node); + return user.repositories.edges?.map((edge) => edge!.node as Repository); + } catch (error) { + console.error("[/projects] Failed to fetch repositories:", error); + return []; + } }; const Page = async () => { - const repos = await getRepos(); + // don't fail the entire site build if the required config for this page is missing, just return a 404 since this page + // would be blank anyways + if (!env.GITHUB_TOKEN) { + console.warn("[/projects] I can't fetch anything from GitHub without 'GITHUB_TOKEN' set!"); + notFound(); + } + + if (!config.authorSocial?.github) { + console.warn( + "[/projects] I can't fetch anything from GitHub without 'authorSocial.github' set in lib/config/index.ts." + ); + notFound(); + } + + // fetch the repos and contributions in parallel + const [contributions, repos] = await Promise.all([getContributions(), getRepos()]); return ( <> Projects +

+ + Contribution activity + +

+ + + + + +

+ + Popular repositories + +

+
{repos?.map((repo) => (
diff --git a/components/HorizontalRule/HorizontalRule.module.css b/components/HorizontalRule/HorizontalRule.module.css index 131656a8..3263ae61 100644 --- a/components/HorizontalRule/HorizontalRule.module.css +++ b/components/HorizontalRule/HorizontalRule.module.css @@ -1,6 +1,7 @@ .hr { margin: 1.5em auto; - height: 0.175em; + max-width: calc(var(--max-width) - 1.5em); + height: 1px; border: 0; background-color: var(--colors-light); } diff --git a/package.json b/package.json index 8f1dca66..5a5adfa1 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@t3-oss/env-nextjs": "^0.12.0", "@upstash/redis": "^1.34.8", "@vercel/analytics": "^1.5.0", + "cheerio": "^1.0.0", "clsx": "^2.1.1", "copy-to-clipboard": "^3.3.3", "date-fns": "^4.1.0", @@ -43,6 +44,7 @@ "polished": "^4.3.1", "prop-types": "^15.8.1", "react": "19.1.0", + "react-activity-calendar": "^2.7.10", "react-countup": "^6.5.3", "react-dom": "19.1.0", "react-innertext": "^1.1.5", @@ -51,6 +53,7 @@ "react-schemaorg": "^2.0.0", "react-textarea-autosize": "^8.5.9", "react-timeago": "^8.2.0", + "react-tooltip": "^5.28.1", "react-turnstile": "^1.1.4", "react-tweet": "^3.2.2", "rehype-mdx-import-media": "^1.2.0", @@ -71,7 +74,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "^9.24.0", + "@eslint/js": "^9.25.0", "@jakejarvis/eslint-config": "^4.0.7", "@types/mdx": "^2.0.13", "@types/node": "^22.14.1", @@ -81,7 +84,7 @@ "@types/react-is": "^19.0.0", "babel-plugin-react-compiler": "19.0.0-beta-ebf51a3-20250411", "cross-env": "^7.0.3", - "eslint": "^9.24.0", + "eslint": "^9.25.0", "eslint-config-next": "15.3.1-canary.13", "eslint-config-prettier": "^10.1.2", "eslint-plugin-css-modules": "^2.12.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba191d89..0aa7c6aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: '@vercel/analytics': specifier: ^1.5.0 version: 1.5.0(next@15.3.1-canary.13(@babel/core@7.26.10)(babel-plugin-react-compiler@19.0.0-beta-ebf51a3-20250411)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + cheerio: + specifier: ^1.0.0 + version: 1.0.0 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -83,6 +86,9 @@ importers: react: specifier: 19.1.0 version: 19.1.0 + react-activity-calendar: + specifier: ^2.7.10 + version: 2.7.10(react@19.1.0) react-countup: specifier: ^6.5.3 version: 6.5.3(react@19.1.0) @@ -107,6 +113,9 @@ importers: react-timeago: specifier: ^8.2.0 version: 8.2.0(react@19.1.0) + react-tooltip: + specifier: ^5.28.1 + version: 5.28.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react-turnstile: specifier: ^1.1.4 version: 1.1.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -163,11 +172,11 @@ importers: specifier: ^3.3.1 version: 3.3.1 '@eslint/js': - specifier: ^9.24.0 - version: 9.24.0 + specifier: ^9.25.0 + version: 9.25.0 '@jakejarvis/eslint-config': specifier: ^4.0.7 - version: 4.0.7(eslint@9.24.0) + version: 4.0.7(eslint@9.25.0) '@types/mdx': specifier: ^2.0.13 version: 2.0.13 @@ -193,38 +202,38 @@ importers: specifier: ^7.0.3 version: 7.0.3 eslint: - specifier: ^9.24.0 - version: 9.24.0 + specifier: ^9.25.0 + version: 9.25.0 eslint-config-next: specifier: 15.3.1-canary.13 - version: 15.3.1-canary.13(eslint@9.24.0)(typescript@5.8.3) + version: 15.3.1-canary.13(eslint@9.25.0)(typescript@5.8.3) eslint-config-prettier: specifier: ^10.1.2 - version: 10.1.2(eslint@9.24.0) + version: 10.1.2(eslint@9.25.0) eslint-plugin-css-modules: specifier: ^2.12.0 - version: 2.12.0(eslint@9.24.0) + version: 2.12.0(eslint@9.25.0) eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0) + version: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.24.0) + version: 6.10.2(eslint@9.25.0) eslint-plugin-mdx: specifier: ^3.4.0 - version: 3.4.0(eslint@9.24.0) + version: 3.4.0(eslint@9.25.0) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.2.6(eslint-config-prettier@10.1.2(eslint@9.24.0))(eslint@9.24.0)(prettier@3.5.3) + version: 5.2.6(eslint-config-prettier@10.1.2(eslint@9.25.0))(eslint@9.25.0)(prettier@3.5.3) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.24.0) + version: 7.37.5(eslint@9.25.0) eslint-plugin-react-compiler: specifier: 19.0.0-beta-ebf51a3-20250411 - version: 19.0.0-beta-ebf51a3-20250411(eslint@9.24.0) + version: 19.0.0-beta-ebf51a3-20250411(eslint@9.25.0) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.24.0) + version: 5.2.0(eslint@9.25.0) husky: specifier: ^9.1.7 version: 9.1.7 @@ -435,10 +444,6 @@ packages: resolution: {integrity: sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.12.0': - resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.13.0': resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -447,8 +452,8 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.24.0': - resolution: {integrity: sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==} + '@eslint/js@9.25.0': + resolution: {integrity: sha512-iWhsUS8Wgxz9AXNfvfOPFSW4VfMXdVhp1hjkZVhXCrpgh/aLcc45rX6MPu+tIVUWDw0HfNwth7O28M1xDxNf9w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': @@ -459,6 +464,15 @@ packages: resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + '@giscus/react@3.1.0': resolution: {integrity: sha512-0TCO2TvL43+oOdyVVGHDItwxD1UMKP2ZYpT6gXmhFOqfAJtZxTzJ9hkn34iAF/b6YzyJ4Um89QIt9z/ajmAEeg==} peerDependencies: @@ -1228,6 +1242,9 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1298,10 +1315,20 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0: + resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} + engines: {node: '>=18.17'} + ci-info@4.2.0: resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} engines: {node: '>=8'} + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -1392,10 +1419,17 @@ packages: resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} engines: {node: '>=12 || >=16'} + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-tree@3.1.0: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -1521,6 +1555,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding-sniffer@0.2.0: + resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -1723,8 +1760,8 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.24.0: - resolution: {integrity: sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==} + eslint@9.25.0: + resolution: {integrity: sha512-MsBdObhM4cEwkzCiraDv7A6txFXEqtNXOb877TsSp2FCkBNl8JfVQrmiuDqC1IkejT6JLPzYBXx/xAiYhyzgGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2090,6 +2127,9 @@ packages: htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + htmlparser2@9.1.0: + resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} + human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -2099,6 +2139,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2740,6 +2784,9 @@ packages: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2833,6 +2880,12 @@ packages: parse-srcset@1.0.2: resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} @@ -2958,6 +3011,11 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-activity-calendar@2.7.10: + resolution: {integrity: sha512-O6ev2JxbsbmF7hPpRCkiXxQ+vGwXS5iUVwOCqtvlJnGhpyJ3ZJap7/qfIZA0WZcDj4gpQh2Dcvkmwh3yBXRrPQ==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-countup@6.5.3: resolution: {integrity: sha512-udnqVQitxC7QWADSPDOxVWULkLvKUWrDapn5i53HE4DPRVgs+Y5rr4bo25qEl8jSh+0l2cToJgGMx+clxPM3+w==} peerDependencies: @@ -3008,6 +3066,12 @@ packages: peerDependencies: react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-tooltip@5.28.1: + resolution: {integrity: sha512-ZA4oHwoIIK09TS7PvSLFcRlje1wGZaxw6xHvfrzn6T82UcMEfEmHVCad16Gnr4NDNDh93HyN037VK4HDi5odfQ==} + peerDependencies: + react: '>=16.14.0' + react-dom: '>=16.14.0' + react-turnstile@1.1.4: resolution: {integrity: sha512-oluyRWADdsufCt5eMqacW4gfw8/csr6Tk+fmuaMx0PWMKP1SX1iCviLvD2D5w92eAzIYDHi/krUWGHhlfzxTpQ==} peerDependencies: @@ -3190,6 +3254,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} @@ -3541,6 +3608,10 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@6.21.2: + resolution: {integrity: sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g==} + engines: {node: '>=18.17'} + unified-engine@11.2.2: resolution: {integrity: sha512-15g/gWE7qQl9tQ3nAEbMd5h9HV1EACtFs6N9xaRBZICoCwnNGbal1kOs++ICf4aiTdItZxU2s/kYWhW7htlqJg==} @@ -3676,6 +3747,14 @@ packages: engines: {node: '>= 10.13.0'} hasBin: true + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -3970,9 +4049,9 @@ snapshots: '@emotion/hash@0.9.2': {} - '@eslint-community/eslint-utils@4.6.1(eslint@9.24.0)': + '@eslint-community/eslint-utils@4.6.1(eslint@9.25.0)': dependencies: - eslint: 9.24.0 + eslint: 9.25.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -3987,10 +4066,6 @@ snapshots: '@eslint/config-helpers@0.2.1': {} - '@eslint/core@0.12.0': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/core@0.13.0': dependencies: '@types/json-schema': 7.0.15 @@ -4009,7 +4084,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.24.0': {} + '@eslint/js@9.25.0': {} '@eslint/object-schema@2.1.6': {} @@ -4018,6 +4093,17 @@ snapshots: '@eslint/core': 0.13.0 levn: 0.4.1 + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/utils@0.2.9': {} + '@giscus/react@3.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: giscus: 1.6.0 @@ -4124,9 +4210,9 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@jakejarvis/eslint-config@4.0.7(eslint@9.24.0)': + '@jakejarvis/eslint-config@4.0.7(eslint@9.25.0)': dependencies: - eslint: 9.24.0 + eslint: 9.25.0 '@jridgewell/gen-mapping@0.3.8': dependencies: @@ -4498,15 +4584,15 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0)(typescript@5.8.3)': + '@typescript-eslint/eslint-plugin@8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint@9.25.0)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.30.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.30.1(eslint@9.25.0)(typescript@5.8.3) '@typescript-eslint/scope-manager': 8.30.1 - '@typescript-eslint/type-utils': 8.30.1(eslint@9.24.0)(typescript@5.8.3) - '@typescript-eslint/utils': 8.30.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.30.1(eslint@9.25.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.30.1(eslint@9.25.0)(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.30.1 - eslint: 9.24.0 + eslint: 9.25.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -4515,14 +4601,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3)': + '@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3)': dependencies: '@typescript-eslint/scope-manager': 8.30.1 '@typescript-eslint/types': 8.30.1 '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.30.1 debug: 4.4.0 - eslint: 9.24.0 + eslint: 9.25.0 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4532,12 +4618,12 @@ snapshots: '@typescript-eslint/types': 8.30.1 '@typescript-eslint/visitor-keys': 8.30.1 - '@typescript-eslint/type-utils@8.30.1(eslint@9.24.0)(typescript@5.8.3)': + '@typescript-eslint/type-utils@8.30.1(eslint@9.25.0)(typescript@5.8.3)': dependencies: '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.3) - '@typescript-eslint/utils': 8.30.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.30.1(eslint@9.25.0)(typescript@5.8.3) debug: 4.4.0 - eslint: 9.24.0 + eslint: 9.25.0 ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: @@ -4559,13 +4645,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.30.1(eslint@9.24.0)(typescript@5.8.3)': + '@typescript-eslint/utils@8.30.1(eslint@9.25.0)(typescript@5.8.3)': dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@9.24.0) + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.0) '@typescript-eslint/scope-manager': 8.30.1 '@typescript-eslint/types': 8.30.1 '@typescript-eslint/typescript-estree': 8.30.1(typescript@5.8.3) - eslint: 9.24.0 + eslint: 9.25.0 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4777,6 +4863,8 @@ snapshots: base64-js@1.5.1: {} + boolbase@1.0.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -4851,8 +4939,33 @@ snapshots: character-reference-invalid@2.0.1: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.1.0 + css-what: 6.1.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.0.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.0 + htmlparser2: 9.1.0 + parse5: 7.2.1 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 6.21.2 + whatwg-mimetype: 4.0.0 + ci-info@4.2.0: {} + classnames@2.5.1: {} + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -4936,11 +5049,21 @@ snapshots: css-functions-list@3.2.3: {} + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-tree@3.1.0: dependencies: mdn-data: 2.12.2 source-map-js: 1.2.1 + css-what@6.1.0: {} + cssesc@3.0.0: {} csstype@3.1.3: {} @@ -5054,6 +5177,11 @@ snapshots: emoji-regex@9.2.2: {} + encoding-sniffer@0.2.0: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + entities@4.5.0: {} env-paths@2.2.1: {} @@ -5184,19 +5312,19 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@15.3.1-canary.13(eslint@9.24.0)(typescript@5.8.3): + eslint-config-next@15.3.1-canary.13(eslint@9.25.0)(typescript@5.8.3): dependencies: '@next/eslint-plugin-next': 15.3.1-canary.13 '@rushstack/eslint-patch': 1.11.0 - '@typescript-eslint/eslint-plugin': 8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint@9.24.0)(typescript@5.8.3) - '@typescript-eslint/parser': 8.30.1(eslint@9.24.0)(typescript@5.8.3) - eslint: 9.24.0 + '@typescript-eslint/eslint-plugin': 8.30.1(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint@9.25.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.30.1(eslint@9.25.0)(typescript@5.8.3) + eslint: 9.25.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@9.24.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.24.0) - eslint-plugin-react: 7.37.5(eslint@9.24.0) - eslint-plugin-react-hooks: 5.2.0(eslint@9.24.0) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@9.25.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.25.0) + eslint-plugin-react: 7.37.5(eslint@9.25.0) + eslint-plugin-react-hooks: 5.2.0(eslint@9.25.0) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -5204,9 +5332,9 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-prettier@10.1.2(eslint@9.24.0): + eslint-config-prettier@10.1.2(eslint@9.25.0): dependencies: - eslint: 9.24.0 + eslint: 9.25.0 eslint-import-resolver-node@0.3.9: dependencies: @@ -5216,26 +5344,26 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@9.24.0): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@9.25.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 - eslint: 9.24.0 + eslint: 9.25.0 get-tsconfig: 4.10.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.12 unrs-resolver: 1.5.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0) transitivePeerDependencies: - supports-color - eslint-mdx@3.4.0(eslint@9.24.0): + eslint-mdx@3.4.0(eslint@9.25.0): dependencies: acorn: 8.14.1 acorn-jsx: 5.3.2(acorn@8.14.1) - eslint: 9.24.0 + eslint: 9.25.0 espree: 10.3.0 estree-util-visit: 2.0.0 remark-mdx: 3.1.0 @@ -5252,24 +5380,24 @@ snapshots: - bluebird - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.30.1(eslint@9.24.0)(typescript@5.8.3) - eslint: 9.24.0 + '@typescript-eslint/parser': 8.30.1(eslint@9.25.0)(typescript@5.8.3) + eslint: 9.25.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@9.24.0) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@9.25.0) transitivePeerDependencies: - supports-color - eslint-plugin-css-modules@2.12.0(eslint@9.24.0): + eslint-plugin-css-modules@2.12.0(eslint@9.25.0): dependencies: - eslint: 9.24.0 + eslint: 9.25.0 gonzales-pe: 4.3.0 lodash: 4.17.21 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -5278,9 +5406,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.24.0 + eslint: 9.25.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.24.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.24.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -5292,13 +5420,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.30.1(eslint@9.24.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.30.1(eslint@9.25.0)(typescript@5.8.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.24.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.25.0): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -5308,7 +5436,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.24.0 + eslint: 9.25.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -5317,10 +5445,10 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-mdx@3.4.0(eslint@9.24.0): + eslint-plugin-mdx@3.4.0(eslint@9.25.0): dependencies: - eslint: 9.24.0 - eslint-mdx: 3.4.0(eslint@9.24.0) + eslint: 9.25.0 + eslint-mdx: 3.4.0(eslint@9.25.0) mdast-util-from-markdown: 2.0.2 mdast-util-mdx: 3.0.0 micromark-extension-mdxjs: 3.0.0 @@ -5336,32 +5464,32 @@ snapshots: - remark-lint-file-extension - supports-color - eslint-plugin-prettier@5.2.6(eslint-config-prettier@10.1.2(eslint@9.24.0))(eslint@9.24.0)(prettier@3.5.3): + eslint-plugin-prettier@5.2.6(eslint-config-prettier@10.1.2(eslint@9.25.0))(eslint@9.25.0)(prettier@3.5.3): dependencies: - eslint: 9.24.0 + eslint: 9.25.0 prettier: 3.5.3 prettier-linter-helpers: 1.0.0 synckit: 0.11.4 optionalDependencies: - eslint-config-prettier: 10.1.2(eslint@9.24.0) + eslint-config-prettier: 10.1.2(eslint@9.25.0) - eslint-plugin-react-compiler@19.0.0-beta-ebf51a3-20250411(eslint@9.24.0): + eslint-plugin-react-compiler@19.0.0-beta-ebf51a3-20250411(eslint@9.25.0): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.27.0 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.10) - eslint: 9.24.0 + eslint: 9.25.0 hermes-parser: 0.25.1 zod: 3.24.3 zod-validation-error: 3.4.0(zod@3.24.3) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.24.0): + eslint-plugin-react-hooks@5.2.0(eslint@9.25.0): dependencies: - eslint: 9.24.0 + eslint: 9.25.0 - eslint-plugin-react@7.37.5(eslint@9.24.0): + eslint-plugin-react@7.37.5(eslint@9.25.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -5369,7 +5497,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.24.0 + eslint: 9.25.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -5392,15 +5520,15 @@ snapshots: eslint-visitor-keys@4.2.0: {} - eslint@9.24.0: + eslint@9.25.0: dependencies: - '@eslint-community/eslint-utils': 4.6.1(eslint@9.24.0) + '@eslint-community/eslint-utils': 4.6.1(eslint@9.25.0) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.20.0 '@eslint/config-helpers': 0.2.1 - '@eslint/core': 0.12.0 + '@eslint/core': 0.13.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.24.0 + '@eslint/js': 9.25.0 '@eslint/plugin-kit': 0.2.8 '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 @@ -5899,10 +6027,21 @@ snapshots: domutils: 3.2.2 entities: 4.5.0 + htmlparser2@9.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + human-signals@5.0.0: {} husky@9.1.7: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -6806,6 +6945,10 @@ snapshots: dependencies: path-key: 4.0.0 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -6934,6 +7077,15 @@ snapshots: parse-srcset@1.0.2: {} + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.2.1 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.2.1 + parse5@7.2.1: dependencies: entities: 4.5.0 @@ -7031,6 +7183,11 @@ snapshots: queue-microtask@1.2.3: {} + react-activity-calendar@2.7.10(react@19.1.0): + dependencies: + date-fns: 4.1.0 + react: 19.1.0 + react-countup@6.5.3(react@19.1.0): dependencies: countup.js: 2.8.0 @@ -7078,6 +7235,13 @@ snapshots: dependencies: react: 19.1.0 + react-tooltip@5.28.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@floating-ui/dom': 1.6.13 + classnames: 2.5.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-turnstile@1.1.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 @@ -7381,6 +7545,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safer-buffer@2.1.2: {} + sax@1.4.1: {} scheduler@0.26.0: {} @@ -7855,6 +8021,8 @@ snapshots: undici-types@6.21.0: {} + undici@6.21.2: {} + unified-engine@11.2.2: dependencies: '@types/concat-stream': 2.0.3 @@ -8075,6 +8243,12 @@ snapshots: - bufferutil - utf-8-validate + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0