Add Human vs AI chart
This commit is contained in:
@@ -1,20 +1,10 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Bar, BarChart, LabelList, XAxis, YAxis, Cell } from "recharts";
|
import { Bar, BarChart, LabelList, XAxis, YAxis, Cell } from "recharts"
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils"
|
||||||
|
import { ChartContainer, type ChartConfig } from "@/components/ui/chart"
|
||||||
|
|
||||||
import {
|
const COLORS = ["#4ade80", "#60a5fa", "#f87171", "#fb923c", "#c084fc"]
|
||||||
ChartContainer,
|
|
||||||
type ChartConfig,
|
|
||||||
} from "@/components/ui/chart";
|
|
||||||
|
|
||||||
const COLORS = [
|
|
||||||
"#4ade80",
|
|
||||||
"#60a5fa",
|
|
||||||
"#f87171",
|
|
||||||
"#fb923c",
|
|
||||||
"#c084fc",
|
|
||||||
]
|
|
||||||
|
|
||||||
const chartConfig = {
|
const chartConfig = {
|
||||||
total_seconds: {
|
total_seconds: {
|
||||||
@@ -33,8 +23,9 @@ interface MyBarChartProps {
|
|||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MyBarChartSkeletonProps {
|
interface MyBarChartStateProps {
|
||||||
className?: string
|
className?: string
|
||||||
|
bars?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MyBarChart({ data, className }: MyBarChartProps) {
|
export function MyBarChart({ data, className }: MyBarChartProps) {
|
||||||
@@ -83,14 +74,11 @@ export function MyBarChart({ data, className }: MyBarChartProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MyBarChartSkeleton({ className }: MyBarChartSkeletonProps) {
|
export function MyBarChartSkeleton({ className, bars = 5 }: MyBarChartStateProps) {
|
||||||
const fakeData = [
|
const fakeData = Array.from({ length: bars }).map((_, i) => ({
|
||||||
{ language: "a", total_seconds: 102000 },
|
language: String.fromCharCode(97 + i),
|
||||||
{ language: "b", total_seconds: 59000 },
|
total_seconds: 100000 - i * 15000,
|
||||||
{ language: "c", total_seconds: 41000 },
|
}))
|
||||||
{ language: "d", total_seconds: 28000 },
|
|
||||||
{ language: "e", total_seconds: 17000 },
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
@@ -98,61 +86,28 @@ export function MyBarChartSkeleton({ className }: MyBarChartSkeletonProps) {
|
|||||||
className={cn("w-full overflow-visible animate-pulse", className)}
|
className={cn("w-full overflow-visible animate-pulse", className)}
|
||||||
style={{ height: fakeData.length * 28 }}
|
style={{ height: fakeData.length * 28 }}
|
||||||
>
|
>
|
||||||
<BarChart
|
<BarChart data={fakeData} layout="vertical" margin={{ right: 0, left: 0, top: 0, bottom: 0 }} barSize={20}>
|
||||||
data={fakeData}
|
|
||||||
layout="vertical"
|
|
||||||
margin={{ right: 0, left: 0, top: 0, bottom: 0 }}
|
|
||||||
barSize={20}
|
|
||||||
barCategoryGap="10%"
|
|
||||||
>
|
|
||||||
<YAxis dataKey="language" type="category" hide />
|
<YAxis dataKey="language" type="category" hide />
|
||||||
<XAxis dataKey="total_seconds" type="number" hide />
|
<XAxis dataKey="total_seconds" type="number" hide />
|
||||||
<Bar
|
<Bar dataKey="total_seconds" layout="vertical" fill="#6b7280" radius={4} opacity={0.3} isAnimationActive={false} />
|
||||||
dataKey="total_seconds"
|
|
||||||
layout="vertical"
|
|
||||||
fill="#6b7280"
|
|
||||||
radius={4}
|
|
||||||
opacity={0.3}
|
|
||||||
isAnimationActive={false}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ChartContainer>
|
</ChartContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MyBarChartError({ className }: MyBarChartSkeletonProps) {
|
export function MyBarChartError({ className, bars = 5 }: MyBarChartStateProps) {
|
||||||
const fakeData = [
|
const fakeData = Array.from({ length: bars }).map((_, i) => ({
|
||||||
{ language: "a", total_seconds: 102000 },
|
language: String.fromCharCode(97 + i),
|
||||||
{ language: "b", total_seconds: 59000 },
|
total_seconds: 100000 - i * 15000,
|
||||||
{ language: "c", total_seconds: 41000 },
|
}))
|
||||||
{ language: "d", total_seconds: 28000 },
|
|
||||||
{ language: "e", total_seconds: 17000 },
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("relative w-full overflow-hidden", className)} style={{ height: fakeData.length * 28 }}>
|
<div className={cn("relative w-full overflow-hidden", className)} style={{ height: fakeData.length * 28 }}>
|
||||||
<ChartContainer
|
<ChartContainer config={chartConfig} className="w-full overflow-visible" style={{ height: fakeData.length * 28 }}>
|
||||||
config={chartConfig}
|
<BarChart data={fakeData} layout="vertical" margin={{ right: 0, left: 0, top: 0, bottom: 0 }} barSize={20}>
|
||||||
className="w-full overflow-visible"
|
|
||||||
style={{ height: fakeData.length * 28 }}
|
|
||||||
>
|
|
||||||
<BarChart
|
|
||||||
data={fakeData}
|
|
||||||
layout="vertical"
|
|
||||||
margin={{ right: 0, left: 0, top: 0, bottom: 0 }}
|
|
||||||
barSize={20}
|
|
||||||
barCategoryGap="10%"
|
|
||||||
>
|
|
||||||
<YAxis dataKey="language" type="category" hide />
|
<YAxis dataKey="language" type="category" hide />
|
||||||
<XAxis dataKey="total_seconds" type="number" hide />
|
<XAxis dataKey="total_seconds" type="number" hide />
|
||||||
<Bar
|
<Bar dataKey="total_seconds" layout="vertical" fill="#7f1d1d" radius={4} opacity={0.6} isAnimationActive={false} />
|
||||||
dataKey="total_seconds"
|
|
||||||
layout="vertical"
|
|
||||||
fill="#7f1d1d"
|
|
||||||
radius={4}
|
|
||||||
opacity={0.6}
|
|
||||||
isAnimationActive={false}
|
|
||||||
/>
|
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ChartContainer>
|
</ChartContainer>
|
||||||
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { MyBarChart, MyBarChartError } from "./bar-chart";
|
import { MyBarChart, MyBarChartError, MyBarChartSkeleton } from "./bar-chart"
|
||||||
|
|
||||||
type WakatimeLanguage = {
|
type WakatimeLanguage = {
|
||||||
name: string
|
name: string
|
||||||
@@ -7,27 +7,64 @@ type WakatimeLanguage = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function Wakatime({ className }: { className?: string }) {
|
export async function Wakatime({ className }: { className?: string }) {
|
||||||
const response = await fetch("https://wakatime.com/api/v1/users/alixz/stats/last_30_days", {
|
const response = await fetch(
|
||||||
method: "GET",
|
"https://wakatime.com/api/v1/users/alixz/stats/last_30_days",
|
||||||
headers: {
|
{
|
||||||
"Authorization": `Basic ${process.env.WAKATIME}`
|
method: "GET",
|
||||||
},
|
headers: {
|
||||||
next: { revalidate: 3600 }
|
Authorization: `Basic ${process.env.WAKATIME}`,
|
||||||
});
|
},
|
||||||
|
next: { revalidate: 3600 },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (!response.ok) return <MyBarChartError className={className} />;
|
if (!response.ok) {
|
||||||
|
return (
|
||||||
const res = await response.json();
|
<div className={className}>
|
||||||
|
<MyBarChartError bars={5} />
|
||||||
if (!res?.data?.languages?.length) {
|
<div className="h-6" />
|
||||||
return <MyBarChartError className={className} />;
|
<MyBarChartError bars={2} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = res.data.languages.slice(0, 5).map((lang: WakatimeLanguage) => ({
|
const res = await response.json()
|
||||||
|
const stats = res?.data
|
||||||
|
|
||||||
|
if (!stats?.languages?.length) {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<MyBarChartError bars={5} />
|
||||||
|
<div className="h-6" />
|
||||||
|
<MyBarChartError bars={2} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const languagesData = stats.languages.slice(0, 5).map((lang: WakatimeLanguage) => ({
|
||||||
language: lang.name,
|
language: lang.name,
|
||||||
total_seconds: lang.total_seconds,
|
total_seconds: lang.total_seconds,
|
||||||
label: `${lang.name} (${lang.text})`,
|
label: `${lang.name} (${lang.text})`,
|
||||||
}));
|
}))
|
||||||
|
|
||||||
return <MyBarChart className={className} data={data} />;
|
const additionsData = [
|
||||||
|
{
|
||||||
|
language: "Human",
|
||||||
|
total_seconds: stats.human_additions,
|
||||||
|
label: `Human (${stats.human_additions.toLocaleString()} lines written)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
language: "AI",
|
||||||
|
total_seconds: stats.ai_additions,
|
||||||
|
label: `AI (${stats.ai_additions.toLocaleString()} lines written)`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<MyBarChart data={languagesData} />
|
||||||
|
<div className="h-6" />
|
||||||
|
<MyBarChart data={additionsData} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user