Skip to content

Commit 46fe161

Browse files
authored
Merge pull request #11 from Priyans-hu/feat/landing-page
Add landing page
2 parents bed5bb4 + 03daa3f commit 46fe161

File tree

17 files changed

+2457
-0
lines changed

17 files changed

+2457
-0
lines changed

.github/workflows/pages.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Deploy Landing Page
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths: ['website/**']
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v4
22+
23+
- uses: actions/setup-node@v4
24+
with:
25+
node-version: 20
26+
cache: npm
27+
cache-dependency-path: website/package-lock.json
28+
29+
- name: Install dependencies
30+
run: npm ci
31+
working-directory: website
32+
33+
- name: Build
34+
run: npm run build
35+
working-directory: website
36+
env:
37+
NODE_ENV: production
38+
39+
- uses: actions/upload-pages-artifact@v3
40+
with:
41+
path: website/out
42+
43+
deploy:
44+
needs: build
45+
runs-on: ubuntu-latest
46+
environment:
47+
name: github-pages
48+
url: ${{ steps.deployment.outputs.page_url }}
49+
steps:
50+
- id: deployment
51+
uses: actions/deploy-pages@v4

website/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
.next/
3+
out/
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
"use client";
2+
3+
import { motion } from "framer-motion";
4+
import { RefreshCw, Settings } from "lucide-react";
5+
6+
function HeatmapGrid() {
7+
// 7 columns (days) x 5 rows (time slots) with varying opacity
8+
const cells = [
9+
[0.1, 0.3, 0.0, 0.6, 0.2, 0.8, 0.1],
10+
[0.4, 0.7, 0.2, 0.9, 0.5, 0.3, 0.0],
11+
[0.2, 0.5, 0.8, 0.4, 0.7, 0.1, 0.3],
12+
[0.6, 0.1, 0.4, 0.3, 0.9, 0.6, 0.2],
13+
[0.0, 0.8, 0.3, 0.7, 0.1, 0.5, 0.4],
14+
];
15+
16+
return (
17+
<div className="flex flex-col gap-[3px]">
18+
{cells.map((row, i) => (
19+
<div key={i} className="flex gap-[3px]">
20+
{row.map((opacity, j) => (
21+
<div
22+
key={j}
23+
className="h-3 w-3 rounded-[2px]"
24+
style={{
25+
backgroundColor:
26+
opacity === 0
27+
? "rgba(255,255,255,0.05)"
28+
: `rgba(74, 222, 128, ${opacity})`,
29+
}}
30+
/>
31+
))}
32+
</div>
33+
))}
34+
</div>
35+
);
36+
}
37+
38+
export default function AppMockup() {
39+
return (
40+
<section className="px-6 py-24 sm:py-32">
41+
<div className="mx-auto flex max-w-6xl justify-center">
42+
<motion.div
43+
initial={{ opacity: 0, scale: 0.95 }}
44+
whileInView={{ opacity: 1, scale: 1 }}
45+
transition={{ duration: 0.6, ease: "easeOut" }}
46+
viewport={{ once: true, margin: "-100px" }}
47+
className="w-full max-w-sm"
48+
>
49+
{/* Window frame */}
50+
<div className="overflow-hidden rounded-xl border border-white/10 bg-[#1a1a1a] shadow-2xl shadow-blue-500/5">
51+
{/* Title bar */}
52+
<div className="flex items-center gap-2 border-b border-white/10 bg-[#222] px-4 py-2.5">
53+
<div className="flex gap-1.5">
54+
<div className="h-3 w-3 rounded-full bg-[#ff5f57]" />
55+
<div className="h-3 w-3 rounded-full bg-[#febc2e]" />
56+
<div className="h-3 w-3 rounded-full bg-[#28c840]" />
57+
</div>
58+
</div>
59+
60+
{/* Popover content */}
61+
<div className="p-4">
62+
{/* Header */}
63+
<div className="flex items-center justify-between">
64+
<div className="flex items-center gap-2">
65+
<span className="text-sm font-semibold text-white">
66+
TokenMeter
67+
</span>
68+
<span className="rounded bg-blue-500/20 px-1.5 py-0.5 text-[10px] font-medium text-blue-400">
69+
Pro
70+
</span>
71+
</div>
72+
<div className="flex items-center gap-2 text-gray-500">
73+
<span className="text-[10px]">just now</span>
74+
<RefreshCw className="h-3 w-3" />
75+
<Settings className="h-3 w-3" />
76+
</div>
77+
</div>
78+
79+
{/* Rate limit bars */}
80+
<div className="mt-4 space-y-3">
81+
{/* Session bar */}
82+
<div>
83+
<div className="flex items-center justify-between text-xs">
84+
<span className="text-gray-400">5-Hour Session</span>
85+
<span className="text-blue-400">42%</span>
86+
</div>
87+
<div className="mt-1.5 h-2 overflow-hidden rounded-full bg-white/10">
88+
<div
89+
className="h-full rounded-full bg-blue-500"
90+
style={{ width: "42%" }}
91+
/>
92+
</div>
93+
</div>
94+
95+
{/* Weekly bar */}
96+
<div>
97+
<div className="flex items-center justify-between text-xs">
98+
<span className="text-gray-400">Weekly (7 days)</span>
99+
<span className="text-orange-400">67%</span>
100+
</div>
101+
<div className="mt-1.5 h-2 overflow-hidden rounded-full bg-white/10">
102+
<div
103+
className="h-full rounded-full bg-orange-500"
104+
style={{ width: "67%" }}
105+
/>
106+
</div>
107+
</div>
108+
</div>
109+
110+
{/* Heatmap */}
111+
<div className="mt-4 rounded-lg border border-white/5 bg-white/[0.02] p-3">
112+
<p className="mb-2 text-[10px] font-medium text-gray-500">
113+
Activity (7 days)
114+
</p>
115+
<HeatmapGrid />
116+
</div>
117+
118+
{/* Cost row */}
119+
<div className="mt-4 grid grid-cols-3 gap-2">
120+
<div className="rounded-lg bg-white/[0.03] p-2 text-center">
121+
<p className="text-[10px] text-gray-500">Today</p>
122+
<p className="text-sm font-semibold text-white">$94.82</p>
123+
</div>
124+
<div className="rounded-lg bg-white/[0.03] p-2 text-center">
125+
<p className="text-[10px] text-gray-500">This Week</p>
126+
<p className="text-sm font-semibold text-white">$295</p>
127+
</div>
128+
<div className="rounded-lg bg-white/[0.03] p-2 text-center">
129+
<p className="text-[10px] text-gray-500">This Month</p>
130+
<p className="text-sm font-semibold text-white">$1,340</p>
131+
</div>
132+
</div>
133+
</div>
134+
</div>
135+
</motion.div>
136+
</div>
137+
</section>
138+
);
139+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"use client";
2+
3+
import { useRef } from "react";
4+
import { motion, useInView } from "framer-motion";
5+
import {
6+
Activity,
7+
Bell,
8+
BarChart3,
9+
DollarSign,
10+
PieChart,
11+
Monitor,
12+
} from "lucide-react";
13+
14+
const features = [
15+
{
16+
icon: Activity,
17+
title: "Real Rate Limits",
18+
description:
19+
"Live utilization percentages from Anthropic API. Session and weekly windows with reset countdowns.",
20+
},
21+
{
22+
icon: Bell,
23+
title: "Smart Notifications",
24+
description:
25+
"macOS alerts when you hit 80% of your rate limit. Throttled to avoid spam.",
26+
},
27+
{
28+
icon: BarChart3,
29+
title: "Usage Heatmap",
30+
description:
31+
"Hour-by-day activity grid showing your coding patterns over 7, 14, or 30 days.",
32+
},
33+
{
34+
icon: DollarSign,
35+
title: "Cost Tracking",
36+
description:
37+
"API-equivalent cost breakdown — today, this week, this month. Per-model pricing.",
38+
},
39+
{
40+
icon: PieChart,
41+
title: "Model Breakdown",
42+
description:
43+
"See which models you use most. Opus, Sonnet, Haiku — tokens and costs per model.",
44+
},
45+
{
46+
icon: Monitor,
47+
title: "Menu Bar Native",
48+
description:
49+
"Lives in your menu bar. No dock icon. Works in fullscreen. Auto-refreshes every 5 minutes.",
50+
},
51+
];
52+
53+
const containerVariants = {
54+
hidden: {},
55+
visible: {
56+
transition: {
57+
staggerChildren: 0.1,
58+
},
59+
},
60+
};
61+
62+
const itemVariants = {
63+
hidden: { opacity: 0, y: 24 },
64+
visible: {
65+
opacity: 1,
66+
y: 0,
67+
transition: { duration: 0.5, ease: "easeOut" },
68+
},
69+
};
70+
71+
export default function Features() {
72+
const ref = useRef<HTMLDivElement>(null);
73+
const isInView = useInView(ref, { once: true, margin: "-100px" });
74+
75+
return (
76+
<section className="px-6 py-24 sm:py-32">
77+
<div className="mx-auto max-w-6xl">
78+
<h2 className="text-center text-3xl font-bold tracking-tight sm:text-4xl">
79+
Everything you need
80+
</h2>
81+
82+
<motion.div
83+
ref={ref}
84+
variants={containerVariants}
85+
initial="hidden"
86+
animate={isInView ? "visible" : "hidden"}
87+
className="mt-16 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3"
88+
>
89+
{features.map((feature) => (
90+
<motion.div
91+
key={feature.title}
92+
variants={itemVariants}
93+
className="rounded-xl border border-white/10 bg-white/[0.03] p-6 transition-colors hover:border-white/20 hover:bg-white/[0.05]"
94+
>
95+
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-blue-500/10">
96+
<feature.icon className="h-5 w-5 text-blue-400" />
97+
</div>
98+
<h3 className="mt-4 text-lg font-semibold">{feature.title}</h3>
99+
<p className="mt-2 text-sm leading-relaxed text-gray-400">
100+
{feature.description}
101+
</p>
102+
</motion.div>
103+
))}
104+
</motion.div>
105+
</div>
106+
</section>
107+
);
108+
}

website/app/components/Footer.tsx

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export default function Footer() {
2+
return (
3+
<footer className="border-t border-white/10 px-6 py-10">
4+
<div className="mx-auto flex max-w-6xl flex-col items-center gap-6 sm:flex-row sm:justify-between">
5+
<div className="flex items-center gap-4">
6+
<span className="text-sm font-semibold text-white">TokenMeter</span>
7+
<span className="text-xs text-gray-600">MIT License</span>
8+
</div>
9+
10+
<nav className="flex items-center gap-6">
11+
<a
12+
href="https://github.com/Priyans-hu/tokenmeter"
13+
target="_blank"
14+
rel="noopener noreferrer"
15+
className="text-xs text-gray-500 transition-colors hover:text-white"
16+
>
17+
GitHub
18+
</a>
19+
<a
20+
href="https://github.com/Priyans-hu/tokenmeter/releases"
21+
target="_blank"
22+
rel="noopener noreferrer"
23+
className="text-xs text-gray-500 transition-colors hover:text-white"
24+
>
25+
Releases
26+
</a>
27+
<a
28+
href="https://github.com/Priyans-hu/tokenmeter/issues"
29+
target="_blank"
30+
rel="noopener noreferrer"
31+
className="text-xs text-gray-500 transition-colors hover:text-white"
32+
>
33+
Issues
34+
</a>
35+
</nav>
36+
37+
<p className="text-xs text-gray-600">
38+
Built by{" "}
39+
<a
40+
href="https://github.com/Priyans-hu"
41+
target="_blank"
42+
rel="noopener noreferrer"
43+
className="text-gray-400 transition-colors hover:text-white"
44+
>
45+
Priyanshu
46+
</a>
47+
</p>
48+
</div>
49+
</footer>
50+
);
51+
}

0 commit comments

Comments
 (0)