mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 13:12:44 +00:00
docs: add /progress page with live stats cards and update navigation and component imports
This commit is contained in:
1 parent
cb4a03b6fa
commit
13734e2e27
11 files changed
+88
-57
No files matched your search
@@ -127,10 +127,11 @@ export default defineConfig({
|
|||||||
llmsTxt: true,
|
llmsTxt: true,
|
||||||
mcp: { enabled: false },
|
mcp: { enabled: false },
|
||||||
},
|
},
|
||||||
// The only content source. `/changelog` and `/appendix` are custom pages
|
// The only content source. `/changelog`, `/appendix` and `/progress` are
|
||||||
// (pages/*.astro): `/changelog` reads the GitHub releases itself — one
|
// custom pages (pages/*.astro): `/changelog` reads the GitHub releases
|
||||||
// timeline, no per-release pages — and `/appendix` is one glossary page
|
// itself — one timeline, no per-release pages — `/appendix` is one glossary
|
||||||
// built from appendix.ts, so neither enters the sidebar tree or prev/next.
|
// page built from appendix.ts, and `/progress` is the live stats cards, so
|
||||||
|
// none enters the sidebar tree or prev/next.
|
||||||
content: {
|
content: {
|
||||||
sources: [filesystem({ root: "content" })],
|
sources: [filesystem({ root: "content" })],
|
||||||
},
|
},
|
||||||
@@ -142,10 +143,11 @@ export default defineConfig({
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
display: "flat", // "flat" | "group" | "page"
|
display: "flat", // "flat" | "group" | "page"
|
||||||
},
|
},
|
||||||
// The two custom pages (pages/*.astro) as header tabs. Neither is a
|
// The custom pages (pages/*.astro) as header tabs. None is a content
|
||||||
// content folder, so the tabs scope nothing out of the sidebar tree.
|
// folder, so the tabs scope nothing out of the sidebar tree.
|
||||||
tabs: [
|
tabs: [
|
||||||
{ label: "Changelog", path: "/changelog" },
|
{ label: "Changelog", path: "/changelog" },
|
||||||
|
{ label: "Progress", path: "/progress" },
|
||||||
{ label: "Appendix", path: "/appendix" },
|
{ label: "Appendix", path: "/appendix" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,12 +5,10 @@
|
|||||||
* hover. A row links to the problem's docs page when one exists: the
|
* hover. A row links to the problem's docs page when one exists: the
|
||||||
* sync-generated short links (`redirects.ts`) are exactly the pages built.
|
* sync-generated short links (`redirects.ts`) are exactly the pages built.
|
||||||
*/
|
*/
|
||||||
import { StatsPending } from "../components/progress/shared";
|
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
|
import { useStats, utcDate } from "../../lib/stats";
|
||||||
import { useStats, utcDate } from "../lib/stats";
|
import redirects from "../../redirects";
|
||||||
import redirects from "../redirects";
|
import { StatsPending } from "./shared";
|
||||||
|
|
||||||
export const client = "load";
|
|
||||||
|
|
||||||
const PAGES = new Map(redirects.map((r) => [r.from, r.to]));
|
const PAGES = new Map(redirects.map((r) => [r.from, r.to]));
|
||||||
|
|
||||||
@@ -8,13 +8,11 @@
|
|||||||
*/
|
*/
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Pie, PieChart } from "recharts";
|
import { Pie, PieChart } from "recharts";
|
||||||
import { StatsPending } from "../components/progress/shared";
|
import { Card, CardContent } from "../ui/card";
|
||||||
import { Card, CardContent } from "../components/ui/card";
|
import { type ChartConfig, ChartContainer } from "../ui/chart";
|
||||||
import { type ChartConfig, ChartContainer } from "../components/ui/chart";
|
import { DIFFICULTIES, type Difficulty, useStats } from "../../lib/stats";
|
||||||
import { DIFFICULTIES, type Difficulty, useStats } from "../lib/stats";
|
import { cn } from "../../lib/utils";
|
||||||
import { cn } from "../lib/utils";
|
import { StatsPending } from "./shared";
|
||||||
|
|
||||||
export const client = "load";
|
|
||||||
|
|
||||||
const chartConfig = {
|
const chartConfig = {
|
||||||
easy: { label: "Easy", color: "var(--chart-1)" },
|
easy: { label: "Easy", color: "var(--chart-1)" },
|
||||||
+5
-7
@@ -9,13 +9,11 @@
|
|||||||
*/
|
*/
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts";
|
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts";
|
||||||
import { StatsPending } from "../components/progress/shared";
|
import { Card, CardAction, CardContent, CardFooter, CardHeader } from "../ui/card";
|
||||||
import { Card, CardAction, CardContent, CardFooter, CardHeader } from "../components/ui/card";
|
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "../ui/chart";
|
||||||
import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from "../components/ui/chart";
|
import { ToggleGroup, ToggleGroupItem } from "../ui/toggle-group";
|
||||||
import { ToggleGroup, ToggleGroupItem } from "../components/ui/toggle-group";
|
import { DIFFICULTIES, type Day, type Difficulty, useStats, utcDate } from "../../lib/stats";
|
||||||
import { DIFFICULTIES, type Day, type Difficulty, useStats, utcDate } from "../lib/stats";
|
import { StatsPending } from "./shared";
|
||||||
|
|
||||||
export const client = "load";
|
|
||||||
|
|
||||||
const chartConfig = {
|
const chartConfig = {
|
||||||
easy: { label: "Easy", color: "var(--chart-1)" },
|
easy: { label: "Easy", color: "var(--chart-1)" },
|
||||||
+3
-5
@@ -8,11 +8,9 @@
|
|||||||
* 4) and rows start on Monday like it, so the three heatmaps read the same.
|
* 4) and rows start on Monday like it, so the three heatmaps read the same.
|
||||||
* Drawn as SVG in a viewBox, so it scales to its column instead of scrolling.
|
* Drawn as SVG in a viewBox, so it scales to its column instead of scrolling.
|
||||||
*/
|
*/
|
||||||
import { StatsPending, TipRow, useHoverTip } from "../components/progress/shared";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card";
|
import { type Day, useStats, utcDate } from "../../lib/stats";
|
||||||
import { type Day, useStats, utcDate } from "../lib/stats";
|
import { StatsPending, TipRow, useHoverTip } from "./shared";
|
||||||
|
|
||||||
export const client = "load";
|
|
||||||
|
|
||||||
const MONTHS = 6;
|
const MONTHS = 6;
|
||||||
const CELL = 10;
|
const CELL = 10;
|
||||||
@@ -9,12 +9,10 @@
|
|||||||
*/
|
*/
|
||||||
import { packEnclose, packSiblings } from "d3-hierarchy";
|
import { packEnclose, packSiblings } from "d3-hierarchy";
|
||||||
import { useId } from "react";
|
import { useId } from "react";
|
||||||
import { StatsPending, TipRow, useHoverTip } from "../components/progress/shared";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card";
|
import { type Stats, useStats } from "../../lib/stats";
|
||||||
import { type Stats, useStats } from "../lib/stats";
|
import { cn } from "../../lib/utils";
|
||||||
import { cn } from "../lib/utils";
|
import { StatsPending, TipRow, useHoverTip } from "./shared";
|
||||||
|
|
||||||
export const client = "load";
|
|
||||||
|
|
||||||
const PAD = 2; // gap between bubbles, in layout units
|
const PAD = 2; // gap between bubbles, in layout units
|
||||||
const UNIT = 12; // radius of a one-problem bubble
|
const UNIT = 12; // radius of a one-problem bubble
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* What the four progress islands share besides the data: the not-ready body
|
* What the progress cards share besides the data: the not-ready body
|
||||||
* (a skeleton while /api/stats loads, one muted line if it fails) and the
|
* (a skeleton while /api/stats loads, one muted line if it fails) and the
|
||||||
* hover tooltip for the two charts drawn as plain SVG (the heatmap calendar
|
* hover tooltip for the two charts drawn as plain SVG (the heatmap calendar
|
||||||
* and the topic bubbles — Recharts has neither layout). The tooltip wears the
|
* and the topic bubbles — Recharts has neither layout). The tooltip wears the
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
title: Progress
|
|
||||||
description: Live campaign progress — solved by difficulty, recent attempts, the year by difficulty, topic coverage, and the most recently solved problems, fetched from the SRS Worker.
|
|
||||||
icon: loader
|
|
||||||
---
|
|
||||||
|
|
||||||
<div className="not-prose flex flex-col gap-6">
|
|
||||||
<SolvedRing />
|
|
||||||
<div className="grid gap-6 md:grid-cols-2">
|
|
||||||
<SubmissionHeatmap />
|
|
||||||
<SubmissionChart />
|
|
||||||
</div>
|
|
||||||
<TopicBubbles />
|
|
||||||
<RecentSolves />
|
|
||||||
</div>
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
---
|
---
|
||||||
title: System Design
|
title: System Design
|
||||||
description: "Notes on System Design Interview — An Insider's Guide (Volumes 1 and 2): how to scope a problem, size it, and pick the parts that carry the load."
|
description: "Notes on System Design Interview — An Insider's Guide (Volumes 1 and 2): how to scope a problem, size it, and pick the parts that carry the load."
|
||||||
icon: network
|
icon: play
|
||||||
|
sidebar:
|
||||||
|
label: 'Getting Started'
|
||||||
---
|
---
|
||||||
|
|
||||||
These notes follow Alex Xu's [System Design Interview — An Insider's Guide](https://bytebytego.com/courses/system-design-interview), [Volumes 1 and 2](https://www.goodreads.com/book/show/54109255-system-design-interview-an-insider-s-guide).
|
These notes follow Alex Xu's [System Design Interview — An Insider's Guide](https://bytebytego.com/courses/system-design-interview), [Volumes 1 and 2](https://www.goodreads.com/book/show/54109255-system-design-interview-an-insider-s-guide).
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
* browser so `blume build` never depends on the API being up. API_BASE is the
|
* browser so `blume build` never depends on the API being up. API_BASE is the
|
||||||
* deployed Worker — do not inline it anywhere else.
|
* deployed Worker — do not inline it anywhere else.
|
||||||
*
|
*
|
||||||
* Four islands read this (SolvedRing, SubmissionHeatmap, RecentSolves,
|
* The five cards on pages/progress.astro read this (components/progress/).
|
||||||
* TopicBubbles). Each hydrates on its own, but they share this module, so the
|
* Each hydrates on its own, but they share this module, so the one in-flight
|
||||||
* one in-flight request is shared too: the page asks the Worker once.
|
* request is shared too: the page asks the Worker once.
|
||||||
*
|
*
|
||||||
* Invariants: a malformed body is an error state, never a throw; the first
|
* Invariants: a malformed body is an error state, never a throw; the first
|
||||||
* frame is always the loading state, so server and client render identically.
|
* frame is always the loading state, so server and client render identically.
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
/**
|
||||||
|
* `/progress`: the live campaign dashboard — five LeetCode-style React cards
|
||||||
|
* over GET /api/stats (lib/stats.ts), hydrated on load. A custom page like
|
||||||
|
* `/changelog` and `/appendix`, linked from the header's `navigation.tabs`,
|
||||||
|
* so it enters neither the sidebar tree nor prev/next. The cards live in
|
||||||
|
* components/progress/, not islands/: they are imported here, never used from
|
||||||
|
* MDX, so Blume has no reason to register them as global MDX components.
|
||||||
|
*/
|
||||||
|
import PageLayout from "blume/components/layout/PageLayout.astro";
|
||||||
|
import data from "blume:data";
|
||||||
|
import RecentSolves from "../components/progress/RecentSolves";
|
||||||
|
import SolvedRing from "../components/progress/SolvedRing";
|
||||||
|
import SubmissionChart from "../components/progress/SubmissionChart";
|
||||||
|
import SubmissionHeatmap from "../components/progress/SubmissionHeatmap";
|
||||||
|
import TopicBubbles from "../components/progress/TopicBubbles";
|
||||||
|
|
||||||
|
const { config } = data;
|
||||||
|
const description =
|
||||||
|
"Live campaign progress — solved by difficulty, recent attempts, the year by difficulty, topic coverage, and the most recently solved problems, fetched from the SRS Worker.";
|
||||||
|
---
|
||||||
|
|
||||||
|
<PageLayout
|
||||||
|
site={{ title: config.title, description: config.description }}
|
||||||
|
logo={config.logo}
|
||||||
|
favicon={config.favicon}
|
||||||
|
banner={config.banner}
|
||||||
|
analytics={config.analytics}
|
||||||
|
navigation={data.navigation}
|
||||||
|
fontCssVars={data.fontCssVars}
|
||||||
|
themeMode={config.theme.mode}
|
||||||
|
searchEnabled={config.search.enabled}
|
||||||
|
siteUrl={config.site}
|
||||||
|
ogEnabled={config.og.enabled}
|
||||||
|
structuredDataEnabled={config.structuredData}
|
||||||
|
page={{ title: `Progress - ${config.title}`, description, route: "/progress" }}
|
||||||
|
>
|
||||||
|
<section class="mx-auto w-full max-w-5xl px-6 py-16">
|
||||||
|
<h1 class="m-0 text-4xl font-semibold tracking-tight text-foreground">Progress</h1>
|
||||||
|
<p class="mt-3 max-w-3xl text-lg text-muted-foreground">{description}</p>
|
||||||
|
|
||||||
|
<div class="mt-10 flex flex-col gap-6">
|
||||||
|
<SolvedRing client:load />
|
||||||
|
<div class="grid gap-6 md:grid-cols-2">
|
||||||
|
<SubmissionHeatmap client:load />
|
||||||
|
<SubmissionChart client:load />
|
||||||
|
</div>
|
||||||
|
<TopicBubbles client:load />
|
||||||
|
<RecentSolves client:load />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</PageLayout>
|
||||||
Reference in new issue
Block a user