feat(lp-2026): Next.js 16 hackathon LP, static-exported to Cloudflare Workers#11
Conversation
…lare Workers - Add the v0-generated Next.js 16 app-router LP (React 19, Tailwind v4, shadcn/ui, framer-motion; pnpm) under apps/hackathon-lp-2026, hosted like the other years on a Cloudflare Workers Static Assets Worker via Workers Builds. - next.config.mjs: output: 'export' (fully client-rendered, no server features) -> build emits ./out, served by the assets-only wrangler.toml (name nemtus-hackathon-lp-2026, custom domain hackathon-2026.nemtus.com; the aggregator already links there). - Fix the v0 lockfile's broken motion resolution: it pinned framer-motion@12.23.24 with motion-dom@12.42.2, which dropped the "activeAnimations" export framer-motion imports, breaking the build. Pin motion-dom to 12.23.23 via pnpm.overrides. - .npmrc ignore-scripts=false to override the inherited root hardening for this pnpm app. Verified: pnpm build succeeds; out/ has index.html/404.html/_next (215 files, max asset 1.78MiB < 25MiB limit); wrangler deploy --dry-run reads out/ cleanly. Build artifacts (node_modules/.next/out) are gitignored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds a standalone Next.js landing-page app for the hackathon, with build/deployment scaffolding, global theming, shared hooks/utilities, a reusable UI component set, and the landing page shell plus content sections. ChangesHackathon LP 2026 App
Estimated code review effort: 5 (Critical) | ~120 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
apps/hackathon-lp-2026/app/globals.cssOops! Something went wrong! :( ESLint: 8.57.1 YAMLException: Cannot read config file: /apps/hackathon-lp-2026/eslint.config.mjs 7 | apps/hackathon-lp-2026/app/layout.tsxOops! Something went wrong! :( ESLint: 8.57.1 YAMLException: Cannot read config file: /apps/hackathon-lp-2026/eslint.config.mjs 7 | apps/hackathon-lp-2026/components/about.tsxOops! Something went wrong! :( ESLint: 8.57.1 YAMLException: Cannot read config file: /apps/hackathon-lp-2026/eslint.config.mjs 7 |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
nemtus-hackathon-lp-2023 | 891d960 | Jul 02 2026, 02:38 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
nemtus-hackathon-lp | 891d960 | Jul 02 2026, 02:40 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
nemtus-hackathon-lp-2024 | 891d960 | Jul 02 2026, 02:43 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
nemtus-hackathon-lp-2025 | 891d960 | Jul 02 2026, 02:45 PM |
There was a problem hiding this comment.
Actionable comments posted: 15
🧹 Nitpick comments (14)
apps/hackathon-lp-2026/next.config.mjs (1)
5-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReconsider suppressing TypeScript build errors.
ignoreBuildErrors: trueletsnext buildsucceed even with type errors, defeating type safety for a codebase that will keep growing. If this was only added to work around v0-generated code that hasn't been fully typed yet, consider fixing the type errors and removing this flag before the app matures.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/next.config.mjs` around lines 5 - 7, The Next.js TypeScript config is suppressing build-time type checking via ignoreBuildErrors in next.config.mjs, which weakens type safety. Remove that flag from the typescript config in next.config.mjs and fix the underlying type issues so next build runs with full TypeScript validation; use the next.config.mjs typescript block as the target location.apps/hackathon-lp-2026/hooks/use-toast.ts (1)
171-189: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
useEffectdependency causes needless resubscribe churn.The effect depends on
[state](Line 182) but only pushes/removes the stablesetStatereference intolisteners. Every toast dispatch re-runs cleanup+setup unnecessarily. Functionally harmless here (inherited from shadcn/ui boilerplate) but worth tightening.♻️ Proposed fix
React.useEffect(() => { listeners.push(setState) return () => { const index = listeners.indexOf(setState) if (index > -1) { listeners.splice(index, 1) } } - }, [state]) + }, [])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/hooks/use-toast.ts` around lines 171 - 189, The useEffect in useToast is resubscribing on every state change even though it only uses the stable setState callback; update the dependency array to stop depending on state so the listener is registered once and cleaned up once. Keep the push/splice logic in useToast unchanged and ensure the effect depends only on the stable setter reference, not the toast state itself.apps/hackathon-lp-2026/app/layout.tsx (1)
55-84: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueEscape the JSON-LD string before injecting it into
<script>
JSON.stringify(...)is fine for the current hardcoded data, but add.replace(/</g, "\\u003c")here so a future dynamic field can’t break out of the script tag.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/app/layout.tsx` around lines 55 - 84, The JSON-LD injection in the layout’s script block needs escaping before being inserted into the `<script>` tag. Update the `dangerouslySetInnerHTML` payload in `app/layout.tsx` so the `JSON.stringify(...)` result is post-processed with an escape for `<` characters, preventing any future dynamic field from breaking out of the script context. Keep the change localized to the Event schema block in `layout.tsx`.Source: Linters/SAST tools
apps/hackathon-lp-2026/components/ui/use-toast.ts (2)
174-182: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUnnecessary effect dependency causes repeated resubscription.
setStateis stable across renders, so depending on[state](Line 182) tears down and re-adds the listener on every dispatch instead of only on mount/unmount.♻️ Proposed fix
React.useEffect(() => { listeners.push(setState) return () => { const index = listeners.indexOf(setState) if (index > -1) { listeners.splice(index, 1) } } - }, [state]) + }, [])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/ui/use-toast.ts` around lines 174 - 182, The listener registration effect in use-toast.ts is resubscribing on every state change because the React.useEffect dependency is [state] instead of the stable setState callback. Update the effect that pushes/removes setState from listeners so it only runs on mount/unmount by removing the changing state dependency and using the stable setter reference in the cleanup.
1-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate toast state module across
hooks/use-toast.tsandcomponents/ui/use-toast.ts.This file re-implements the same
useToast/toast/reducer logic as thehooks/use-toast.tsmodule from another layer, resulting in two independent, unsynchronized toast stores. Components importing from different paths will not share toast state.Consider consolidating to a single source of truth and re-exporting from the other location.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/ui/use-toast.ts` around lines 1 - 16, The toast state logic is duplicated here and in hooks/use-toast.ts, creating two separate unsynchronized stores. Consolidate the implementation into a single source of truth in one module (for example the existing useToast/toast/reducer code) and make the other module re-export it so all callers share the same toast state. Keep the shared symbols like useToast, toast, and reducer in one place and update imports accordingly.apps/hackathon-lp-2026/components/ui/toaster.tsx (1)
1-36: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the dead toast stack and duplicate hooks.
app/layout.tsx/app/page.tsxdon’t mount either toast provider, and the repo still carries duplicateuse-toast/use-mobilecopies undercomponents/ui/beside thehooks/versions. Keep one implementation to avoid stale, diverging code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/ui/toaster.tsx` around lines 1 - 36, The Toaster component is rendering a toast stack that is not mounted anywhere, and the repo also contains duplicate hook implementations under components/ui alongside the canonical hooks versions. Remove the unused toaster wiring in Toaster and keep only one source of truth for the toast/mobile hooks, updating any imports to use the shared hooks use-toast/use-mobile symbols so there are no stale duplicates.apps/hackathon-lp-2026/components/ui/menubar.tsx (1)
219-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInconsistent outline handling in
MenubarSubTrigger.Line 232 uses
outline-nonewhile every other interactive item in this file (MenubarItem,MenubarCheckboxItem,MenubarRadioItem) and the equivalentDropdownMenuSubTriggeruseoutline-hidden. In Tailwind v4,outline-nonefully removes the outline (including in forced-colors/high-contrast mode), whereasoutline-hiddenpreserves visibility for accessibility in that mode.Suggested fix
className={cn( - 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8', + 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8', className, )}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/ui/menubar.tsx` around lines 219 - 241, The MenubarSubTrigger component is using outline-none while the other interactive menu items and the matching DropdownMenuSubTrigger use outline-hidden. Update the class list in MenubarSubTrigger to use outline-hidden so focus styling stays accessible in forced-colors/high-contrast mode, keeping the change localized to the MenubarPrimitive.SubTrigger wrapper.apps/hackathon-lp-2026/components/ui/use-mobile.tsx (1)
1-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate
useIsMobileimplementation.Identical to
apps/hackathon-lp-2026/hooks/use-mobile.ts, which is the version actually imported bysidebar.tsx. Consider removing this copy and re-exporting/importing from the shared hook to avoid future divergence.♻️ Proposed fix
-import * as React from 'react' - -const MOBILE_BREAKPOINT = 768 - -export function useIsMobile() { - const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined) - - React.useEffect(() => { - const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) - const onChange = () => { - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - } - mql.addEventListener('change', onChange) - setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - return () => mql.removeEventListener('change', onChange) - }, []) - - return !!isMobile -} +export { useIsMobile } from '`@/hooks/use-mobile`'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/ui/use-mobile.tsx` around lines 1 - 20, The useIsMobile hook here is a duplicate of the shared implementation, which risks diverging behavior over time. Remove the local hook in use-mobile.tsx and make this module re-export or import the canonical useIsMobile from the shared hooks/use-mobile implementation so sidebar.tsx and other consumers all use the same source of truth.apps/hackathon-lp-2026/components/navigation.tsx (1)
32-47: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUnthrottled scroll handler runs
getBoundingClientRectfor every nav item on every scroll event.
handleScrolliterates allNAV_ITEMSand callsdocument.getElementById+getBoundingClientRecton each scroll tick without debouncing/throttling (e.g. viarequestAnimationFrame). This can cause layout thrashing and janky scrolling, especially on lower-end devices.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/navigation.tsx` around lines 32 - 47, The handleScroll scroll-spy logic in navigation.tsx is doing DOM reads on every scroll event, which can cause janky scrolling. Update handleScroll to be throttled or scheduled via requestAnimationFrame before calling document.getElementById and getBoundingClientRect for NAV_ITEMS, and keep the activeSection/isScrolled updates inside that optimized path.apps/hackathon-lp-2026/components/circuit-background.tsx (1)
61-129: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winLarge number of continuously-animated SVG elements may hurt performance.
With
gridSize = 8.3over a 1400×1800 viewport,generateGridPaths()produces roughly 350-400 line entries, each rendering a static<line>plus an infinitely-loopingmotion.line(lines 69-93, 97-121). That's 700+ animated SVG elements running Framer Motion's animation loop simultaneously on every page load, purely as decoration — a real risk for jank/battery drain on low-end/mobile devices.Consider increasing
gridSize, capping the animated line count (e.g., only animate a subset), or switching to a lighter technique (CSS@keyframes, canvas, orwill-change+ fewer elements) for this purely decorative background.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/circuit-background.tsx` around lines 61 - 129, The CircuitBackground decorative SVG is creating too many continuously looping Framer Motion elements, which can hurt performance on low-end devices. Reduce the number of animated paths in CircuitBackground by increasing the density step, capping or sampling the gridPaths that get a motion.line, or replacing the per-element animation with a lighter approach such as CSS keyframes or canvas so the background stays visual without animating hundreds of SVG nodes.apps/hackathon-lp-2026/components/about.tsx (1)
1-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInconsistent in-view hook: uses framer-motion's
useInViewdirectly instead of the shared hook.Every sibling section (
participation-flow.tsx,themes.tsx,multi-chain.tsx,prizes.tsx,schedule.tsx) uses the shared@/hooks/use-in-viewhook, which triggers once and staystrue. This file instead calls framer-motion's ownuseInView(ref, { once: false, amount: 0.3 })directly, giving it different semantics (re-toggles on every viewport exit/enter) from the rest of the page. This is a maintainability/consistency gap and unnecessary duplication of the "detect in view" concept.♻️ Align with the shared hook used elsewhere
-import { motion, useInView } from "framer-motion" -import { useRef } from "react" +import { motion } from "framer-motion" +import { useInView } from "`@/hooks/use-in-view`" import { Card } from "`@/components/ui/card`" export function About() { - const ref = useRef(null) - const isInView = useInView(ref, { once: false, amount: 0.3 }) + const { ref, isInView } = useInView()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/about.tsx` around lines 1 - 9, The About section is using framer-motion’s local useInView(ref, { once: false, amount: 0.3 }) directly instead of the shared `@/hooks/use-in-view` hook used by the other page sections. Update About to use the shared hook for consistent once-only in-view behavior and remove the duplicated in-view setup, keeping the motion/Card logic in About aligned with participation-flow, themes, multi-chain, prizes, and schedule.apps/hackathon-lp-2026/components/entry.tsx (2)
22-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHardcoded "published" flags produce permanently dead code branches.
isDocumentsPublished/isRulesPublishedare alwaystrue, so the disabled-button branches (Lines 70-79, 94-103, 139-148) can never render. If these were meant to be togglable likeIS_HACKATHON_ENDED, move them intolib/constants.tsas real flags; otherwise drop the conditionals and unreachable branches.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/entry.tsx` around lines 22 - 23, The hardcoded isDocumentsPublished and isRulesPublished constants in Entry make the disabled button branches in Entry unreachable. Either move these flags into lib/constants.ts as real toggles if they need to be configurable, or remove the conditional rendering and dead disabled-button branches entirely from Entry and keep only the always-enabled path.
45-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated Button/ExternalLink ternary pattern across both branches.
The same "asChild active button vs. disabled fallback with icon" shape is repeated 4 times with only className/href/label differing, and the two branches (open vs. ended) diverge inconsistently — e.g. the submit-PDF button in the "ended" branch (Lines 117-125) is unconditionally disabled instead of also checking
isDocumentsPublishedlike the open branch does (Lines 58-80). Extracting a smallLinkButton({ href, published, ... })helper would remove the duplication and the inconsistency risk.♻️ Example extraction
function ExternalLinkButton({ href, published, disabled, size = "lg", variant, className, children, }: { href: string published: boolean disabled?: boolean size?: "lg" | "sm" variant?: "outline" className: string children: React.ReactNode }) { if (!published || disabled) { return ( <Button size={size} disabled variant={variant} className={`${className} opacity-50 cursor-not-allowed`}> {children} <ExternalLink className="ml-2" size={size === "lg" ? 18 : 16} /> </Button> ) } return ( <Button asChild size={size} variant={variant} className={className}> <a href={href} target="_blank" rel="noopener noreferrer"> {children} <ExternalLink className="ml-2" size={size === "lg" ? 18 : 16} /> </a> </Button> ) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/entry.tsx` around lines 45 - 151, The button rendering in Entry uses the same active-vs-disabled ExternalLink pattern repeatedly and the open/ended branches are drifting, especially for the submit-PDF button where the ended branch ignores isDocumentsPublished. Extract a reusable helper/component such as ExternalLinkButton inside entry.tsx and use it for the ENTRY_URL, SUBMIT_PDF_URL, and RULES_PDF_URL cases so the published/disabled logic lives in one place and both branches stay consistent.apps/hackathon-lp-2026/components/sponsors.tsx (1)
138-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winToggle button lacks
aria-expanded.The expand/collapse control changes visible content but doesn't expose its state to assistive tech.
🛠 Suggested fix
<button onClick={() => setIsExpanded(!isExpanded)} + aria-expanded={isExpanded} className="text-sm text-purple-400 hover:text-purple-300 transition-colors mt-2 flex items-center gap-1 self-start" >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/sponsors.tsx` around lines 138 - 153, The expand/collapse button in sponsors.tsx does not expose its current state to assistive technology. Update the toggle control in the shouldTruncate block to include an aria-expanded attribute that reflects isExpanded, and keep it tied to the existing onClick/setIsExpanded behavior. Use the button inside the truncation UI as the reference point so the accessible state matches the visible “もっと見る/閉じる” content.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/hackathon-lp-2026/app/globals.css`:
- Around line 93-97: The macOS system font fallback in the `@theme` inline block
is misspelled, so the intended font never applies. Update the --font-heading
value in globals.css to use the correct BlinkMacSystemFont token, matching the
existing --font-sans fallback style, and keep the rest of the font stack
unchanged.
In `@apps/hackathon-lp-2026/components/circuit-background.tsx`:
- Around line 5-59: The module-level grid generation in generateGridPaths is
using Math.random() to build gridPaths, which makes the server-rendered output
differ from the client during hydration. Move the randomization out of module
scope in circuit-background.tsx, either by generating the paths inside a
client-only effect/state after mount or by replacing Math.random() with
deterministic values derived from stable inputs like the path index. Make sure
the motion.line props that read path.direction, path.delay, and path.duration
still receive consistent values on both renders.
In `@apps/hackathon-lp-2026/components/final-cta.tsx`:
- Around line 9-11: The `FinalCTA` component is deriving `isEntryOpen` directly
from `new Date()` in the render body, so it will only update when `useInView()`
triggers a re-render and can become stale. Update `FinalCTA` to use the same
shared periodically-updating entry-state hook used by
`navigation.tsx`/`hero.tsx`, and compute `isEntryOpen` from that shared source
instead of inline time math. Ensure the hook or shared state is what drives the
CTA rendering so the entry status refreshes automatically without requiring a
reload.
In `@apps/hackathon-lp-2026/components/footer.tsx`:
- Around line 73-75: The footer copyright text is stale and should be updated in
the Footer component. Replace the hardcoded year in the copyright line with the
current year, ideally by deriving it dynamically using the Footer’s render logic
so it stays correct over time. Update the text where the © notice is rendered in
the footer markup.
In `@apps/hackathon-lp-2026/components/hero.tsx`:
- Around line 10-46: The countdown transition is not triggering a final state
update, so the UI can stay stale when the target date passes. Update
useCountdown to perform one last timeLeft state update when distance drops below
zero, and make sure Hero derives isEntryOpen from the same countdown state
instead of only recomputing new Date() on render. Use the useCountdown hook and
the isEntryOpen logic in Hero to keep the entry-open/ended branches in sync.
In `@apps/hackathon-lp-2026/components/highlights.tsx`:
- Around line 60-86: The hover-glow overlay is not triggering because the
`group-hover` overlay sits outside the element that has the `group` class in
`highlights`, and the same pattern appears in `judges` and `sponsors`. Move the
`group` class to a parent wrapper that contains both the glow overlay and the
`Card`, or otherwise make the overlay a descendant of the `.group` element so
Tailwind’s `group-hover` can apply. Update the affected wrapper structure in the
`highlight.icon` card block and mirror the same fix in the corresponding card
layouts in `judges` and `sponsors`.
- Line 44: The in-view setup in useInView currently uses an unsupported amount
option, so update it to use the proper threshold setting to wait for full
visibility. Also fix the glow so it’s rendered inside the hovered .group card
rather than as a sibling, ensuring group-hover:opacity-100 can actually trigger
it; adjust the highlights.tsx component structure around the useInView and glow
markup accordingly.
In `@apps/hackathon-lp-2026/components/navigation.tsx`:
- Around line 29-51: The Navigation component’s `isEntryOpen` is only set once
in the mount-only `useEffect`, so it never updates when `ENTRY_START_DATE` is
crossed during an open session. Update `navigation.tsx` by moving this logic
into a shared `useEntryStatus()` hook (or equivalent) that recomputes on a timer
or scheduled timeout, and use that same hook in `Navigation`, `Hero`, and
`FinalCTA` so all CTA states stay consistent without a page reload.
In `@apps/hackathon-lp-2026/components/results.tsx`:
- Line 27: The useInView configuration in results.tsx is using the wrong option
name, so the visibility trigger is not applied as intended. Update the useInView
call in the Results component to replace amount with threshold, keeping the same
0.3 value so the IntersectionObserver fires at 30% visibility.
In `@apps/hackathon-lp-2026/components/ui/carousel.tsx`:
- Around line 96-105: The carousel effect in `Carousel` registers both `reInit`
and `select` on `api`, but the cleanup only unsubscribes `select`, so stale
`reInit` listeners can accumulate when the effect reruns. Update the cleanup in
the `React.useEffect` block to remove both listeners from the same `api`
instance, keeping the subscribe/unsubscribe pair symmetric for `onSelect`,
`api.on`, and `api.off`.
In `@apps/hackathon-lp-2026/components/ui/chart.tsx`:
- Around line 235-239: Zero values are being rendered as a stray text node in
the chart tooltip because the conditional around item.value uses a truthy check.
Update the tooltip rendering in the chart component where item.value is
displayed so it matches the existing undefined check used elsewhere in this
file, and only render the span when item.value is actually defined rather than
relying on item.value && (...).
In `@apps/hackathon-lp-2026/components/ui/collapsible.tsx`:
- Around line 1-9: The Collapsible wrapper uses React.ComponentProps in the
Collapsible function without importing React, which will cause a TypeScript
error. Update the component module to follow the same pattern as the other UI
wrappers by adding the React import at the top, keeping the existing
CollapsiblePrimitive.Root usage unchanged.
In `@apps/hackathon-lp-2026/components/ui/empty.tsx`:
- Around line 1-4: The `empty.tsx` module uses `React.ComponentProps` in its
component type definitions, but it does not import the React namespace, so
TypeScript cannot resolve it. Update the top of the file to add the React import
alongside the existing `cva` and `cn` imports, keeping the component definitions
that reference `React.ComponentProps` unchanged.
In `@apps/hackathon-lp-2026/components/ui/navigation-menu.tsx`:
- Around line 1-7: The NavigationMenu wrapper needs a client boundary because it
uses interactive Radix primitives and icons that must run on the client. Add the
client directive at the top of the navigation-menu.tsx module so the
NavigationMenu component can be safely imported from Server Components. Keep the
change local to this wrapper file and ensure the directive appears before the
React and NavigationMenuPrimitive imports.
In `@apps/hackathon-lp-2026/styles/globals.css`:
- Around line 21-23: The destructive color tokens in globals.css are mismatched
because --destructive-foreground currently uses the same value as --destructive,
making destructive text unreadable. Update the theme token in the globals.css
variables block so --destructive-foreground uses a contrasting foreground color,
and verify any components that rely on destructive variants (for example button
and alert styles) inherit the corrected token.
---
Nitpick comments:
In `@apps/hackathon-lp-2026/app/layout.tsx`:
- Around line 55-84: The JSON-LD injection in the layout’s script block needs
escaping before being inserted into the `<script>` tag. Update the
`dangerouslySetInnerHTML` payload in `app/layout.tsx` so the
`JSON.stringify(...)` result is post-processed with an escape for `<`
characters, preventing any future dynamic field from breaking out of the script
context. Keep the change localized to the Event schema block in `layout.tsx`.
In `@apps/hackathon-lp-2026/components/about.tsx`:
- Around line 1-9: The About section is using framer-motion’s local
useInView(ref, { once: false, amount: 0.3 }) directly instead of the shared
`@/hooks/use-in-view` hook used by the other page sections. Update About to use
the shared hook for consistent once-only in-view behavior and remove the
duplicated in-view setup, keeping the motion/Card logic in About aligned with
participation-flow, themes, multi-chain, prizes, and schedule.
In `@apps/hackathon-lp-2026/components/circuit-background.tsx`:
- Around line 61-129: The CircuitBackground decorative SVG is creating too many
continuously looping Framer Motion elements, which can hurt performance on
low-end devices. Reduce the number of animated paths in CircuitBackground by
increasing the density step, capping or sampling the gridPaths that get a
motion.line, or replacing the per-element animation with a lighter approach such
as CSS keyframes or canvas so the background stays visual without animating
hundreds of SVG nodes.
In `@apps/hackathon-lp-2026/components/entry.tsx`:
- Around line 22-23: The hardcoded isDocumentsPublished and isRulesPublished
constants in Entry make the disabled button branches in Entry unreachable.
Either move these flags into lib/constants.ts as real toggles if they need to be
configurable, or remove the conditional rendering and dead disabled-button
branches entirely from Entry and keep only the always-enabled path.
- Around line 45-151: The button rendering in Entry uses the same
active-vs-disabled ExternalLink pattern repeatedly and the open/ended branches
are drifting, especially for the submit-PDF button where the ended branch
ignores isDocumentsPublished. Extract a reusable helper/component such as
ExternalLinkButton inside entry.tsx and use it for the ENTRY_URL,
SUBMIT_PDF_URL, and RULES_PDF_URL cases so the published/disabled logic lives in
one place and both branches stay consistent.
In `@apps/hackathon-lp-2026/components/navigation.tsx`:
- Around line 32-47: The handleScroll scroll-spy logic in navigation.tsx is
doing DOM reads on every scroll event, which can cause janky scrolling. Update
handleScroll to be throttled or scheduled via requestAnimationFrame before
calling document.getElementById and getBoundingClientRect for NAV_ITEMS, and
keep the activeSection/isScrolled updates inside that optimized path.
In `@apps/hackathon-lp-2026/components/sponsors.tsx`:
- Around line 138-153: The expand/collapse button in sponsors.tsx does not
expose its current state to assistive technology. Update the toggle control in
the shouldTruncate block to include an aria-expanded attribute that reflects
isExpanded, and keep it tied to the existing onClick/setIsExpanded behavior. Use
the button inside the truncation UI as the reference point so the accessible
state matches the visible “もっと見る/閉じる” content.
In `@apps/hackathon-lp-2026/components/ui/menubar.tsx`:
- Around line 219-241: The MenubarSubTrigger component is using outline-none
while the other interactive menu items and the matching DropdownMenuSubTrigger
use outline-hidden. Update the class list in MenubarSubTrigger to use
outline-hidden so focus styling stays accessible in forced-colors/high-contrast
mode, keeping the change localized to the MenubarPrimitive.SubTrigger wrapper.
In `@apps/hackathon-lp-2026/components/ui/toaster.tsx`:
- Around line 1-36: The Toaster component is rendering a toast stack that is not
mounted anywhere, and the repo also contains duplicate hook implementations
under components/ui alongside the canonical hooks versions. Remove the unused
toaster wiring in Toaster and keep only one source of truth for the toast/mobile
hooks, updating any imports to use the shared hooks use-toast/use-mobile symbols
so there are no stale duplicates.
In `@apps/hackathon-lp-2026/components/ui/use-mobile.tsx`:
- Around line 1-20: The useIsMobile hook here is a duplicate of the shared
implementation, which risks diverging behavior over time. Remove the local hook
in use-mobile.tsx and make this module re-export or import the canonical
useIsMobile from the shared hooks/use-mobile implementation so sidebar.tsx and
other consumers all use the same source of truth.
In `@apps/hackathon-lp-2026/components/ui/use-toast.ts`:
- Around line 174-182: The listener registration effect in use-toast.ts is
resubscribing on every state change because the React.useEffect dependency is
[state] instead of the stable setState callback. Update the effect that
pushes/removes setState from listeners so it only runs on mount/unmount by
removing the changing state dependency and using the stable setter reference in
the cleanup.
- Around line 1-16: The toast state logic is duplicated here and in
hooks/use-toast.ts, creating two separate unsynchronized stores. Consolidate the
implementation into a single source of truth in one module (for example the
existing useToast/toast/reducer code) and make the other module re-export it so
all callers share the same toast state. Keep the shared symbols like useToast,
toast, and reducer in one place and update imports accordingly.
In `@apps/hackathon-lp-2026/hooks/use-toast.ts`:
- Around line 171-189: The useEffect in useToast is resubscribing on every state
change even though it only uses the stable setState callback; update the
dependency array to stop depending on state so the listener is registered once
and cleaned up once. Keep the push/splice logic in useToast unchanged and ensure
the effect depends only on the stable setter reference, not the toast state
itself.
In `@apps/hackathon-lp-2026/next.config.mjs`:
- Around line 5-7: The Next.js TypeScript config is suppressing build-time type
checking via ignoreBuildErrors in next.config.mjs, which weakens type safety.
Remove that flag from the typescript config in next.config.mjs and fix the
underlying type issues so next build runs with full TypeScript validation; use
the next.config.mjs typescript block as the target location.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e2e74beb-2ee6-4ece-bc3e-218735d1b1fd
⛔ Files ignored due to path filters (42)
apps/hackathon-lp-2026/pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlapps/hackathon-lp-2026/public/Jaguar.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/SP_Astar_Color_Black.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/SP_SEKKA_SHIRETOKO.jpegis excluded by!**/*.jpegapps/hackathon-lp-2026/public/SP_as_logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/apple-icon.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/Astar_logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/BitcoinLogo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/CosmosLogo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/NEM_Logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/Symbol_Logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/avalanche_logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/eth.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/mona.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/soneiumLogo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/cryptlogo/suilogo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/goto.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/hayakawa_profile.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/icon-dark-32x32.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/icon-light-32x32.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/icon.svgis excluded by!**/*.svgapps/hackathon-lp-2026/public/images/Daoka.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/chaintokyo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/design-mode/logo_hacktus_%EF%BD%82_2026S.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/logo-hacktus-fabi.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/pleasanter.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/sp-gox-logo-w.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/sp-hatchet-avatar.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/sp-one-line-full-color-light.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/sp-progate.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/images/sp-wavee2.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/kuramochi.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/logo-hacktus-2026.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/mizuki.jpgis excluded by!**/*.jpgapps/hackathon-lp-2026/public/placeholder-logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/placeholder-logo.svgis excluded by!**/*.svgapps/hackathon-lp-2026/public/placeholder-user.jpgis excluded by!**/*.jpgapps/hackathon-lp-2026/public/placeholder.jpgis excluded by!**/*.jpgapps/hackathon-lp-2026/public/placeholder.svgis excluded by!**/*.svgapps/hackathon-lp-2026/public/sp_fushiginayado.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/sp_tss_logo.pngis excluded by!**/*.pngapps/hackathon-lp-2026/public/takahashi.pngis excluded by!**/*.png
📒 Files selected for processing (94)
apps/hackathon-lp-2026/.gitignoreapps/hackathon-lp-2026/.npmrcapps/hackathon-lp-2026/README.mdapps/hackathon-lp-2026/app/globals.cssapps/hackathon-lp-2026/app/layout.tsxapps/hackathon-lp-2026/app/page.tsxapps/hackathon-lp-2026/components.jsonapps/hackathon-lp-2026/components/about.tsxapps/hackathon-lp-2026/components/circuit-background.tsxapps/hackathon-lp-2026/components/entry.tsxapps/hackathon-lp-2026/components/faq.tsxapps/hackathon-lp-2026/components/final-cta.tsxapps/hackathon-lp-2026/components/footer.tsxapps/hackathon-lp-2026/components/hero.tsxapps/hackathon-lp-2026/components/highlights.tsxapps/hackathon-lp-2026/components/judges.tsxapps/hackathon-lp-2026/components/multi-chain.tsxapps/hackathon-lp-2026/components/navigation.tsxapps/hackathon-lp-2026/components/nemtus-info.tsxapps/hackathon-lp-2026/components/participation-flow.tsxapps/hackathon-lp-2026/components/prizes.tsxapps/hackathon-lp-2026/components/results.tsxapps/hackathon-lp-2026/components/schedule.tsxapps/hackathon-lp-2026/components/sponsors.tsxapps/hackathon-lp-2026/components/theme-provider.tsxapps/hackathon-lp-2026/components/themes.tsxapps/hackathon-lp-2026/components/ui/accordion.tsxapps/hackathon-lp-2026/components/ui/alert-dialog.tsxapps/hackathon-lp-2026/components/ui/alert.tsxapps/hackathon-lp-2026/components/ui/aspect-ratio.tsxapps/hackathon-lp-2026/components/ui/avatar.tsxapps/hackathon-lp-2026/components/ui/badge.tsxapps/hackathon-lp-2026/components/ui/breadcrumb.tsxapps/hackathon-lp-2026/components/ui/button-group.tsxapps/hackathon-lp-2026/components/ui/button.tsxapps/hackathon-lp-2026/components/ui/calendar.tsxapps/hackathon-lp-2026/components/ui/card.tsxapps/hackathon-lp-2026/components/ui/carousel.tsxapps/hackathon-lp-2026/components/ui/chart.tsxapps/hackathon-lp-2026/components/ui/checkbox.tsxapps/hackathon-lp-2026/components/ui/collapsible.tsxapps/hackathon-lp-2026/components/ui/command.tsxapps/hackathon-lp-2026/components/ui/context-menu.tsxapps/hackathon-lp-2026/components/ui/dialog.tsxapps/hackathon-lp-2026/components/ui/drawer.tsxapps/hackathon-lp-2026/components/ui/dropdown-menu.tsxapps/hackathon-lp-2026/components/ui/empty.tsxapps/hackathon-lp-2026/components/ui/field.tsxapps/hackathon-lp-2026/components/ui/form.tsxapps/hackathon-lp-2026/components/ui/hover-card.tsxapps/hackathon-lp-2026/components/ui/input-group.tsxapps/hackathon-lp-2026/components/ui/input-otp.tsxapps/hackathon-lp-2026/components/ui/input.tsxapps/hackathon-lp-2026/components/ui/item.tsxapps/hackathon-lp-2026/components/ui/kbd.tsxapps/hackathon-lp-2026/components/ui/label.tsxapps/hackathon-lp-2026/components/ui/menubar.tsxapps/hackathon-lp-2026/components/ui/navigation-menu.tsxapps/hackathon-lp-2026/components/ui/pagination.tsxapps/hackathon-lp-2026/components/ui/popover.tsxapps/hackathon-lp-2026/components/ui/progress.tsxapps/hackathon-lp-2026/components/ui/radio-group.tsxapps/hackathon-lp-2026/components/ui/resizable.tsxapps/hackathon-lp-2026/components/ui/scroll-area.tsxapps/hackathon-lp-2026/components/ui/select.tsxapps/hackathon-lp-2026/components/ui/separator.tsxapps/hackathon-lp-2026/components/ui/sheet.tsxapps/hackathon-lp-2026/components/ui/sidebar.tsxapps/hackathon-lp-2026/components/ui/skeleton.tsxapps/hackathon-lp-2026/components/ui/slider.tsxapps/hackathon-lp-2026/components/ui/sonner.tsxapps/hackathon-lp-2026/components/ui/spinner.tsxapps/hackathon-lp-2026/components/ui/switch.tsxapps/hackathon-lp-2026/components/ui/table.tsxapps/hackathon-lp-2026/components/ui/tabs.tsxapps/hackathon-lp-2026/components/ui/textarea.tsxapps/hackathon-lp-2026/components/ui/toast.tsxapps/hackathon-lp-2026/components/ui/toaster.tsxapps/hackathon-lp-2026/components/ui/toggle-group.tsxapps/hackathon-lp-2026/components/ui/toggle.tsxapps/hackathon-lp-2026/components/ui/tooltip.tsxapps/hackathon-lp-2026/components/ui/use-mobile.tsxapps/hackathon-lp-2026/components/ui/use-toast.tsapps/hackathon-lp-2026/hooks/use-in-view.tsxapps/hackathon-lp-2026/hooks/use-mobile.tsapps/hackathon-lp-2026/hooks/use-toast.tsapps/hackathon-lp-2026/lib/constants.tsapps/hackathon-lp-2026/lib/utils.tsapps/hackathon-lp-2026/next.config.mjsapps/hackathon-lp-2026/package.jsonapps/hackathon-lp-2026/postcss.config.mjsapps/hackathon-lp-2026/styles/globals.cssapps/hackathon-lp-2026/tsconfig.jsonapps/hackathon-lp-2026/wrangler.toml
…it/e2e/audit/socket) Tooling for apps/hackathon-lp-2026 (pnpm, standalone): - ESLint 9 flat config (typescript-eslint + react + react-hooks + @next/next) — passes - Prettier (.prettierrc) + format / format:check — codebase formatted to a baseline - type:check (tsc --noEmit): fixed the 5 v0 type errors centrally in hooks/use-in-view (generic ref + amount->threshold), so they are caught rather than masked here - Vitest + Testing Library (jsdom) — 14 guardrail tests: constants invariants, cn(), useInView behavior, Entry CTA gating on IS_HACKATHON_ENDED (both states), FAQ accordion - Playwright e2e against the static export (out/) — 4 tests: title, key sections, entry inert while ended, FAQ interaction, no JS runtime errors Scripts: lint / format / format:check / type:check / test / e2e / preview. CI: .github/workflows/ci-hackathon-lp-2026.yml (path-filtered, pnpm) with jobs: - verify: audit (--audit-level=high) + frozen install + lint + format:check + type:check + build + unit - e2e: playwright (chromium) - socket: runs `socket ci` when SOCKET_SECURITY_API_KEY is set, else no-op Deployment stays with Cloudflare Workers Builds (Git integration) — CI is checks only. Security: bumped next 16.0.10 -> 16.2.10 (clears 9 Next SSR/middleware advisories that do not apply to a static export); allowlisted the remaining transitive lodash `_.template` advisory (GHSA-r5fr-rjxr-66jc via recharts, unreachable in this static LP) through pnpm.auditConfig.ignoreGhsas so audit stays green and still blocks NEW high vulns. Storybook deferred: the vitest component/interaction tests + playwright e2e already cover the interactive behavior; a full Storybook harness adds limited value for this LP. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…p secret job Mirror nemtus/symbol-rest-api-client's token-free Socket setup instead of the API-key-based `socket ci` job: - Socket Firewall Free (SocketDev/action@…, mode: firewall-free — no token) wraps the pnpm install in the verify and e2e jobs (`sfw pnpm install --frozen-lockfile`), blocking confirmed-malicious packages at fetch time. - Add repo-root socket.yml for the Socket GitHub App (PR dependency-risk comments), with monorepo trigger paths (npm workspace + standalone npm apps + the pnpm 2026 app). - Remove the socket job that required SOCKET_SECURITY_API_KEY. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ydration) - app/globals.css: fix BlinkMacMacSystemFont -> BlinkMacSystemFont (font fallback typo) - footer: (c) 2025 -> 2026 - circuit-background: move Math.random() grid generation from module scope into a client-only useEffect/useState, avoiding a static-export hydration mismatch/flicker Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…loudflare cutover hackathon-2026.nemtus.com currently points at Vercel via an existing Cloudflare DNS record. Keeping the custom_domain route active would make the first Workers Builds deploy fail on a DNS conflict, so comment it out to deploy to *.workers.dev for safe verification. Restored by a follow-up PR once the Vercel DNS record is deleted.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (5)
apps/hackathon-lp-2026/components/sponsors.tsx (2)
88-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: extract a
Sponsorinterface instead of(typeof SPONSOR_LOGOS)[0].Deriving the prop type from the array element works but is slightly indirect; an explicit
interface Sponsor { name: string; logo: string; description: string; url: string }would be clearer and reusable.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/sponsors.tsx` around lines 88 - 92, The SponsorCard props currently infer sponsor from (typeof SPONSOR_LOGOS)[0], which is indirect and harder to reuse. Define a named Sponsor interface in sponsors.tsx with the sponsor fields, update SponsorCard to accept sponsor: Sponsor, and use that interface anywhere the sponsor shape is needed so the type is explicit and reusable.
131-131: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueConsider
next/imagefor LCP, with static-export caveats.Lint flags plain
<img>for LCP/bandwidth. Since this app builds withoutput: 'export',next/image's default optimizer requiresimages.unoptimized: trueor a custom loader (e.g., Cloudflare Images) to work with static export. Worth confirming this was a deliberate tradeoff rather than an oversight.Also applies to: 220-220
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/components/sponsors.tsx` at line 131, The sponsor image usage in the relevant component still relies on plain <img>, which triggers the LCP/bandwidth lint warning. Update the image rendering in sponsors.tsx to use next/image where appropriate, and make sure the static-export setup is handled correctly by either setting images.unoptimized: true or using a compatible custom loader. Also review the other img occurrence mentioned in the same component and apply the same choice consistently.Source: Linters/SAST tools
apps/hackathon-lp-2026/test/use-in-view.test.tsx (1)
43-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider covering the
once: falsereset behavior.Current tests cover the
amount→thresholdmapping and the latch-to-truecase, but the newly addedonceoption's reset-to-falsepath (hooks/use-in-view.tsxLine 26-28) isn't exercised.✅ Suggested additional test
+ it("resets isInView to false on exit when once=false", () => { + function OnceFalseProbe() { + const { ref, isInView } = useInView<HTMLDivElement>({ once: false }) + return <div ref={ref} data-testid="probe" data-inview={String(isInView)} /> + } + const { getByTestId } = render(<OnceFalseProbe />) + act(() => { + lastCallback?.([{ isIntersecting: true }]) + }) + expect(getByTestId("probe").getAttribute("data-inview")).toBe("true") + act(() => { + lastCallback?.([{ isIntersecting: false }]) + }) + expect(getByTestId("probe").getAttribute("data-inview")).toBe("false") + })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/test/use-in-view.test.tsx` around lines 43 - 52, Add a test in use-in-view.test.tsx to cover the once: false reset path in useInView, since the current Probe-based tests only verify the latch-to-true behavior. Update the existing test suite near the latches isInView test to simulate an intersecting callback followed by a non-intersecting one, and assert that the hook resets data-inview back to false when once is false. Use the existing Probe component, lastCallback, and useInView-related test setup to keep the coverage aligned with hooks/use-in-view.tsx.apps/hackathon-lp-2026/e2e/home.spec.ts (1)
7-13: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueBroad console-error filter could mask real regressions.
Failed to load resourceis matched loosely against any console error text, so a genuinely broken static asset (e.g. a missing JS chunk from the static export) would be silently ignored rather than failing the test, alongside the intended favicon-probe noise.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/hackathon-lp-2026/e2e/home.spec.ts` around lines 7 - 13, The console error filter in the e2e home spec is too broad and can hide real asset regressions. Tighten the guard inside the page.on("console") handler so it only ignores the specific benign probe you intend to skip (for example, the favicon request), rather than any msg.text() containing “Failed to load resource”; keep failing on broken static assets while still allowing harmless browser noise. Use the existing consoleErrors collection and the page.on("console") logic as the place to update..github/workflows/ci-hackathon-lp-2026.yml (1)
64-85: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueConsider gating
e2eonverifysucceeding.The
e2ejob has noneeds: verify, so Playwright runs (including its own install/build) even when lint/typecheck/unit tests already failed, wasting CI minutes on a doomed PR.e2e: name: e2e (playwright) + needs: verify runs-on: ubuntu-latest🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ci-hackathon-lp-2026.yml around lines 64 - 85, The e2e job currently runs independently, so it can spend time on Playwright install/build even after earlier checks fail. Update the e2e job in the workflow to depend on the verify job by adding a needs relationship, so e2e only starts after verify succeeds; keep the rest of the e2e steps unchanged and reference the e2e and verify job names when locating the workflow block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci-hackathon-lp-2026.yml:
- Line 39: Both jobs use actions/checkout without disabling persisted Git
credentials, which leaves the GITHUB_TOKEN available to later processes in the
job. Update each checkout step in ci-hackathon-lp-2026.yml to set
persist-credentials to false on the actions/checkout invocation so the token is
not written to local git config. Make the change in both checkout usages,
keeping the rest of the job behavior unchanged.
---
Nitpick comments:
In @.github/workflows/ci-hackathon-lp-2026.yml:
- Around line 64-85: The e2e job currently runs independently, so it can spend
time on Playwright install/build even after earlier checks fail. Update the e2e
job in the workflow to depend on the verify job by adding a needs relationship,
so e2e only starts after verify succeeds; keep the rest of the e2e steps
unchanged and reference the e2e and verify job names when locating the workflow
block.
In `@apps/hackathon-lp-2026/components/sponsors.tsx`:
- Around line 88-92: The SponsorCard props currently infer sponsor from (typeof
SPONSOR_LOGOS)[0], which is indirect and harder to reuse. Define a named Sponsor
interface in sponsors.tsx with the sponsor fields, update SponsorCard to accept
sponsor: Sponsor, and use that interface anywhere the sponsor shape is needed so
the type is explicit and reusable.
- Line 131: The sponsor image usage in the relevant component still relies on
plain <img>, which triggers the LCP/bandwidth lint warning. Update the image
rendering in sponsors.tsx to use next/image where appropriate, and make sure the
static-export setup is handled correctly by either setting images.unoptimized:
true or using a compatible custom loader. Also review the other img occurrence
mentioned in the same component and apply the same choice consistently.
In `@apps/hackathon-lp-2026/e2e/home.spec.ts`:
- Around line 7-13: The console error filter in the e2e home spec is too broad
and can hide real asset regressions. Tighten the guard inside the
page.on("console") handler so it only ignores the specific benign probe you
intend to skip (for example, the favicon request), rather than any msg.text()
containing “Failed to load resource”; keep failing on broken static assets while
still allowing harmless browser noise. Use the existing consoleErrors collection
and the page.on("console") logic as the place to update.
In `@apps/hackathon-lp-2026/test/use-in-view.test.tsx`:
- Around line 43-52: Add a test in use-in-view.test.tsx to cover the once: false
reset path in useInView, since the current Probe-based tests only verify the
latch-to-true behavior. Update the existing test suite near the latches isInView
test to simulate an intersecting callback followed by a non-intersecting one,
and assert that the hook resets data-inview back to false when once is false.
Use the existing Probe component, lastCallback, and useInView-related test setup
to keep the coverage aligned with hooks/use-in-view.tsx.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d69ac340-199c-4b97-b815-53a8415fcc10
⛔ Files ignored due to path filters (1)
apps/hackathon-lp-2026/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (106)
.github/workflows/ci-hackathon-lp-2026.ymlapps/hackathon-lp-2026/.gitignoreapps/hackathon-lp-2026/.prettierignoreapps/hackathon-lp-2026/.prettierrc.jsonapps/hackathon-lp-2026/README.mdapps/hackathon-lp-2026/app/globals.cssapps/hackathon-lp-2026/app/layout.tsxapps/hackathon-lp-2026/components/about.tsxapps/hackathon-lp-2026/components/circuit-background.tsxapps/hackathon-lp-2026/components/entry.tsxapps/hackathon-lp-2026/components/faq.tsxapps/hackathon-lp-2026/components/final-cta.tsxapps/hackathon-lp-2026/components/footer.tsxapps/hackathon-lp-2026/components/hero.tsxapps/hackathon-lp-2026/components/highlights.tsxapps/hackathon-lp-2026/components/judges.tsxapps/hackathon-lp-2026/components/multi-chain.tsxapps/hackathon-lp-2026/components/navigation.tsxapps/hackathon-lp-2026/components/nemtus-info.tsxapps/hackathon-lp-2026/components/participation-flow.tsxapps/hackathon-lp-2026/components/prizes.tsxapps/hackathon-lp-2026/components/results.tsxapps/hackathon-lp-2026/components/schedule.tsxapps/hackathon-lp-2026/components/sponsors.tsxapps/hackathon-lp-2026/components/theme-provider.tsxapps/hackathon-lp-2026/components/themes.tsxapps/hackathon-lp-2026/components/ui/accordion.tsxapps/hackathon-lp-2026/components/ui/alert-dialog.tsxapps/hackathon-lp-2026/components/ui/alert.tsxapps/hackathon-lp-2026/components/ui/aspect-ratio.tsxapps/hackathon-lp-2026/components/ui/avatar.tsxapps/hackathon-lp-2026/components/ui/badge.tsxapps/hackathon-lp-2026/components/ui/breadcrumb.tsxapps/hackathon-lp-2026/components/ui/button-group.tsxapps/hackathon-lp-2026/components/ui/button.tsxapps/hackathon-lp-2026/components/ui/calendar.tsxapps/hackathon-lp-2026/components/ui/card.tsxapps/hackathon-lp-2026/components/ui/carousel.tsxapps/hackathon-lp-2026/components/ui/chart.tsxapps/hackathon-lp-2026/components/ui/checkbox.tsxapps/hackathon-lp-2026/components/ui/collapsible.tsxapps/hackathon-lp-2026/components/ui/command.tsxapps/hackathon-lp-2026/components/ui/context-menu.tsxapps/hackathon-lp-2026/components/ui/dialog.tsxapps/hackathon-lp-2026/components/ui/drawer.tsxapps/hackathon-lp-2026/components/ui/dropdown-menu.tsxapps/hackathon-lp-2026/components/ui/empty.tsxapps/hackathon-lp-2026/components/ui/field.tsxapps/hackathon-lp-2026/components/ui/form.tsxapps/hackathon-lp-2026/components/ui/hover-card.tsxapps/hackathon-lp-2026/components/ui/input-group.tsxapps/hackathon-lp-2026/components/ui/input-otp.tsxapps/hackathon-lp-2026/components/ui/input.tsxapps/hackathon-lp-2026/components/ui/item.tsxapps/hackathon-lp-2026/components/ui/kbd.tsxapps/hackathon-lp-2026/components/ui/label.tsxapps/hackathon-lp-2026/components/ui/menubar.tsxapps/hackathon-lp-2026/components/ui/navigation-menu.tsxapps/hackathon-lp-2026/components/ui/pagination.tsxapps/hackathon-lp-2026/components/ui/popover.tsxapps/hackathon-lp-2026/components/ui/progress.tsxapps/hackathon-lp-2026/components/ui/radio-group.tsxapps/hackathon-lp-2026/components/ui/resizable.tsxapps/hackathon-lp-2026/components/ui/scroll-area.tsxapps/hackathon-lp-2026/components/ui/select.tsxapps/hackathon-lp-2026/components/ui/separator.tsxapps/hackathon-lp-2026/components/ui/sheet.tsxapps/hackathon-lp-2026/components/ui/sidebar.tsxapps/hackathon-lp-2026/components/ui/skeleton.tsxapps/hackathon-lp-2026/components/ui/slider.tsxapps/hackathon-lp-2026/components/ui/sonner.tsxapps/hackathon-lp-2026/components/ui/spinner.tsxapps/hackathon-lp-2026/components/ui/switch.tsxapps/hackathon-lp-2026/components/ui/table.tsxapps/hackathon-lp-2026/components/ui/tabs.tsxapps/hackathon-lp-2026/components/ui/textarea.tsxapps/hackathon-lp-2026/components/ui/toast.tsxapps/hackathon-lp-2026/components/ui/toaster.tsxapps/hackathon-lp-2026/components/ui/toggle-group.tsxapps/hackathon-lp-2026/components/ui/toggle.tsxapps/hackathon-lp-2026/components/ui/tooltip.tsxapps/hackathon-lp-2026/components/ui/use-mobile.tsxapps/hackathon-lp-2026/components/ui/use-toast.tsapps/hackathon-lp-2026/e2e/home.spec.tsapps/hackathon-lp-2026/eslint.config.mjsapps/hackathon-lp-2026/hooks/use-in-view.tsxapps/hackathon-lp-2026/hooks/use-mobile.tsapps/hackathon-lp-2026/hooks/use-toast.tsapps/hackathon-lp-2026/lib/constants.tsapps/hackathon-lp-2026/lib/utils.tsapps/hackathon-lp-2026/next.config.mjsapps/hackathon-lp-2026/package.jsonapps/hackathon-lp-2026/playwright.config.tsapps/hackathon-lp-2026/postcss.config.mjsapps/hackathon-lp-2026/styles/globals.cssapps/hackathon-lp-2026/test/constants.test.tsapps/hackathon-lp-2026/test/entry-open.test.tsxapps/hackathon-lp-2026/test/entry.test.tsxapps/hackathon-lp-2026/test/faq.test.tsxapps/hackathon-lp-2026/test/use-in-view.test.tsxapps/hackathon-lp-2026/test/utils.test.tsapps/hackathon-lp-2026/tsconfig.jsonapps/hackathon-lp-2026/vitest.config.tsapps/hackathon-lp-2026/vitest.setup.tsapps/hackathon-lp-2026/wrangler.tomlsocket.yml
✅ Files skipped from review due to trivial changes (11)
- apps/hackathon-lp-2026/.prettierignore
- apps/hackathon-lp-2026/test/utils.test.ts
- apps/hackathon-lp-2026/.gitignore
- apps/hackathon-lp-2026/lib/constants.ts
- apps/hackathon-lp-2026/.prettierrc.json
- apps/hackathon-lp-2026/components/ui/input.tsx
- apps/hackathon-lp-2026/postcss.config.mjs
- apps/hackathon-lp-2026/next.config.mjs
- apps/hackathon-lp-2026/README.md
- apps/hackathon-lp-2026/vitest.config.ts
- apps/hackathon-lp-2026/components/ui/button-group.tsx
🚧 Files skipped from review as they are similar to previous changes (76)
- apps/hackathon-lp-2026/components/ui/toggle.tsx
- apps/hackathon-lp-2026/components/ui/checkbox.tsx
- apps/hackathon-lp-2026/components/ui/textarea.tsx
- apps/hackathon-lp-2026/components/theme-provider.tsx
- apps/hackathon-lp-2026/components/participation-flow.tsx
- apps/hackathon-lp-2026/hooks/use-mobile.ts
- apps/hackathon-lp-2026/components/ui/toaster.tsx
- apps/hackathon-lp-2026/components/ui/sonner.tsx
- apps/hackathon-lp-2026/components/ui/collapsible.tsx
- apps/hackathon-lp-2026/components/nemtus-info.tsx
- apps/hackathon-lp-2026/components/ui/aspect-ratio.tsx
- apps/hackathon-lp-2026/lib/utils.ts
- apps/hackathon-lp-2026/components/ui/radio-group.tsx
- apps/hackathon-lp-2026/tsconfig.json
- apps/hackathon-lp-2026/components/ui/avatar.tsx
- apps/hackathon-lp-2026/components/ui/skeleton.tsx
- apps/hackathon-lp-2026/components/ui/kbd.tsx
- apps/hackathon-lp-2026/components/ui/label.tsx
- apps/hackathon-lp-2026/components/ui/switch.tsx
- apps/hackathon-lp-2026/components/ui/tabs.tsx
- apps/hackathon-lp-2026/components/ui/separator.tsx
- apps/hackathon-lp-2026/components/ui/spinner.tsx
- apps/hackathon-lp-2026/components/results.tsx
- apps/hackathon-lp-2026/components/themes.tsx
- apps/hackathon-lp-2026/components/ui/button.tsx
- apps/hackathon-lp-2026/components/ui/progress.tsx
- apps/hackathon-lp-2026/components/ui/resizable.tsx
- apps/hackathon-lp-2026/styles/globals.css
- apps/hackathon-lp-2026/components/prizes.tsx
- apps/hackathon-lp-2026/components/ui/alert.tsx
- apps/hackathon-lp-2026/components/schedule.tsx
- apps/hackathon-lp-2026/components/ui/accordion.tsx
- apps/hackathon-lp-2026/components/highlights.tsx
- apps/hackathon-lp-2026/components/ui/slider.tsx
- apps/hackathon-lp-2026/components/ui/input-otp.tsx
- apps/hackathon-lp-2026/app/layout.tsx
- apps/hackathon-lp-2026/components/ui/alert-dialog.tsx
- apps/hackathon-lp-2026/components/ui/toggle-group.tsx
- apps/hackathon-lp-2026/components/ui/item.tsx
- apps/hackathon-lp-2026/components/ui/breadcrumb.tsx
- apps/hackathon-lp-2026/components/ui/scroll-area.tsx
- apps/hackathon-lp-2026/components/ui/use-mobile.tsx
- apps/hackathon-lp-2026/components/ui/command.tsx
- apps/hackathon-lp-2026/components/about.tsx
- apps/hackathon-lp-2026/components/navigation.tsx
- apps/hackathon-lp-2026/components/ui/drawer.tsx
- apps/hackathon-lp-2026/components/faq.tsx
- apps/hackathon-lp-2026/components/judges.tsx
- apps/hackathon-lp-2026/components/ui/navigation-menu.tsx
- apps/hackathon-lp-2026/components/ui/table.tsx
- apps/hackathon-lp-2026/components/ui/badge.tsx
- apps/hackathon-lp-2026/components/final-cta.tsx
- apps/hackathon-lp-2026/components/ui/hover-card.tsx
- apps/hackathon-lp-2026/components/ui/sheet.tsx
- apps/hackathon-lp-2026/components/ui/pagination.tsx
- apps/hackathon-lp-2026/components/multi-chain.tsx
- apps/hackathon-lp-2026/components/ui/use-toast.ts
- apps/hackathon-lp-2026/components/footer.tsx
- apps/hackathon-lp-2026/components/ui/toast.tsx
- apps/hackathon-lp-2026/components/ui/carousel.tsx
- apps/hackathon-lp-2026/components/ui/chart.tsx
- apps/hackathon-lp-2026/components/ui/popover.tsx
- apps/hackathon-lp-2026/components/ui/dialog.tsx
- apps/hackathon-lp-2026/components/ui/calendar.tsx
- apps/hackathon-lp-2026/components/ui/select.tsx
- apps/hackathon-lp-2026/components/ui/card.tsx
- apps/hackathon-lp-2026/components/hero.tsx
- apps/hackathon-lp-2026/hooks/use-toast.ts
- apps/hackathon-lp-2026/components/ui/dropdown-menu.tsx
- apps/hackathon-lp-2026/components/ui/menubar.tsx
- apps/hackathon-lp-2026/components/ui/context-menu.tsx
- apps/hackathon-lp-2026/components/ui/input-group.tsx
- apps/hackathon-lp-2026/components/ui/tooltip.tsx
- apps/hackathon-lp-2026/components/entry.tsx
- apps/hackathon-lp-2026/components/ui/field.tsx
- apps/hackathon-lp-2026/components/ui/sidebar.tsx
| name: lint / format / types / build / unit | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Set persist-credentials: false on checkout.
Both jobs check out the repo without persist-credentials: false, leaving the GITHUB_TOKEN in the local git config for the remainder of the job. Since pnpm install runs with scripts enabled (per .npmrc ignore-scripts=false) against third-party packages, a malicious/compromised transitive dependency's postinstall script could read and exfiltrate the token. permissions: contents: read limits blast radius but doesn't prevent local credential exposure to spawned processes.
🔒 Suggested fix
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
+ with:
+ persist-credentials: falseApply to both checkout steps (lines 39 and 68).
Also applies to: 68-68
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 39-39: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/ci-hackathon-lp-2026.yml at line 39, Both jobs use
actions/checkout without disabling persisted Git credentials, which leaves the
GITHUB_TOKEN available to later processes in the job. Update each checkout step
in ci-hackathon-lp-2026.yml to set persist-credentials to false on the
actions/checkout invocation so the token is not written to local git config.
Make the change in both checkout usages, keeping the rest of the job behavior
unchanged.
Source: Linters/SAST tools
Summary
Adds the 2026 hackathon LP to the monorepo, hosted on Cloudflare Workers like the other years — but this one is a v0-generated Next.js 16 app-router app (React 19, Tailwind v4, shadcn/ui, framer-motion; pnpm), so it uses a build step + static export rather than a plain
public/folder.Approach
next/headers, or dynamic rendering), sonext buildwithoutput: 'export'emits./out, served by an assets-only Worker — same Workers Builds + Static Assets model as the other LP years. (OpenNext not needed.)Changes (all under
apps/hackathon-lp-2026/)app/,components/,hooks/,lib/,public/,styles/, configs).next.config.mjs: addoutput: 'export'(keepsimages.unoptimized,ignoreBuildErrors).wrangler.toml: assets-only Workernemtus-hackathon-lp-2026,directory = "./out", custom domainhackathon-2026.nemtus.com(the aggregator already links there). Header comment documents the Workers Builds dashboard settings (Build commandpnpm build)..npmrcignore-scripts=falseto override the inherited repo-root hardening for this standalone pnpm app.framer-motion@12.23.24alongsidemotion-dom@12.42.2, which dropped theactiveAnimationsexport framer-motion imports → build failure. Pinnedmotion-domto12.23.23viapnpm.overrides.Verification
pnpm install && pnpm buildsucceeds;/and/_not-foundprerender as static.out/hasindex.html,404.html,_next/…(215 files); largest asset 1.78 MiB (< the 25 MiB Workers limit).wrangler deploy --dry-runreadsout/cleanly.node_modules,.next,out,next-env.d.ts) are gitignored (not committed).Cloudflare dashboard (to do, like the other years)
Create Worker
nemtus-hackathon-lp-2026, connectnemtus/apps, Root directoryapps/hackathon-lp-2026, Build commandpnpm build, Deploy commandnpx wrangler deploy, Build watch pathsapps/hackathon-lp-2026/*, production branchmain, Preview URLs on. The custom domain attaches via theroutesentry on deploy.Notes
apps/*frontends stay standalone.@vercel/analyticsis a no-op off Vercel; left in place (optional to remove later).@opennextjs/cloudflareinstead of static export.🤖 Generated with Claude Code
Summary by CodeRabbit