diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 35b00da..503778a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,9 +12,18 @@ updates: - 'minor' - 'patch' ignore: - # Keep eslint pinned at v9 — v10 breaks eslint-config-next + # Ignore eslint updates entirely - dependency-name: 'eslint' - versions: ['>= 10'] + update-types: + - 'version-update:semver-major' + - 'version-update:semver-minor' + - 'version-update:semver-patch' + # Ignore minimatch updates entirely + - dependency-name: 'minimatch' + update-types: + - 'version-update:semver-major' + - 'version-update:semver-minor' + - 'version-update:semver-patch' open-pull-requests-limit: 10 # GitHub Actions version updates diff --git a/README.md b/README.md index 9080ff1..072cc81 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Where code meets conscience.** A brutalist × cyberpunk portfolio built with Next.js 16. -[![Version](https://img.shields.io/badge/version-1.1.1-cyan?logo=github)](package.json) +[![Version](https://img.shields.io/badge/version-1.1.2-cyan?logo=github)](package.json) [![Security: SLSA Level 3](https://img.shields.io/badge/SLSA-Level%203-brightgreen)](https://github.com/devakesu/devakesu-web/attestations) [![Security Scan: Trivy](https://img.shields.io/badge/Security-Trivy%20Scanned-blue)](.github/workflows/deploy.yml) [![Attestations](https://img.shields.io/badge/Attestations-Enabled-success)](https://github.com/devakesu/devakesu-web/attestations) @@ -413,5 +413,5 @@ _Love is the only way to rescue humanity from all evils._ --- -**Last Updated**: February 25, 2026 -**Version**: 1.1.1 +**Last Updated**: March 02, 2026 +**Version**: 1.1.2 diff --git a/SECURITY.md b/SECURITY.md index 1bd6dc2..5740dcd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -148,5 +148,5 @@ We appreciate security researchers who responsibly disclose vulnerabilities. --- -**Last Updated**: February 25, 2026 -**Version**: 1.1.1 +**Last Updated**: March 02, 2026 +**Version**: 1.1.2 diff --git a/app/globals.css b/app/globals.css index 74eed13..3343988 100644 --- a/app/globals.css +++ b/app/globals.css @@ -5,7 +5,7 @@ html { scroll-padding-top: 0px; /* Improve mouse wheel scrolling smoothness */ overscroll-behavior-y: contain; - scroll-snap-type: y proximity; + scroll-snap-type: none; /* Mobile optimization */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; diff --git a/app/page.tsx b/app/page.tsx index 8fb38cb..b6ee957 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -28,8 +28,6 @@ import { import { FaXTwitter } from "react-icons/fa6"; const SCROLL_LOCK_DURATION = 800; -const TOUCH_THRESHOLD_PX = 40; -const MIN_WHEEL_DELTA = 2; // Throttle utility for performance optimization const throttle = void>( @@ -45,21 +43,6 @@ const throttle = void>( } }; }; -// NOTE: Inline style attribute selectors (e.g., [style*="overflow-y: auto"]) are -// whitespace- and order-sensitive and may miss valid inline style syntax variations -// (e.g., "overflow-y:auto" without space, or multiple spaces). Scrollable elements -// should preferably use data attributes or classes for reliable detection. The -// fallback logic in scrollToSection only runs when no elements match SCROLLABLE_SELECTORS. -const SCROLLABLE_SELECTORS = [ - "[data-scrollable]", - ".overflow-y-auto", - ".overflow-y-scroll", - '[style*="overflow-y: auto"]', - '[style*="overflow-y: scroll"]', - '[style*="overflow: auto"]', - '[style*="overflow: scroll"]', -].join(", "); - // Helper function to scroll element into view on mobile after a delay const scrollIntoViewOnMobile = (elementId: string, delay = 300): void => { if (window.matchMedia("(max-width: 768px)").matches) { @@ -332,11 +315,15 @@ export default function Home() { const activeSectionIndexRef = useRef(0); const isAnimatingRef = useRef(false); const unlockTimeoutRef = useRef | null>(null); - const touchStartYRef = useRef(null); - const touchStartXRef = useRef(null); - const touchIsVerticalRef = useRef(null); - const touchStartedWithinScrollableRef = useRef(false); const lastScrollTimeRef = useRef(0); + const wheelAccumulatorRef = useRef(0); + const wheelLockTimeoutRef = useRef | null>( + null, + ); + const scrollEndTimeoutRef = useRef | null>( + null, + ); + const isInertiaScrollingRef = useRef(false); const scrollTargetRef = useRef(null); // Calculate age based on birth date (April 19) @@ -506,8 +493,9 @@ export default function Home() { // Force section-by-section scroll with smooth snapping across input methods useEffect(() => { if ( - !isSectionScrollEnabled || isCoarsePointer || - typeof window === "undefined" + !isSectionScrollEnabled || + typeof window === "undefined" || + isCoarsePointer ) { return undefined; } @@ -589,6 +577,32 @@ export default function Home() { activeSectionIndexRef.current = closestIndex; }; + // Check if the current section is taller than the viewport and the user + // hasn't reached its edge in the given direction. If true, allow native + // (free) scrolling within the section instead of jumping to the next one. + const canScrollWithinSection = (direction: number): boolean => { + const currentSection = sections[activeSectionIndexRef.current]; + if (!currentSection) return false; + + const rect = currentSection.getBoundingClientRect(); + const viewportHeight = window.innerHeight; + const tolerance = 5; // px — accounts for sub-pixel rendering + + // Section fits within the viewport — no intra-section scroll needed + if (rect.height <= viewportHeight + tolerance) { + return false; + } + + // Section is taller than viewport — check boundary + if (direction > 0) { + // Scrolling down: allow free scroll if section bottom is still below viewport + return rect.bottom > viewportHeight + tolerance; + } else { + // Scrolling up: allow free scroll if section top is still above viewport + return rect.top < -tolerance; + } + }; + const scrollToSection = (direction: number) => { // Prevent any scroll if we're already animating or scrolled too recently const now = Date.now(); @@ -609,43 +623,47 @@ export default function Home() { } lastScrollTimeRef.current = now; + isAnimatingRef.current = true; + activeSectionIndexRef.current = nextIndex; - // Reset scroll position of all scrollable elements in the target section + // Ensure the scroll feels smooth but strictly locks to 1 section + // using the document's scrolling element const targetSection = sections[nextIndex]; - const scrollableElements = Array.from( - targetSection.querySelectorAll(SCROLLABLE_SELECTORS), - ); - // Fallback: if no matching descendants, include the section itself if it is scrollable - if ( - scrollableElements.length === 0 && isScrollableElement(targetSection) - ) { - scrollableElements.push(targetSection); - } - scrollableElements.forEach((el) => { - // Only reset if element has scrollable content (using same tolerance as isScrollableElement) - if (el.scrollHeight - el.clientHeight > 1) { - el.scrollTop = 0; - } - }); + const targetTop = targetSection.getBoundingClientRect().top + + window.scrollY; - isAnimatingRef.current = true; - sections[nextIndex].scrollIntoView({ + window.scrollTo({ + top: targetTop, behavior: "smooth", - block: "start", }); - activeSectionIndexRef.current = nextIndex; + // Clear any existing timeout if (unlockTimeoutRef.current) { clearTimeout(unlockTimeoutRef.current); } + // Reset scroll tracking and allow next scroll after animation completes unlockTimeoutRef.current = setTimeout(() => { isAnimatingRef.current = false; + wheelAccumulatorRef.current = 0; // reset accumulator after animation + syncSectionIndex(); }, SCROLL_LOCK_DURATION); }; const handleWheel = (event: WheelEvent) => { - // Check if we're in a scrollable area first + // Setup scrolling ends detector to reset inertia blocking + if (scrollEndTimeoutRef.current) { + clearTimeout(scrollEndTimeoutRef.current); + } + + // If we don't see wheel events for 150ms, assume the trackpad gesture/momentum has thoroughly ended + scrollEndTimeoutRef.current = setTimeout(() => { + isInertiaScrollingRef.current = false; + wheelAccumulatorRef.current = 0; + }, 150); + + // Always prevent default native scroll immediately if we intend to handle it via snap + // but only if it's not a modifying shortcut or inside a scrollable div if ( event.ctrlKey || allowNativeScroll(event.target, event.deltaY > 0 ? 1 : -1) @@ -653,19 +671,59 @@ export default function Home() { return; } - // Always prevent default for section scrolling, even when animating + const direction = event.deltaY > 0 ? 1 : -1; + + // Allow free native scrolling within sections taller than the viewport + if (canScrollWithinSection(direction)) { + return; + } + + // We are in snap-mode territory, immediately prevent native default scroll + // so trackpad inertia doesn't bleed into the actual page scroll event.preventDefault(); - // Block scroll attempts while an animation is currently running + const now = Date.now(); + + // Block all hardware scroll attempts during animation if (isAnimatingRef.current) { + // Since we got an event during animation, extend the inertia block flag + // to prevent immediate skipping once the animation unlocks + isInertiaScrollingRef.current = true; + return; + } + + // If we are currently "coasting" (receiving inertia events from a previous swipe) + // or if we haven't crossed the time lock threshold, block the scroll + if ( + isInertiaScrollingRef.current || + now - lastScrollTimeRef.current < SCROLL_LOCK_DURATION + ) { + // Still trackpad coasting + isInertiaScrollingRef.current = true; return; } - if (Math.abs(event.deltaY) < MIN_WHEEL_DELTA) { + // Trackpads fire hundreds of tiny wheel events. We use an accumulator + // to ensure a deliberate swipe happens, ignoring delicate resting finger movements + wheelAccumulatorRef.current += event.deltaY; + + if (wheelLockTimeoutRef.current) { + clearTimeout(wheelLockTimeoutRef.current); + } + + // Accumulator reset for slow continuous touches vs rapid flicks + wheelLockTimeoutRef.current = setTimeout(() => { + wheelAccumulatorRef.current = 0; + }, 50); + + // Require a larger accumulation for trackpads to trigger the next section + if (Math.abs(wheelAccumulatorRef.current) < 50) { return; } - scrollToSection(event.deltaY > 0 ? 1 : -1); + // Mark that a heavy stroke happened, lock down further events as inertia + isInertiaScrollingRef.current = true; + scrollToSection(direction); }; const handleKeyDown = (event: KeyboardEvent) => { @@ -673,6 +731,13 @@ export default function Home() { return; } + const isDownKey = ["ArrowDown", "PageDown", " "].includes(event.key); + const isUpKey = ["ArrowUp", "PageUp"].includes(event.key); + + if (!isDownKey && !isUpKey) { + return; + } + // Ignore key events when focus is inside interactive/input elements const target = event.target; @@ -690,93 +755,26 @@ export default function Home() { return; } - if (["ArrowDown", "PageDown", " "].includes(event.key)) { - event.preventDefault(); - if (!isAnimatingRef.current) scrollToSection(1); - } else if (["ArrowUp", "PageUp"].includes(event.key)) { - event.preventDefault(); - if (!isAnimatingRef.current) scrollToSection(-1); - } - }; - - const resetTouchTracking = () => { - touchStartYRef.current = null; - touchStartXRef.current = null; - touchIsVerticalRef.current = null; - }; - - const handleTouchStart = (event: TouchEvent) => { - if ( - event.touches.length !== 1 || allowNativeScroll(event.touches[0].target) - ) { - touchStartedWithinScrollableRef.current = true; - resetTouchTracking(); - return; - } - - touchStartedWithinScrollableRef.current = false; - touchStartYRef.current = event.touches[0].clientY; - touchStartXRef.current = event.touches[0].clientX; - touchIsVerticalRef.current = null; - }; - - const handleTouchMove = (event: TouchEvent) => { - if (touchStartYRef.current === null || event.touches.length !== 1) { - return; - } - - if (touchStartedWithinScrollableRef.current) { - return; - } - - // Block touch scrolling while animating - ensures only 1 section per gesture + // While animating, always block native keyboard scroll to avoid + // drifting between sections during smooth snap transitions. if (isAnimatingRef.current) { event.preventDefault(); - resetTouchTracking(); return; } - const currentTouch = event.touches[0]; - const deltaY = currentTouch.clientY - touchStartYRef.current; - const deltaX = currentTouch.clientX - - (touchStartXRef.current ?? currentTouch.clientX); - - if (touchIsVerticalRef.current === null) { - const totalDelta = Math.hypot(deltaX, deltaY); - if (totalDelta < 6) { + if (isDownKey) { + if (canScrollWithinSection(1)) { + return; // Allow native keyboard scroll within tall section + } + event.preventDefault(); + scrollToSection(1); + } else if (isUpKey) { + if (canScrollWithinSection(-1)) { return; } - touchIsVerticalRef.current = Math.abs(deltaY) >= Math.abs(deltaX); - } - - if (!touchIsVerticalRef.current) { - return; - } - - if (Math.abs(deltaY) < TOUCH_THRESHOLD_PX) { - return; - } - - const direction = deltaY > 0 ? -1 : 1; - if (allowNativeScroll(currentTouch.target, direction)) { - return; + event.preventDefault(); + scrollToSection(-1); } - - event.preventDefault(); - - scrollToSection(direction); - - resetTouchTracking(); - }; - - const handleTouchEnd = () => { - touchStartedWithinScrollableRef.current = false; - resetTouchTracking(); - }; - - const handleTouchCancel = () => { - touchStartedWithinScrollableRef.current = false; - resetTouchTracking(); }; const handleScroll = throttle(() => { @@ -794,23 +792,14 @@ export default function Home() { window.addEventListener("wheel", handleWheel, { passive: false }); window.addEventListener("keydown", handleKeyDown); - window.addEventListener("touchstart", handleTouchStart, { passive: false }); - window.addEventListener("touchmove", handleTouchMove, { passive: false }); - window.addEventListener("touchend", handleTouchEnd); - window.addEventListener("touchcancel", handleTouchCancel); window.addEventListener("scroll", handleScroll, { passive: true }); window.addEventListener("resize", handleResize); return () => { window.removeEventListener("wheel", handleWheel); window.removeEventListener("keydown", handleKeyDown); - window.removeEventListener("touchstart", handleTouchStart); - window.removeEventListener("touchmove", handleTouchMove); - window.removeEventListener("touchend", handleTouchEnd); - window.removeEventListener("touchcancel", handleTouchCancel); window.removeEventListener("scroll", handleScroll); window.removeEventListener("resize", handleResize); - resetTouchTracking(); if (unlockTimeoutRef.current) { clearTimeout(unlockTimeoutRef.current); diff --git a/package-lock.json b/package-lock.json index 4614c3c..830d30c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "devakesu-web", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "devakesu-web", - "version": "1.1.1", + "version": "1.1.2", "dependencies": { "next": "16.1.6", "react": "19.2.4", @@ -15,11 +15,11 @@ }, "devDependencies": { "@tailwindcss/postcss": "4.2.1", - "@types/node": "25.3.0", + "@types/node": "25.3.3", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", - "autoprefixer": "10.4.24", - "eslint": "9.39.1", + "autoprefixer": "10.4.27", + "eslint": "^9.39.1", "eslint-config-next": "16.1.6", "postcss": "8.5.6", "tailwindcss": "4.2.1", @@ -74,7 +74,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -471,9 +470,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.3", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", + "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", "dev": true, "license": "MIT", "engines": { @@ -560,9 +559,9 @@ } }, "node_modules/@img/colour": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", "license": "MIT", "optional": true, "engines": { @@ -1600,9 +1599,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1615,7 +1614,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1675,7 +1673,6 @@ "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/types": "8.56.1", @@ -1819,6 +1816,19 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils": { "version": "8.56.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", @@ -1861,6 +1871,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@unrs/resolver-binding-android-arm-eabi": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", @@ -2136,7 +2159,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2382,9 +2404,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.24", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", - "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", "dev": true, "funding": [ { @@ -2403,7 +2425,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001766", + "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -2477,9 +2499,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { @@ -2522,7 +2544,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2598,9 +2619,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001774", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", - "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "version": "1.0.30001775", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001775.tgz", + "integrity": "sha512-s3Qv7Lht9zbVKE9XoTyRG6wVDCKdtOFIjBGg3+Yhn6JaytuNKPIjBMTMIY1AnOH3seL5mvF+x33oGAyK3hVt3A==", "funding": [ { "type": "opencollective", @@ -2864,9 +2885,9 @@ "license": "MIT" }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3078,12 +3099,11 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.3", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", + "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3091,7 +3111,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.3", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -3206,7 +3226,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -3412,6 +3431,30 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -3429,19 +3472,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", @@ -3593,24 +3623,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -4998,9 +5010,9 @@ } }, "node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -5425,20 +5437,6 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -5469,7 +5467,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5544,7 +5541,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5554,7 +5550,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -6218,6 +6213,37 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6360,7 +6386,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6636,7 +6661,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 3fc24ba..a2e6313 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "devakesu-web", - "version": "1.1.1", + "version": "1.1.2", "private": true, "engines": { - "node": ">=20.9.0" + "node": ">=20.19.0" }, "scripts": { "dev": "next dev", @@ -22,10 +22,10 @@ }, "devDependencies": { "@tailwindcss/postcss": "4.2.1", - "@types/node": "25.3.0", + "@types/node": "25.3.3", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", - "autoprefixer": "10.4.24", + "autoprefixer": "10.4.27", "eslint": "^9.39.1", "eslint-config-next": "16.1.6", "postcss": "8.5.6",