-
Notifications
You must be signed in to change notification settings - Fork 431
feat(web): add SEO-ready open source landing page #1980
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(web): add SEO-ready open source landing page #1980
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for hyprnote-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughRemoved a placeholder product opensource route and added a new standalone open-source landing route; updated the footer to include additional social links and icons. Metadata and multi-section UI for the new route were introduced. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎ Awaiting the start of a new Argos build… |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/routes/_view/product/opensource.tsx (2)
100-109: Use<Link>for internal navigation.This download link uses an
<a>tag with a full URL, but Line 477 uses<Link to="/product/local-ai">for internal navigation. For consistency and to enable client-side routing, use<Link>for internal routes.- <a - href="https://hyprnote.com/download" + <Link + to="/download" className={cn([ "inline-flex items-center justify-center px-8 py-3 text-base font-medium rounded-full", "border border-neutral-300 text-stone-600", "hover:bg-stone-50 transition-colors", ])} > Download for free - </a> + </Link>
467-476: Use<Link>for internal navigation (same issue as HeroSection).For consistency with Line 477-486 which correctly uses
<Link>, this download button should also use the<Link>component.- <a - href="https://hyprnote.com/download" + <Link + to="/download" className={cn([ "px-8 py-3 text-base font-medium rounded-full", "bg-linear-to-t from-stone-600 to-stone-500 text-white", "hover:scale-105 active:scale-95 transition-transform", ])} > Download for free - </a> + </Link>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/routes/_view/product/opensource.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/src/routes/_view/product/opensource.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Redirect rules - hyprnote
- GitHub Check: Header rules - hyprnote
- GitHub Check: Pages changed - hyprnote
- GitHub Check: ci (macos, macos-14)
- GitHub Check: fmt
🔇 Additional comments (6)
apps/web/src/routes/_view/product/opensource.tsx (6)
9-44: Comprehensive SEO metadata setup.The
head()configuration provides well-structured metadata including Open Graph, Twitter cards, and keywords. This is good for SEO discoverability.
46-69: Clean component composition.The main component structure is well-organized with consistent use of
SlashSeparatorbetween sections.
117-176: Well-structured feature cards.The grid layout with consistent card styling is clean and readable.
178-258: LGTM!External links are properly configured with
target="_blank"andrel="noopener noreferrer". The section structure is clean.
260-354: LGTM!The tech stack cards are well-organized and the external GitHub link is properly configured.
477-486: Correct use of<Link>for internal navigation.This is the correct pattern for internal routes. The other download links should follow this approach.
| <a | ||
| href="https://discord.gg/hyprnote" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="flex items-center gap-3 p-4 border border-neutral-200 rounded-lg bg-white hover:border-stone-400 transition-colors" | ||
| > | ||
| <Icon icon="mdi:discord" className="text-2xl text-stone-600" /> | ||
| <div> | ||
| <p className="font-medium text-stone-600">Discord</p> | ||
| <p className="text-sm text-neutral-500">Join the chat</p> | ||
| </div> | ||
| </a> | ||
| <a | ||
| href="https://twitter.com/hyprnote" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="flex items-center gap-3 p-4 border border-neutral-200 rounded-lg bg-white hover:border-stone-400 transition-colors" | ||
| > | ||
| <Icon icon="mdi:twitter" className="text-2xl text-stone-600" /> | ||
| <div> | ||
| <p className="font-medium text-stone-600">Twitter</p> | ||
| <p className="text-sm text-neutral-500">Follow updates</p> | ||
| </div> | ||
| </a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
[Skip the verification of external links via curl as they would require network access to external services]
# Instead, let's examine the actual code to ensure the links are correctly formatted
# and check if there are any other related configurations or patterns in the codebase
# 1. First, let's look at the full context of the file to understand the code
cat -n apps/web/src/routes/_view/product/opensource.tsx | sed -n '420,450p'Repository: fastrepl/hyprnote
Length of output: 1644
🏁 Script executed:
#!/bin/bash
# Search for references to discord.gg or twitter.com in the codebase
echo "=== Searching for Discord references ==="
rg "discord\.gg|discord" -i --type=ts --type=tsx -C2
echo ""
echo "=== Searching for Twitter/X references ==="
rg "twitter\.com|@hyprnote" -i --type=ts --type=tsx -C2
echo ""
echo "=== Checking for any link validation or verification utilities ==="
fd -e ts -e tsx | xargs rg -l "link|href|url" | head -10Repository: fastrepl/hyprnote
Length of output: 651
🏁 Script executed:
#!/bin/bash
# Search for configuration files or environment variables
echo "=== Checking for config files ==="
fd -e env -e config -e json -e yaml -e yml | head -20
echo ""
echo "=== Looking for references to 'hyprnote' across all files ==="
rg "hyprnote" -C2 --type=ts --type=json
echo ""
echo "=== Checking the full opensource section for context ==="
cat -n apps/web/src/routes/_view/product/opensource.tsx | sed -n '356,452p'Repository: fastrepl/hyprnote
Length of output: 50374
Fix Twitter handle inconsistency in social media links.
The Discord invite link appears correct and consistent across the codebase. However, the Twitter handle is inconsistent: the opensource.tsx file uses @hyprnote, while other files throughout the codebase reference @tryhyprnote (see apps/web/src/routes/__root.tsx, apps/web/src/routes/x.tsx, and apps/web/src/routes/_view/company-handbook/-components.tsx). Update line 437 from https://twitter.com/hyprnote to https://twitter.com/tryhyprnote to match the canonical handle used elsewhere.
🤖 Prompt for AI Agents
In apps/web/src/routes/_view/product/opensource.tsx around lines 424 to 447, the
Twitter link uses the inconsistent handle https://twitter.com/hyprnote; update
the href on line 437 to the canonical handle https://twitter.com/tryhyprnote so
it matches other files (apps/web/src/routes/__root.tsx,
apps/web/src/routes/x.tsx,
apps/web/src/routes/_view/company-handbook/-components.tsx) and ensure target,
rel and className remain unchanged.
cd99174 to
cb527d5
Compare
- Add comprehensive meta tags for SEO (title, description, og:*, twitter:*) - Add hero section with clear value proposition - Add 'Why open source matters' section with key benefits - Integrate GitHubOpenSource component for community showcase - Add transparency section highlighting auditable codebase - Add tech stack section showcasing Rust, Tauri, React, Whisper, LLMs - Add community contribution section with links to GitHub, Discord, Twitter - Add CTA section with download and learn more links - Follow existing design patterns from other product pages Co-Authored-By: john@hyprnote.com <john@hyprnote.com>
35d7f7b to
d434cca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
apps/web/src/routes/_view/opensource.tsx (1)
411-447: Align Twitter handle with canonical account used elsewhere.This card links to
https://twitter.com/hyprnote, but prior review comments noted that other parts of the app (e.g.,/xroute and company-handbook components) consistently link tohttps://twitter.com/tryhyprnote. For consistency and to avoid sending users to the wrong account, update the href here to the canonical handle.Proposed change:
- <a - href="https://twitter.com/hyprnote" + <a + href="https://twitter.com/tryhyprnote" target="_blank" rel="noopener noreferrer" className="flex items-center gap-3 p-4 border border-neutral-200 rounded-lg bg-white hover:border-stone-400 transition-colors" >
🧹 Nitpick comments (1)
apps/web/src/routes/_view/opensource.tsx (1)
13-42: Optional: consider adding og:image and twitter:image for richer link previews.The head() meta includes title, description, og:type, og:url, and twitter:card/title/description, but no
og:imageortwitter:image. If other marketing/product pages define per‑page preview images, consider adding those here too for consistent rich previews when/opensourceis shared.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
apps/web/src/routeTree.gen.tsis excluded by!**/*.gen.ts
📒 Files selected for processing (3)
apps/web/src/components/footer.tsx(7 hunks)apps/web/src/routes/_view/opensource.tsx(1 hunks)apps/web/src/routes/_view/product/opensource.tsx(0 hunks)
💤 Files with no reviewable changes (1)
- apps/web/src/routes/_view/product/opensource.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, usecn(import from@hypr/utils). It is similar toclsx. Always pass an array and split by logical grouping.
Usemotion/reactinstead offramer-motion.
Files:
apps/web/src/routes/_view/opensource.tsxapps/web/src/components/footer.tsx
🧬 Code graph analysis (1)
apps/web/src/routes/_view/opensource.tsx (3)
apps/web/src/components/slash-separator.tsx (1)
SlashSeparator(1-8)apps/web/src/components/github-open-source.tsx (1)
GitHubOpenSource(309-534)packages/utils/src/cn.ts (1)
cn(20-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: fmt
- GitHub Check: ci (macos, macos-14)
🔇 Additional comments (2)
apps/web/src/components/footer.tsx (1)
2-2: Footer navigation and social icon updates look good; just confirm new routes exist.The added icons and inline-flex styling for external links are consistent and accessible, and the new “Press Kit” (
to="/press-kit") and “Open Source” (to="/opensource") entries align with the rest of the footer. Please just double‑check that these routes are actually registered and that/opensourcecorrectly resolves to the new_view/opensourceroute in your router config so users don’t hit 404s.Also applies to: 195-207, 213-270
apps/web/src/routes/_view/opensource.tsx (1)
271-338: Ensuresimple-icons:tauriand other Iconify glyphs render correctly.The TechStackSection uses several Iconify icons, including
"simple-icons:tauri", which some icon sets don’t include by default. Please run the web app locally and visually confirm that all icons (Rust, Tauri, React, Whisper, Local LLMs, SQLite) load correctly with no missing‑glyph boxes or console errors.
| { title: "Open Source - Hyprnote" }, | ||
| { | ||
| name: "description", | ||
| content: | ||
| "Hyprnote is fully open source under GPL-3.0. Inspect every line of code, contribute to development, and build on a transparent foundation. No black boxes, no hidden data collection.", | ||
| }, | ||
| { property: "og:title", content: "Open Source - Hyprnote" }, | ||
| { | ||
| property: "og:description", | ||
| content: | ||
| "AI-powered meeting notes built in the open. Fully auditable codebase, community-driven development, and complete transparency. Join thousands of developers building the future of private meeting notes.", | ||
| }, | ||
| { property: "og:type", content: "website" }, | ||
| { | ||
| property: "og:url", | ||
| content: "https://hyprnote.com/opensource", | ||
| }, | ||
| { name: "twitter:card", content: "summary_large_image" }, | ||
| { name: "twitter:title", content: "Open Source - Hyprnote" }, | ||
| { | ||
| name: "twitter:description", | ||
| content: | ||
| "AI-powered meeting notes built in the open. Fully auditable codebase and community-driven development.", | ||
| }, | ||
| { | ||
| name: "keywords", | ||
| content: | ||
| "open source, meeting notes, AI transcription, privacy, GPL-3.0, Rust, Tauri, local AI, whisper, llm", | ||
| }, | ||
| ], | ||
| }), | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== License files (to verify GPL-3.0) ==="
fd -a '^LICENSE' . --type f || true
echo
echo "=== First 50 lines of LICENSE (if present) ==="
if [ -f "LICENSE" ]; then
head -50 LICENSE
else
echo "LICENSE file not found at root"
fi
echo
echo "=== Look for GPL-3.0 mentions in code/config ==="
rg -n "GPL-3\.0" -S --max-count 20 || true
echo
echo "=== Check analytics plugin location and implementation ==="
find . -path "*/analytics/src/lib.rs" -o -path "*/analytics/src/lib.ts" 2>/dev/null | head -5 || echo "Not found via find"
echo
echo "=== Look for telemetry/analytics references in codebase ==="
rg -n "opt-in|telemetry|analytics" -S --type ts --type tsx --max-count 30 | head -30 || trueRepository: fastrepl/hyprnote
Length of output: 4376
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check route configuration for opensource route ==="
fd -name "opensource.tsx" -type f | head -5
echo
echo "=== Inspect the full opensource.tsx file ==="
if [ -f "apps/web/src/routes/_view/opensource.tsx" ]; then
wc -l "apps/web/src/routes/_view/opensource.tsx"
echo "--- File content (first 100 lines) ---"
head -100 "apps/web/src/routes/_view/opensource.tsx"
fiRepository: fastrepl/hyprnote
Length of output: 363
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check for thousands/users metrics ==="
rg "thousands|metrics|users" apps/web/src/routes/_view/opensource.tsx -A 2 -B 2 || true
echo
echo "=== Look for canonical URL handling in routing ==="
rg -n "canonical|og:url" apps/web/src --type ts --type tsx --max-count 20 || true
echo
echo "=== Check footer/navigation for opensource link ==="
rg -n "opensource" apps/web/src --type tsx --max-count 30 | grep -i "link\|href\|to" || trueRepository: fastrepl/hyprnote
Length of output: 1352
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Full opensource.tsx file ==="
if [ -f "apps/web/src/routes/_view/opensource.tsx" ]; then
cat "apps/web/src/routes/_view/opensource.tsx"
fiRepository: fastrepl/hyprnote
Length of output: 19480
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Analytics implementation in crates/analytics/src/lib.rs ==="
if [ -f "crates/analytics/src/lib.rs" ]; then
head -150 "crates/analytics/src/lib.rs"
fi
echo
echo "=== Analytics implementation in plugins/analytics/src/lib.rs ==="
if [ -f "plugins/analytics/src/lib.rs" ]; then
head -150 "plugins/analytics/src/lib.rs"
fiRepository: fastrepl/hyprnote
Length of output: 7227
🏁 Script executed:
#!/bin/bash
set -euoripefail
echo "=== Search for telemetry opt-in configuration ==="
rg -i "opt.in|telemetry.*default|analytics.*enabled|data.collection" --max-count 30 || true
echo
echo "=== Search for analytics documentation or README ==="
find . -path "*analytics*" -name "README*" -o -path "*analytics*" -name "*.md" 2>/dev/null | head -10Repository: fastrepl/hyprnote
Length of output: 735
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check store.rs for telemetry default behavior ==="
if [ -f "plugins/analytics/src/store.rs" ]; then
cat "plugins/analytics/src/store.rs"
fi
echo
echo "=== Check for telemetry opt-in documentation ==="
rg -i "telemetry.*default|disabled.*default|analytics.*default|opt.in|opt.out" --max-count 20 || true
echo
echo "=== Check README or docs for telemetry explanation ==="
rg -i "telemetry" README* CONTRIBUTING* docs/ 2>/dev/null | head -20 || trueRepository: fastrepl/hyprnote
Length of output: 50373
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Search for any user/metrics documentation ==="
find . -name "*.md" -o -name "*.txt" | xargs rg -l "thousands|metrics|users" 2>/dev/null | head -10 || true
echo
echo "=== Check if telemetry storage persists disabled state ==="
if [ -f "plugins/analytics/src/store.rs" ]; then
head -50 "plugins/analytics/src/store.rs"
fiRepository: fastrepl/hyprnote
Length of output: 420
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Check telemetry_consent default value ==="
rg "telemetry_consent" --type ts --type tsx -B 2 -A 2 | head -40 || true
echo
echo "=== Check analytics.mdx documentation ==="
if [ -f "apps/web/content/docs/developers/0.analytics.mdx" ]; then
cat "apps/web/content/docs/developers/0.analytics.mdx"
fiRepository: fastrepl/hyprnote
Length of output: 499
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Search for default telemetry behavior in config/setup ==="
rg "telemetry.*true|analytics.*true|POSTHOG" -B 3 -A 3 --max-count 30 || true
echo
echo "=== Check if telemetry is sent by default when no opt-out ==="
rg -i "is_disabled|disabled.*false" plugins/analytics -A 5 -B 5 || trueRepository: fastrepl/hyprnote
Length of output: 9438
Correct the telemetry opt-in claim; it is actually opt-out (enabled by default).
The page states telemetry is "opt-in, minimal, and fully documented in the source code," but this contradicts the implementation:
packages/store/src/schema-internal.tssetstelemetry_consent: z.boolean().default(true)— telemetry is enabled by default, not opt-in.plugins/analytics/src/ext.rschecksif !self.is_disabled()with a default offalse, confirming telemetry sends unless explicitly disabled.- The analytics documentation (
apps/web/content/docs/developers/0.analytics.mdx) correctly states "You can opt-out," which implies opt-out behavior, not opt-in.
Update the page to reflect the actual opt-out model (e.g., "telemetry is enabled by default but you can disable it from the settings menu").
The "thousands of developers/users" claims in og:description and CTASection also lack supporting metrics in the codebase. Verify these numbers with your business/marketing team or soften the language.
🤖 Prompt for AI Agents
In apps/web/src/routes/_view/opensource.tsx around lines 13 to 44, the metadata
and copy incorrectly state telemetry is "opt-in" whereas the code enables
telemetry by default (opt-out); change the copy to state telemetry is enabled by
default and can be disabled in settings (or via user preferences), and update
the OG/CTA text to remove or soften the unsupported "thousands of
developers/users" claim—either confirm exact metrics with marketing/business or
use non-quantitative phrasing like "a growing community" or "community-driven."
feat(web): add SEO-ready open source landing page
Summary
Transforms the placeholder
/product/opensourcepage into a comprehensive SEO-ready landing page for Hyprnote's open source offering. The page follows existing design patterns from other product pages (local-ai, self-hosting) and includes:GitHubOpenSourcecomponent for community showcaseReview & Testing Checklist for Human
/product/opensourceand verify the page renders correctly on desktop and mobile viewportssimple-icons:tauriwhich may not be in the icon setdiscord.gg/hyprnote), Twitter (twitter.com/hyprnote), and GitHub analytics link work correctlyRecommended test plan:
pnpm -F web devand navigate tohttp://localhost:3000/product/opensourceNotes
dprint checkformattingLink to Devin run: https://app.devin.ai/sessions/5c1966ec426042afbec766d38f9b4453
Requested by: john@hyprnote.com (@ComputelessComputer)