Skip to content

Repository files navigation

Sightline — B2B analytics landing page

A production-quality marketing site for a fictional product analytics platform, built to show how I approach landing pages: real components, real accessibility, and charts built from scratch rather than dropped in from a library.

Live site: https://sightline-analytics.vercel.app

Sightline landing page, light and dark

Sightline is not a real company. The product, the customer names, the quotes and every number on the page are invented. This is a self-directed portfolio project.


The brief I set myself

Take the kind of request that lands in my inbox most weeks — "a modern, responsive landing page for our SaaS, React or Next.js preferred" — and answer it properly rather than minimally.

That meant treating four things as non-negotiable:

  1. The charts had to be real. An analytics product with fake chart images is the tell that nobody built the hard part.
  2. Both themes had to be designed, not generated by inverting the light one.
  3. Keyboard and screen-reader users had to get the whole page, including the tabs, the accordion and the data behind every chart.
  4. It had to be fast, because performance is the one quality claim a client can verify in thirty seconds.

Stack, and why

Choice Reason
Next.js 16 (App Router) Static prerendering out of the box. The whole page ships as HTML, so first paint does not wait on JavaScript.
TypeScript Chart geometry is arithmetic. Types catch the off-by-one before the browser does.
Tailwind CSS v4 Utilities for layout, CSS custom properties for colour. See the theming note below.
Framer Motion Scroll-triggered reveals and layout transitions with a built-in reduced-motion escape hatch.
No chart library Recharts or Chart.js would have been faster to write and heavier to ship. The SVG here is a few hundred lines and does exactly what this page needs.

Worth a look

Charts built from nothingsrc/components/charts/

Three chart types, all hand-drawn SVG: an area chart with a damped Catmull-Rom curve, a grouped bar chart with rounded data-ends anchored flat to the baseline, and a sparkline. Each has a pointer-tracking crosshair that snaps to the nearest real data point, a tooltip, a legend, and a View data table disclosure exposing the underlying numbers. Axis ceilings round to readable values, so 3,680 gives a 4,000 axis rather than 3,680.

Theming with no dark: variantssrc/app/globals.css

Every colour in the UI is a semantic role (--surface, --ink-2, --line, --s1) rather than a literal. Light and dark are two selected sets of the same roles, defined once. Components never carry a dark-mode variant, which is the same pattern I maintain in a bank-wide design system at work. An inline script applies the stored theme before first paint, and the toggle reads through useSyncExternalStore so there is no flash and no hydration mismatch.

Accessibility that survives a real audit

Tabs implement the full roving-focus pattern with arrow, Home and End keys. The accordion is a real disclosure with aria-expanded and labelled regions. Charts carry a table view. There is a skip link, visible focus rings throughout, and semantic landmarks.

Reduced motion done correctlysrc/lib/motion.ts

Every reveal animates opacity alongside its transform. The usual scroll-animation bug is a transform-only reveal that leaves the page permanently blank when the viewer has reduced motion enabled. Here the parallax is disabled, the counters resolve to their final value, and all content ends up visible.

Performance

Measured with Lighthouse against a production build (next start), not the dev server, on a desktop profile with Lighthouse's default throttling.

Category Score
Performance 97
Accessibility 100
Best Practices 100
SEO 100
Metric Value
First Contentful Paint 0.8 s
Speed Index 0.8 s
Largest Contentful Paint 2.5 s
Total Blocking Time 40 ms
Cumulative Layout Shift 0

Cumulative Layout Shift is zero because the charts reserve their height before measuring, and the theme is applied by an inline script before first paint.

The full report is committed at docs/lighthouse.json, so the numbers above can be checked rather than taken on trust.

More screenshots

Dark theme hero Feature grid
Charts with tooltip Pricing

Running it locally

npm install
npm run dev

Then open http://localhost:3000.

npm run build && npm start   # production build
npx tsc --noEmit             # type check
npx eslint .                 # lint

Structure

src/
├── app/              layout, page, design tokens
├── components/
│   ├── charts/       SVG charts and shared scale helpers
│   ├── sections/     one file per page section
│   └── ui/           Button, Icon, Section, ThemeToggle
└── lib/
    ├── content.ts    every string, price and data point
    └── motion.ts     shared animation vocabulary

All copy and data lives in content.ts rather than being scattered through JSX, so the page can be rebranded without touching a component.

License

MIT — see LICENSE.


Built by Irakli Tabukashvili. Available for landing page and front-end work on Upwork.

About

B2B SaaS analytics landing page. Next.js 16, TypeScript, Tailwind v4, Framer Motion. Hand-built SVG charts, no charting library. Lighthouse 97/100/100/100.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages