feat: better navigation, updated cc.json, icons on homepage, better structure, cleanup manifesto page, NowPlaying.tsx fix
This commit is contained in:
parent
c1f0832f4a
commit
f81b145bf7
9 changed files with 773 additions and 252 deletions
|
@ -4,6 +4,7 @@ import Header from '@/components/Header'
|
|||
import Footer from '@/components/Footer'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { SiClaude } from 'react-icons/si'
|
||||
import Link from 'next/link'
|
||||
import {
|
||||
Line,
|
||||
BarChart,
|
||||
|
@ -83,8 +84,103 @@ export default function AI() {
|
|||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<Header />
|
||||
<main className="flex-1 flex items-center justify-center">
|
||||
<div className="text-gray-300">Loading Claude metrics...</div>
|
||||
<main className="w-full relative">
|
||||
<Link
|
||||
href="/ai"
|
||||
className="absolute top-4 left-4 text-gray-400 hover:text-gray-200 hover:underline transition-colors duration-200 z-10 px-2 py-1 text-sm sm:text-base"
|
||||
>
|
||||
← Back to AI
|
||||
</Link>
|
||||
|
||||
<div className="my-12 text-center">
|
||||
<div className="flex justify-center mb-6">
|
||||
<SiClaude size={60} />
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold mb-2 text-gray-100 glow">Claude Code Usage</h1>
|
||||
<p className="text-gray-400">How much I use Claude Code!</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 px-4">
|
||||
<div className="p-6 border-2 border-gray-700 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-gray-400 mb-2">Total Cost</h3>
|
||||
<div className="h-9 w-32 bg-gray-800 rounded animate-pulse" />
|
||||
</div>
|
||||
<div className="p-6 border-2 border-gray-700 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-gray-400 mb-2">Total Tokens</h3>
|
||||
<div className="h-9 w-32 bg-gray-800 rounded animate-pulse" />
|
||||
</div>
|
||||
<div className="p-6 border-2 border-gray-700 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-gray-400 mb-2">Days Active</h3>
|
||||
<div className="h-9 w-32 bg-gray-800 rounded animate-pulse" />
|
||||
</div>
|
||||
<div className="p-6 border-2 border-gray-700 rounded-lg">
|
||||
<h3 className="text-sm font-medium text-gray-400 mb-2">Avg Daily Cost</h3>
|
||||
<div className="h-9 w-32 bg-gray-800 rounded animate-pulse" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 p-4">
|
||||
<section className="p-8 border-2 border-gray-700 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Daily Usage Trend</h2>
|
||||
<div className="flex gap-2 mb-4">
|
||||
<button className="px-3 py-1 rounded bg-gray-700 text-gray-300" disabled>
|
||||
Cost
|
||||
</button>
|
||||
<button className="px-3 py-1 rounded bg-gray-700 text-gray-300" disabled>
|
||||
Tokens
|
||||
</button>
|
||||
</div>
|
||||
<div className="h-[300px] bg-gray-800 rounded animate-pulse" />
|
||||
</section>
|
||||
<section className="p-8 border-2 border-gray-700 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Model Usage Distribution</h2>
|
||||
<div className="h-[300px] bg-gray-800 rounded animate-pulse" />
|
||||
</section>
|
||||
<section className="p-8 border-2 border-gray-700 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Token Type Breakdown</h2>
|
||||
<div className="h-[300px] bg-gray-800 rounded animate-pulse" />
|
||||
</section>
|
||||
<section className="p-8 border-2 border-gray-700 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Daily Token Composition</h2>
|
||||
<div className="h-[300px] bg-gray-800 rounded animate-pulse" />
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div className="px-4 pb-4">
|
||||
<section className="p-8 border-2 border-gray-700 rounded-lg">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Recent Sessions</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left">
|
||||
<thead>
|
||||
<tr className="border-b border-gray-700">
|
||||
<th className="py-2 px-4 text-gray-400">Date</th>
|
||||
<th className="py-2 px-4 text-gray-400">Models Used</th>
|
||||
<th className="py-2 px-4 text-gray-400">Total Tokens</th>
|
||||
<th className="py-2 px-4 text-gray-400">Cost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{[...Array(5)].map((_, index) => (
|
||||
<tr key={index} className="border-b border-gray-800">
|
||||
<td className="py-2 px-4">
|
||||
<div className="h-5 w-24 bg-gray-800 rounded animate-pulse" />
|
||||
</td>
|
||||
<td className="py-2 px-4">
|
||||
<div className="h-5 w-96 bg-gray-800 rounded animate-pulse" />
|
||||
</td>
|
||||
<td className="py-2 px-4">
|
||||
<div className="h-5 w-16 bg-gray-800 rounded animate-pulse" />
|
||||
</td>
|
||||
<td className="py-2 px-4">
|
||||
<div className="h-5 w-20 bg-gray-800 rounded animate-pulse" />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
@ -114,6 +210,7 @@ export default function AI() {
|
|||
})
|
||||
return acc
|
||||
}, [] as { name: string; value: number }[])
|
||||
.sort((a, b) => b.value - a.value)
|
||||
|
||||
const tokenTypeData = [
|
||||
{ name: 'Input', value: data.totals.inputTokens },
|
||||
|
@ -123,7 +220,7 @@ export default function AI() {
|
|||
]
|
||||
|
||||
const dailyTrendData = data.daily.map(day => ({
|
||||
date: new Date(day.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
|
||||
date: new Date(day.date + 'T00:00:00').toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
|
||||
cost: day.totalCost,
|
||||
tokens: day.totalTokens / 1000000,
|
||||
inputTokens: day.inputTokens / 1000,
|
||||
|
@ -137,7 +234,13 @@ export default function AI() {
|
|||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<Header />
|
||||
<main className="w-full">
|
||||
<main className="w-full relative">
|
||||
<Link
|
||||
href="/ai"
|
||||
className="absolute top-4 left-4 text-gray-400 hover:text-gray-200 hover:underline transition-colors duration-200 z-10 px-2 py-1 text-sm sm:text-base"
|
||||
>
|
||||
← Back to AI
|
||||
</Link>
|
||||
<div className="my-12 text-center">
|
||||
<div className="flex justify-center mb-6">
|
||||
<SiClaude size={60} />
|
||||
|
@ -227,6 +330,8 @@ export default function AI() {
|
|||
<Tooltip
|
||||
contentStyle={{ backgroundColor: '#1f2937', border: '1px solid #374151', borderRadius: '8px' }}
|
||||
formatter={(value: number) => formatCurrency(value)}
|
||||
labelStyle={{ color: '#fff' }}
|
||||
itemStyle={{ color: '#fff' }}
|
||||
/>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
|
@ -273,10 +378,13 @@ export default function AI() {
|
|||
<XAxis dataKey="name" stroke="#9ca3af" />
|
||||
<YAxis stroke="#9ca3af" tickFormatter={(value) => `${(value / 1000000).toFixed(0)}M`} />
|
||||
<Tooltip
|
||||
contentStyle={{ backgroundColor: '#1f2937', border: '1px solid #374151' }}
|
||||
contentStyle={{ backgroundColor: 'rgba(31, 41, 55)', border: '1px solid #374151' }}
|
||||
formatter={(value: number) => `${(value / 1000000).toFixed(2)}M tokens`}
|
||||
/>
|
||||
<Bar dataKey="value" fill="#b1ada1" />
|
||||
<Bar
|
||||
dataKey="value"
|
||||
fill="#b1ada1"
|
||||
/>
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</section>
|
||||
|
@ -317,7 +425,7 @@ export default function AI() {
|
|||
<tbody>
|
||||
{data.daily.slice(-5).reverse().map((day, index) => (
|
||||
<tr key={index} className="border-b border-gray-800 hover:bg-gray-800/50">
|
||||
<td className="py-2 px-4 text-gray-300">{new Date(day.date).toLocaleDateString()}</td>
|
||||
<td className="py-2 px-4 text-gray-300">{new Date(day.date + 'T00:00:00').toLocaleDateString()}</td>
|
||||
<td className="py-2 px-4 text-gray-300">
|
||||
{day.modelsUsed.join(', ')}
|
||||
</td>
|
||||
|
|
|
@ -16,8 +16,8 @@ export default function Manifesto() {
|
|||
Internet Manifesto
|
||||
</h1>
|
||||
</div>
|
||||
<div className="px-6 pt-6">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">
|
||||
<div className="px-6 pt-12">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">
|
||||
1. Empathy and Understanding
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-4">
|
||||
|
@ -28,6 +28,7 @@ export default function Manifesto() {
|
|||
<li>Suspend judgment and seek to understand</li>
|
||||
<li>Recognize the humanity in every digital interaction</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="text-2xl font-semibold mb-4 mt-12 text-gray-200">
|
||||
2. Unconditional Sharing!
|
||||
</h2>
|
||||
|
@ -40,12 +41,14 @@ export default function Manifesto() {
|
|||
<li>Support open-source principles</li>
|
||||
<li>Create extensive documentation on all of my projects</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="text-2xl font-semibold mb-4 mt-12 text-gray-200">
|
||||
3. Genuine Human Connection
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-4">
|
||||
I aim to create a genuine human connection with all people I meet, regardless of who or where they are from.
|
||||
</p>
|
||||
|
||||
<h2 className="text-2xl font-semibold mb-4 mt-12 text-gray-200">
|
||||
4. Privacy & Self-Hosted Services
|
||||
</h2>
|
||||
|
@ -62,6 +65,7 @@ export default function Manifesto() {
|
|||
<li>Focus my services on being free and open</li>
|
||||
<li>Suggest and support privacy-focused software</li>
|
||||
</ul>
|
||||
|
||||
<h2 className="text-2xl font-semibold mb-4 mt-12 text-gray-200">
|
||||
I Commit
|
||||
</h2>
|
||||
|
|
64
app/page.tsx
64
app/page.tsx
|
@ -4,11 +4,26 @@ import Header from '@/components/Header'
|
|||
import Footer from '@/components/Footer'
|
||||
import Button from '@/components/objects/Button'
|
||||
import LastPlayed from '@/components/widgets/NowPlaying'
|
||||
|
||||
import Image from 'next/image'
|
||||
import { CreditCard, Mail, PillBottle, Scale } from 'lucide-react'
|
||||
|
||||
import {CreditCard, Mail, PillBottle, Scale, UserCircle} from 'lucide-react'
|
||||
import { BsArrowClockwise } from "react-icons/bs";
|
||||
import { FaHandcuffs } from "react-icons/fa6"
|
||||
import {
|
||||
SiGithubsponsors,
|
||||
SiNextdotjs,
|
||||
SiTailwindcss,
|
||||
SiDocker,
|
||||
SiLinux,
|
||||
SiTypescript,
|
||||
SiClaude,
|
||||
SiPostgresql
|
||||
} from 'react-icons/si'
|
||||
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SiGithubsponsors } from 'react-icons/si'
|
||||
import {TbHeartHandshake, TbUserHeart, TbMessage} from "react-icons/tb";
|
||||
import {BiDonateHeart} from "react-icons/bi";
|
||||
|
||||
export default function Home() {
|
||||
const { t } = useTranslation()
|
||||
|
@ -58,7 +73,33 @@ export default function Home() {
|
|||
|
||||
{mainSections.map((section, secIndex) => (
|
||||
<section key={secIndex} className="p-4 sm:p-8 border-2 border-gray-700 rounded-lg hover:border-gray-600 transition-colors duration-300">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">{section}</h2>
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">{section === t('home.sections.whereYouAre') ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<TbHeartHandshake />
|
||||
<span className="align-middle">{section}</span>
|
||||
</div>
|
||||
) : section === t('home.sections.whoIAm') ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<UserCircle />
|
||||
<span className="align-middle">{section}</span>
|
||||
</div>
|
||||
) : section === t('home.sections.whatIDo') ? (
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<TbUserHeart />
|
||||
<span className="align-middle">{section}</span>
|
||||
</div>
|
||||
) : (section)}</h2>
|
||||
{section === t('home.sections.whatIDo') && (
|
||||
<div className="flex flex-row items-center justify-center gap-4 my-8">
|
||||
<SiNextdotjs size={38} />
|
||||
<SiTypescript size={38} />
|
||||
<SiTailwindcss size={38} />
|
||||
<SiPostgresql size={38} />
|
||||
<SiDocker size={38} />
|
||||
<SiLinux size={38} />
|
||||
<SiClaude size={38} />
|
||||
</div>
|
||||
)}
|
||||
{mainStrings[secIndex].map((text: string, index: number) => (
|
||||
<p key={index} className="text-gray-300 leading-relaxed mt-2">
|
||||
{text}
|
||||
|
@ -68,7 +109,10 @@ export default function Home() {
|
|||
))}
|
||||
|
||||
<section id="contact" className="p-4 sm:p-8 border-2 border-gray-700 rounded-lg hover:border-gray-600 transition-colors duration-300">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">{t('home.contact.title')}</h2>
|
||||
<h2 className="flex flex-row items-center gap-2 text-2xl font-semibold mb-4 text-gray-200">
|
||||
<TbMessage />
|
||||
{t('home.contact.title')}
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-6">{t('home.contact.description')}</p>
|
||||
<Button
|
||||
href={'/contact'}
|
||||
|
@ -79,7 +123,10 @@ export default function Home() {
|
|||
</section>
|
||||
|
||||
<section id="donation" className="p-4 sm:p-8 border-2 border-gray-700 rounded-lg hover:border-gray-600 transition-colors duration-300">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">{t('home.donation.title')}</h2>
|
||||
<h2 className="flex flex-row items-center gap-2 text-2xl font-semibold mb-4 text-gray-200">
|
||||
<BiDonateHeart />
|
||||
{t('home.donation.title')}
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-6">{t('home.donation.description')}</p>
|
||||
<h4 className="text-lg font-semibold mb-2 text-gray-200">{t('home.donation.charities.title')}</h4>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 md:text-sm gap-3">
|
||||
|
@ -104,6 +151,13 @@ export default function Home() {
|
|||
>
|
||||
{t('home.donation.charities.aclu')}
|
||||
</Button>
|
||||
<Button
|
||||
href="https://www.epicrestartfoundation.org"
|
||||
icon={<BsArrowClockwise size={16} />}
|
||||
target="_blank"
|
||||
>
|
||||
{t('home.donation.charities.epic-restart')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<h4 className="text-lg font-semibold mt-5 mb-2 text-gray-200">{t('home.donation.donate.title')}</h4>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue