Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 30 additions & 67 deletions app/components/cta.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,21 @@
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { FC, useState, FormEvent, startTransition, useActionState, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { formSchema } from '../utils/waitlist/schema';
import { submitWaitlistForm } from '../utils/waitlist/action';
import * as z from 'zod';

type FormValues = z.infer<typeof formSchema>;
import { FC } from 'react';
import { Chrome, Github } from 'lucide-react';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug — dead code left behind: The waitlist form was the only consumer of app/utils/waitlist/action.ts and app/utils/waitlist/schema.ts. These files are now completely unreferenced dead code and should be deleted.

Similarly, components/ui/form.tsx (a shadcn/ui form component) imports react-hook-form but is no longer imported anywhere in the codebase — also dead code.

import { CHROME_STORE_URL, GITHUB_REPO_URL } from '../utils/constant';

export const CTA: FC = () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cleanup — unused npm dependencies. With the waitlist form removed, these package.json dependencies are now only referenced by dead code and should be uninstalled:

  • @hookform/resolvers — was used only by the old cta.tsx form
  • react-hook-form — used only by dead cta.tsx form + dead components/ui/form.tsx
  • zod — used only by app/utils/waitlist/schema.ts (dead code)

Keeping unused dependencies inflates install time and bundle size.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

They will be reused later

const [email, setEmail] = useState<string>('');
const [submitted, setSubmitted] = useState<boolean>(false);
const [, formAction] = useActionState(submitWaitlistForm, { message: '' });

const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: { email: '' },
});

const formRef = useRef<HTMLFormElement>(null);

const handleSubmit = (e: FormEvent<HTMLFormElement>): void => {
e.preventDefault();
startTransition(() => {
formAction(new FormData(formRef.current!));
form.reset();
});
setSubmitted(true);
};

return (
<section className="py-36 px-6 md:px-12 relative overflow-hidden bg-ink" id="get-access">
<section
className="py-36 px-6 md:px-12 relative overflow-hidden bg-ink"
id="install"
>
<div className="absolute inset-0 grid-bg opacity-70" />
<div className="absolute top-0 left-0 right-0 h-px bg-edge" />

<div className="relative max-w-xl mx-auto text-center">
<div className="inline-flex items-center gap-2 border border-edge bg-ink2/80 px-4 py-1.5 mb-10 rounded-full">
<span className="w-1.5 h-1.5 rounded-full bg-amber animate-blink" />
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-blink" />
<span className="font-mono text-[10px] tracking-[0.18em] uppercase text-fog">
Early access open
Available now — free
</span>
</div>

Expand All @@ -49,45 +26,31 @@ export const CTA: FC = () => {
</h2>

<p className="text-[14px] text-mist mb-10 leading-relaxed font-body">
Be among the first to bring persistent memory to every AI you use.
Install the extension and bring persistent memory to every AI you use.
<br className="hidden md:block" />
No credit card. No setup fees.
Free, open-source, takes 30 seconds.
</p>

{!submitted ? (
<form
ref={formRef}
onSubmit={handleSubmit}
className="flex flex-col sm:flex-row gap-3 max-w-sm mx-auto"
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
<a
href={CHROME_STORE_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2.5 bg-amber text-white px-7 py-3.5 text-[12px] tracking-widest uppercase font-medium hover:bg-amber/90 transition-colors rounded-sm"
>
<input
type="email"
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="your@email.com"
className="flex-1 bg-ink2 border border-edge text-cream placeholder:text-fog px-4 py-3 text-[13px] font-body focus:outline-none focus:border-amber/40 transition-colors rounded-sm"
required
/>
<button
type="submit"
className="bg-amber text-white px-7 py-3 text-[11px] tracking-widest uppercase font-medium hover:bg-amber/90 transition-colors whitespace-nowrap rounded-sm"
>
Get Access
</button>
</form>
) : (
<div className="flex items-center justify-center gap-3 border border-edge bg-ink2/80 px-8 py-4 max-w-sm mx-auto animate-fade-in rounded-sm">
<span className="text-amber">✦</span>
<span className="font-mono text-[12px] text-mist">
You&apos;re on the list. We&apos;ll be in touch.
</span>
</div>
)}

<p className="mt-8 font-mono text-[10px] text-fog tracking-wide">
Built with Go · Qdrant · PostgreSQL · MCP
</p>
<Chrome size={20} strokeWidth={1.75} />
Add to Chrome
</a>
<a
href={GITHUB_REPO_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2.5 border border-edge bg-ink2/60 text-cream px-7 py-3.5 text-[12px] tracking-widest uppercase font-medium hover:bg-ink2 hover:border-edge2 transition-colors rounded-sm"
>
<Github size={18} strokeWidth={1.75} />
Star on GitHub
</a>
</div>
</div>
</section>
);
Expand Down
3 changes: 2 additions & 1 deletion app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { FC } from 'react';
import { GITHUB_REPO_URL } from '../utils/constant';

const footerLinks = [
{ label: 'GitHub', href: 'https://github.com/freedisch/havril' },
{ label: 'GitHub', href: GITHUB_REPO_URL },
{ label: 'Privacy', href: '/privacy' },
{ label: 'Status', href: '#' },
];
Expand Down
32 changes: 20 additions & 12 deletions app/components/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
'use client';
import { FC, useEffect, useState } from 'react';
import { Chrome, Github } from 'lucide-react';
import { useTypewriter } from '../utils/customState';
import { CHROME_STORE_URL, GITHUB_REPO_URL } from '../utils/constant';

export const Hero: FC = () => {
const memories = [
'"User is building a Go REST API"',
'"User prefers minimal dependencies"',
'"User is based in Kigali, Rwanda"',
'"User uses Chi router + PostgreSQL"',
'"User is writing a thesis on climate policy"',
'"User prefers APA citations and concise summaries"',
'"User is preparing for the GRE in August"',
'"User is learning French at intermediate level"',
];
const typed = useTypewriter(memories, 44, 2600);

Expand All @@ -17,9 +19,9 @@ export const Hero: FC = () => {

{/* Badge */}
<div className="relative z-10 flex items-center gap-2 border border-edge bg-ink2/80 px-4 py-1.5 mb-10 rounded-full animate-fade-up delay-0">
<span className="w-1.5 h-1.5 rounded-full bg-amber animate-blink" />
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400 animate-blink" />
<span className="font-mono text-[10px] tracking-widest uppercase text-fog">
Now in development
Live on Chrome Web Store
</span>
</div>

Expand All @@ -43,16 +45,22 @@ export const Hero: FC = () => {
{/* CTAs */}
<div className="relative z-10 mt-9 flex flex-col sm:flex-row items-center gap-4 animate-fade-up delay-300">
<a
href="#get-access"
className="bg-amber text-white px-7 py-3 text-[12px] tracking-widest uppercase font-medium rounded-sm hover:bg-amber/90 transition-colors"
href={CHROME_STORE_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2.5 bg-amber text-white px-7 py-3.5 text-[12px] tracking-widest uppercase font-medium rounded-sm hover:bg-amber/90 transition-colors"
>
Get early access
<Chrome size={20} strokeWidth={1.75} />
Add to Chrome
</a>
<a
href="#integrations"
className="text-[12px] tracking-widest uppercase text-fog hover:text-mist transition-colors"
href={GITHUB_REPO_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2.5 border border-edge bg-ink2/60 text-cream px-7 py-3.5 text-[12px] tracking-widest uppercase font-medium rounded-sm hover:bg-ink2 hover:border-edge2 transition-colors"
>
See it in action
<Github size={18} strokeWidth={1.75} />
Star on GitHub
</a>
</div>

Expand Down
26 changes: 19 additions & 7 deletions app/components/nav.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use client';
import { FC, useState } from 'react';
import { Chrome } from 'lucide-react';
import { useScrolled } from '../utils/customState';
import { CHROME_STORE_URL, GITHUB_REPO_URL } from '../utils/constant';

export const Nav: FC = () => {
const scrolled = useScrolled();
Expand All @@ -19,7 +21,7 @@ export const Nav: FC = () => {

<div className="hidden md:flex items-center gap-4">
<a
href="https://github.com/freedisch/havril"
href={GITHUB_REPO_URL}
target="_blank"
rel="noopener noreferrer"
aria-label="View on GitHub"
Expand All @@ -41,10 +43,13 @@ export const Nav: FC = () => {
</svg>
</a>
<a
href="#get-access"
className="text-[11px] tracking-widest uppercase bg-amber text-white px-5 py-2.5 font-medium hover:bg-amber/90 transition-colors rounded-sm"
href={CHROME_STORE_URL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 text-[11px] tracking-widest uppercase bg-amber text-white px-5 py-2.5 font-medium hover:bg-amber/90 transition-colors rounded-sm"
>
Get Early Access
<Chrome size={16} strokeWidth={1.75} />
Add to Chrome
</a>
</div>

Expand All @@ -66,7 +71,7 @@ export const Nav: FC = () => {
{menuOpen && (
<div className="absolute top-full left-0 right-0 bg-ink border-b border-edge p-8 flex flex-col gap-6 md:hidden">
<a
href="https://github.com/freedisch/havril"
href={GITHUB_REPO_URL}
target="_blank"
rel="noopener noreferrer"
className="text-[11px] tracking-widest uppercase text-mist hover:text-cream transition-colors"
Expand All @@ -83,8 +88,15 @@ export const Nav: FC = () => {
>
X / Twitter
</a>
<a href="#get-access" className="text-[11px] uppercase bg-amber text-white px-5 py-3 font-medium text-center rounded-sm">
Get Early Access
<a
href={CHROME_STORE_URL}
target="_blank"
rel="noopener noreferrer"
onClick={() => setMenuOpen(false)}
className="inline-flex items-center justify-center gap-2 text-[11px] uppercase bg-amber text-white px-5 py-3 font-medium text-center rounded-sm"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Styling inconsistency — mobile CTA missing tracking-widest. The desktop "Add to Chrome" button (line 48) has tracking-widest but this mobile version only has uppercase without it. The letter-spacing will differ between breakpoints for the same button, which looks inconsistent. Add tracking-widest here to match the desktop variant.

>
<Chrome size={16} strokeWidth={1.75} />
Add to Chrome
</a>
</div>
)}
Expand Down
3 changes: 3 additions & 0 deletions app/utils/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const CHROME_STORE_URL =
'https://chromewebstore.google.com/detail/jjlelibnopjfeefpdplponpnocjfcega?utm_source=item-share-cb';
export const GITHUB_REPO_URL = 'https://github.com/freedisch/havril';
Loading