Skip to content

init hacker news webview#1

Merged
seokju-na merged 3 commits into
mainfrom
webview/hacker-news-init
Jun 14, 2026
Merged

init hacker news webview#1
seokju-na merged 3 commits into
mainfrom
webview/hacker-news-init

Conversation

@seokju-na

@seokju-na seokju-na commented Jun 14, 2026

Copy link
Copy Markdown
Member

Summary by cubic

Initial Hacker News–style webview added with SSR + prerendering, built in React and TanStack Router. Also sets up a Yarn v4 workspace and CI for linting, type checks, and builds.

  • New Features

    • New webviews/hacker-news app: feed, post detail, and profiles with responsive layout, light/dark theme, vote toggles, and collapsible comments.
    • SSR + static prerender (entry-server.tsx and scripts/prerender.mjs) to emit HTML per route.
    • Routing via @tanstack/react-router with generated route tree; Vite + TailwindCSS UI; variable Inter and JetBrains Mono fonts.
    • Mock data for posts, users, and comments; simple state for theme/votes.
  • Dependencies

    • Monorepo tooling: Yarn v4 workspaces, root tsconfig.json, biome.json, .yarnrc.yml, and Node 24.15.0 via mise.toml.
    • GitHub Actions CI: composite Node setup, cached Yarn, yarn check, typecheck, and build.
    • Added packages: react, react-dom, @tanstack/react-router, @tanstack/router-plugin, vite, @vitejs/plugin-react, tailwindcss, @tailwindcss/vite, typescript.

Written for commit d9ba2bf. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 issues found across 41 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="webviews/hacker-news/src/components/LeftSidebar.tsx">

<violation number="1" location="webviews/hacker-news/src/components/LeftSidebar.tsx:34">
P2: `saved` button has no onClick or routing — completely inert. A button that does nothing is dead UI that misleads users.</violation>
</file>

<file name="webviews/hacker-news/src/components/Composer.tsx">

<violation number="1" location="webviews/hacker-news/src/components/Composer.tsx:13">
P1: onSubmit silently discards all input: form fields are uncontrolled with no value/onChange/ref and the submit handler calls close() without reading title or body.</violation>
</file>

<file name="webviews/hacker-news/src/routes/index.tsx">

<violation number="1" location="webviews/hacker-news/src/routes/index.tsx:126">
P2: Mobile search field is not synchronized with URL query after mount. This can show stale text that no longer matches active feed filtering.</violation>
</file>

<file name=".github/workflows/ci.yaml">

<violation number="1" location=".github/workflows/ci.yaml:10">
P2: `github.event.head_commit` is undefined for `pull_request` events. The `contains()` call always returns `false`, so the condition always evaluates to `true` and never skips the job.</violation>
</file>

<file name="webviews/hacker-news/src/components/RightRail.tsx">

<violation number="1" location="webviews/hacker-news/src/components/RightRail.tsx:59">
P2: Trending tag links use `search={{ tag }}`, which replaces all existing search params. The "create post" link in the same component correctly uses `search={prev => ({ ...prev, compose: true })}` to preserve params. Clicking a tag will reset `sort`, `q`, and `compose` state unexpectedly.</violation>
</file>

<file name="webviews/hacker-news/src/components/TagBadge.tsx">

<violation number="1" location="webviews/hacker-news/src/components/TagBadge.tsx:10">
P1: `search={{ tag }}` replaces all existing search params. Use function form to preserve other params like `sort` and `q`, matching the pattern used throughout the codebase.</violation>
</file>

<file name="webviews/hacker-news/src/components/MobileNav.tsx">

<violation number="1" location="webviews/hacker-news/src/components/MobileNav.tsx:17">
P2: Home link does not reset `sort` param, so tapping "home" preserves the current sort (e.g., `sort=top` / popular) instead of returning to the default hot-sorted feed. Desktop sidebar home uses `search={{}}` which correctly resets all params.</violation>
</file>

Note: This PR contains a large number of files. Free-tier reviews are limited to 40 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review. Paid plans can review more files.
You're on the cubic free plan with 19 free PR reviews remaining this month. Upgrade for unlimited reviews.

Re-trigger cubic


return (
<form
onSubmit={e => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: onSubmit silently discards all input: form fields are uncontrolled with no value/onChange/ref and the submit handler calls close() without reading title or body.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/components/Composer.tsx, line 13:

<comment>onSubmit silently discards all input: form fields are uncontrolled with no value/onChange/ref and the submit handler calls close() without reading title or body.</comment>

<file context>
@@ -0,0 +1,44 @@
+
+  return (
+    <form
+      onSubmit={e => {
+        e.preventDefault();
+        close();
</file context>

return (
<Link
to="/"
search={{ tag }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: search={{ tag }} replaces all existing search params. Use function form to preserve other params like sort and q, matching the pattern used throughout the codebase.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/components/TagBadge.tsx, line 10:

<comment>`search={{ tag }}` replaces all existing search params. Use function form to preserve other params like `sort` and `q`, matching the pattern used throughout the codebase.</comment>

<file context>
@@ -0,0 +1,19 @@
+  return (
+    <Link
+      to="/"
+      search={{ tag }}
+      className={cn(
+        'rounded-sm border border-border-1 bg-bg-3 px-1.5 py-px text-[10.5px] text-fg-2 transition-colors hover:border-accent hover:text-accent',
</file context>

>
✦ popular
</Link>
<button type="button" className={cn(rowBase, idleRow, 'cursor-pointer')}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: saved button has no onClick or routing — completely inert. A button that does nothing is dead UI that misleads users.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/components/LeftSidebar.tsx, line 34:

<comment>`saved` button has no onClick or routing — completely inert. A button that does nothing is dead UI that misleads users.</comment>

<file context>
@@ -0,0 +1,61 @@
+        >
+          ✦ popular
+        </Link>
+        <button type="button" className={cn(rowBase, idleRow, 'cursor-pointer')}>
+          ▣ saved
+        </button>
</file context>


function MobileFeedControls({ activeTag, q }: { activeTag?: TagId; q?: string }) {
const navigate = useNavigate();
const [value, setValue] = useState(q ?? '');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Mobile search field is not synchronized with URL query after mount. This can show stale text that no longer matches active feed filtering.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/routes/index.tsx, line 126:

<comment>Mobile search field is not synchronized with URL query after mount. This can show stale text that no longer matches active feed filtering.</comment>

<file context>
@@ -0,0 +1,166 @@
+
+function MobileFeedControls({ activeTag, q }: { activeTag?: TagId; q?: string }) {
+  const navigate = useNavigate();
+  const [value, setValue] = useState(q ?? '');
+
+  return (
</file context>

Comment thread .github/workflows/ci.yaml
jobs:
check:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: github.event.head_commit is undefined for pull_request events. The contains() call always returns false, so the condition always evaluates to true and never skips the job.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yaml, line 10:

<comment>`github.event.head_commit` is undefined for `pull_request` events. The `contains()` call always returns `false`, so the condition always evaluates to `true` and never skips the job.</comment>

<file context>
@@ -0,0 +1,31 @@
+jobs:
+  check:
+    runs-on: ubuntu-latest
+    if: "!contains(github.event.head_commit.message, '[skip ci]')"
+    steps:
+      - name: Git checkout
</file context>

<Link
key={tag}
to="/"
search={{ tag }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Trending tag links use search={{ tag }}, which replaces all existing search params. The "create post" link in the same component correctly uses search={prev => ({ ...prev, compose: true })} to preserve params. Clicking a tag will reset sort, q, and compose state unexpectedly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/components/RightRail.tsx, line 59:

<comment>Trending tag links use `search={{ tag }}`, which replaces all existing search params. The "create post" link in the same component correctly uses `search={prev => ({ ...prev, compose: true })}` to preserve params. Clicking a tag will reset `sort`, `q`, and `compose` state unexpectedly.</comment>

<file context>
@@ -0,0 +1,69 @@
+            <Link
+              key={tag}
+              to="/"
+              search={{ tag }}
+              className="rounded-full border border-border-1 bg-bg-2 px-2.5 py-[3px] text-[11px] text-fg-2 transition-colors hover:border-accent hover:text-accent"
+            >
</file context>
Suggested change
search={{ tag }}
search={prev => ({ ...prev, tag })}

<nav className="flex flex-shrink-0 border-t border-border-1 bg-bg-1 pb-[env(safe-area-inset-bottom)] lg:hidden">
<Link
to="/"
search={prev => ({ ...prev, tag: undefined, q: undefined, compose: undefined })}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Home link does not reset sort param, so tapping "home" preserves the current sort (e.g., sort=top / popular) instead of returning to the default hot-sorted feed. Desktop sidebar home uses search={{}} which correctly resets all params.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At webviews/hacker-news/src/components/MobileNav.tsx, line 17:

<comment>Home link does not reset `sort` param, so tapping "home" preserves the current sort (e.g., `sort=top` / popular) instead of returning to the default hot-sorted feed. Desktop sidebar home uses `search={{}}` which correctly resets all params.</comment>

<file context>
@@ -0,0 +1,45 @@
+    <nav className="flex flex-shrink-0 border-t border-border-1 bg-bg-1 pb-[env(safe-area-inset-bottom)] lg:hidden">
+      <Link
+        to="/"
+        search={prev => ({ ...prev, tag: undefined, q: undefined, compose: undefined })}
+        className={cn(itemBase, isFeed ? 'text-accent' : 'text-fg-4')}
+      >
</file context>

@seokju-na seokju-na merged commit 3972dd5 into main Jun 14, 2026
3 checks passed
@seokju-na seokju-na deleted the webview/hacker-news-init branch June 14, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant