Skip to content

Rewrite landing around keep → share → see - #142

Merged
tsoumdoa merged 3 commits into
mainfrom
feat/landing-narrative-overhaul
Jul 29, 2026
Merged

Rewrite landing around keep → share → see#142
tsoumdoa merged 3 commits into
mainfrom
feat/landing-narrative-overhaul

Conversation

@tsoumdoa

@tsoumdoa tsoumdoa commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Reframe the LP from review-first to keep → share → see: personal clip library, one-click share, then DuckerWeb inspect/diff
  • Add restrained in-page copy/share demos that mirror Hopper Card UI (rings, tag chips, green-300 Shared badge)
  • Warm the page with product accents (green-300 CTAs, section labels, Shared badge) without leaving the dark theme
  • Brand once: header owns “Hopper Clip”; hero leads with the job headline
  • Demote DuckerWeb out of the hero; name it in the inspect beat with a direct link

Test plan

  • Open / signed out — brand only in header; hero is the job line + library preview
  • Try copy / share demos; confirm green-300 feedback matches card language
  • Inspect beat mentions DuckerWeb and links to /duckerweb
  • Diff visual stays dark (fits LP); spacing feels tight on mobile + desktop
  • Signed-in users still redirect to /ghcards

Lead with personal clip library, then frictionless share and DuckerWeb inspect/diff, with light in-page demos instead of the review-first case cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hopperclip Ready Ready Preview, Comment Jul 29, 2026 11:41am

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The landing route is redesigned around new clip-library and inspection visuals, with updated metadata, animated section content, copy/share interactions, calls to action, and the existing bottom fade integrated into the new composition.

Changes

Landing Page Redesign

Layer / File(s) Summary
Clip library demo
src/app/components/landing/clip-library-demo.tsx
Adds preview, copy, and share modes with featured-clip actions, temporary feedback state, and animated share messaging.
Inspection diff visual
src/app/components/landing/inspect-diff-visual.tsx
Adds an animated SVG showing wires, unmodified and modified components, an added panel, value nodes, and change-status badges.
Landing page composition
src/routes/index.tsx
Replaces the prior landing layout with Hero, personal, sharing, inspection, closing, and bottom-fade sections, and updates the page title metadata.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main landing-page rewrite and the new keep/share/inspect narrative.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/landing-narrative-overhaul

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 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 `@src/app/components/landing/clip-library-demo.tsx`:
- Around line 42-52: Update handleCopy and handleShare to store each mode’s
timeout handle, clear the existing handle before scheduling a replacement, and
retain the latest handle. Add unmount cleanup to clear any pending copied and
shared timers so stale callbacks cannot update state after the component is
removed.

In `@src/app/components/landing/inspect-diff-visual.tsx`:
- Around line 183-188: Update the animated motion.g group in the inspect-diff
visual so its existing translate(362, 128) positioning is preserved: wrap it in
a static SVG g carrying the translation, and move the animation props to the
inner motion.g. Keep the current animation behavior and wire endpoint offset
unchanged.
🪄 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 Plus

Run ID: 43798fe0-a50c-4bb8-b701-d11bad4a305f

📥 Commits

Reviewing files that changed from the base of the PR and between 8cf30e0 and 530ba32.

📒 Files selected for processing (3)
  • src/app/components/landing/clip-library-demo.tsx
  • src/app/components/landing/inspect-diff-visual.tsx
  • src/routes/index.tsx

Comment on lines +42 to +52
const handleCopy = (id: string) => {
setSharedId(null);
setCopiedId(id);
window.setTimeout(() => setCopiedId((cur) => (cur === id ? null : cur)), 1800);
};

const handleShare = (id: string) => {
setCopiedId(null);
setSharedId(id);
window.setTimeout(() => setSharedId((cur) => (cur === id ? null : cur)), 2800);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Prevent stale feedback timers from clearing a later action.

Clicking the same button again leaves its earlier timeout active, so it can clear the newer “copied”/“shared” feedback at the original deadline. Cancel and replace each mode’s existing timeout before scheduling a new one; also clear pending timers on unmount.

🤖 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 `@src/app/components/landing/clip-library-demo.tsx` around lines 42 - 52,
Update handleCopy and handleShare to store each mode’s timeout handle, clear the
existing handle before scheduling a replacement, and retain the latest handle.
Add unmount cleanup to clear any pending copied and shared timers so stale
callbacks cannot update state after the component is removed.

Comment on lines +183 to +188
<motion.g
transform="translate(362, 128)"
initial={{ opacity: 0, y: 6 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.75 }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate SVG elements that combine a transform attribute with Motion x/y transforms.
rg -n -U 'transform=.*\n(?:.*\n){0,8}(?:initial|whileInView)=\{\{[^}]*\b[xy]:' \
  src/app/components/landing/inspect-diff-visual.tsx

Repository: tsoumdoa/hopperclip

Length of output: 157


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target component and relevant package metadata without running repo code.
echo "== candidate file excerpt =="
sed -n '160,225p' src/app/components/landing/inspect-diff-visual.tsx

echo
echo "== motion/framer package versions from package manifests =="
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock bun.lockb; do
  if [ -f "$f" ]; then
    echo "-- $f --"
    if [ "$f" = "package.json" ]; then
      rg -n '"(framer-motion|motion|react-dom)"' "$f" -C 1 || true
    else
      rg -n '(framer-motion|motion)\W|/framer-motion@|/motion@' "$f" -C 1 | head -80 || true
    fi
  fi
done

echo
echo "== all transform+motion svg groups near each other =="
python3 - <<'PY'
from pathlib import Path
p=Path('src/app/components/landing/inspect-diff-visual.tsx')
text=p.read_text().splitlines()
for i,line in enumerate(text,1):
    if '<motion.g' in line.lower() or '<motion.path' in line.lower() or 'transform=' in line:
        if any('initial' in l or 'whileInView' in l or 'transform=' in l for l in text[max(1,i-12):i+12]):
            print(f"-- around line {i} --")
            for j in range(max(1,i-8), min(len(text),i+14)+1):
                print(f"{j:4}: {text[j-1]}")
            print()
PY

Repository: tsoumdoa/hopperclip

Length of output: 10863


🌐 Web query:

Motion docs f12 0.27.2 SVG transforms style transforms transform attribute

💡 Result:

In Motion (formerly Framer Motion), SVG transforms are handled specifically to overcome limitations of standard SVG behavior [1][2]. Key behaviors regarding SVG transforms, styles, and attributes in version 0.27.2 and the broader Motion 12+ ecosystem include: Transform Origins: By default, SVG elements apply transforms relative to the top-left corner of the viewBox [1][2]. Motion automatically changes this behavior for motion components to match CSS, making transforms relative to the element's center [1][2]. This is achieved by defaulting to transform-box: fill-box [1][3]. You can restore the default SVG behavior or customize it by explicitly setting the transformBox style (e.g., transformBox: "view-box") [1][2]. Styles vs. Attributes: - Motion generally prefers animating values via CSS styles (transform property) rather than the SVG transform attribute, as this provides better performance and consistent behavior across modern browsers [4][3]. - When animating properties like x, y, or scale on SVG elements, Motion components will default to using CSS transforms (translateX/translateY) [5]. - If you specifically need to animate positional attributes (like the x or y attributes of a or ), you should use the attr-prefixed props: attrX, attrY, and attrScale [1][6][5]. Recent Pipeline Unification: As of recent updates (part of the unified Motion architecture), SVG values that exist as valid CSS properties (such as fill, opacity, and others) are rendered as inline styles rather than presentation attributes [3]. This approach ensures deterministic specificity (inline styles take priority) and improves performance by avoiding attribute-mutation overhead [3]. For scenarios where you must animate the SVG transform attribute directly (e.g., complex strings or legacy compatibility), Motion does not provide a native shorthand for animating the raw string. You may need to use external parsing logic or utilize Motion's mix function to interpolate transform matrices manually before updating the attribute via a ref [7]. Top results: [1][2][3][5]

Citations:


Preserve the panel’s SVG translation while animating it.

Motion renders SVG y as a CSS transform, so this group loses the transform="translate(362, 128)" position during animation. Wrap the animated group in a static translated <g> so it keeps the wire endpoint offset.

Proposed fix
-				<motion.g
-					transform="translate(362, 128)"
+				<g transform="translate(362, 128)">
+					<motion.g
 					initial={{ opacity: 0, y: 4 }}
 					whileInView={{ opacity: 1, y: 0 }}
 					viewport={{ once: true }}
 					transition={{ duration: 0.5, delay: 0.75 }}
-				>
+					>
						...
-				</motion.g>
+					</motion.g>
+				</g>
🤖 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 `@src/app/components/landing/inspect-diff-visual.tsx` around lines 183 - 188,
Update the animated motion.g group in the inspect-diff visual so its existing
translate(362, 128) positioning is preserved: wrap it in a static SVG g carrying
the translation, and move the animation props to the inner motion.g. Keep the
current animation behavior and wire endpoint offset unchanged.

Use green-300 Shared badge, tag chips, and matching CTAs so the landing feels closer to the product UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Let the header own the brand; hero leads with the job line instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tsoumdoa
tsoumdoa merged commit 88f0b6d into main Jul 29, 2026
3 checks passed
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