DEV Community

Cover image for Building a Lightweight Portfolio Dashboard with ProvChart & st-core Tokens
FSCSS tutorial for ProvChart

Posted on

Building a Lightweight Portfolio Dashboard with ProvChart & st-core Tokens

Open-source template: github.com/Figsh/dashboard-project

Most dashboard tutorials start the same way: pull in 40–150 KB of JavaScript, wait for hydration, and hope search engines eventually see the chart.

We wanted the opposite.

This is a dark portfolio dashboard that:

  • Renders charts with zero charting JavaScript on the page
  • Uses ProvChart to turn data into pure HTML + CSS
  • Keeps the original st-core.fscss design tokens for a consistent, high-end look
  • Stays crawlable, fast on first paint, and easy to theme

This article walks through how it was built and how you can reuse the template.


The problem with typical chart libraries

Approach Cost First paint SEO / crawl
JS Libs 40–150 KB+ JS After hydration Often missed
Hand-written CSS charts Fragile, limited points Instant Good
ProvChart 0 KB chart runtime Instant Excellent

ProvChart compiles your data into CSS custom properties and returns scoped HTML + CSS. The browser paints the shape with native CSS (clip-path, gradients, etc.). No chart library ships to the client.


Stack overview

  • ProvChart APIPOST /api/v1/generate{ html, css }
  • st-core tokens — the same CSS variables used by st-core.fscss
  • Vite — fast local dev and simple build
  • Tiny Node proxy — keeps the API key off the browser

Design tokens stay exactly as they were:

:root {
  --st-bg:       #080710;
  --st-surface:  #0f0e1c;
  --st-card:     #13122a;
  --st-accent:   #6c47ff;
  --st-accent-2: #a78bff;
  --st-green:    #00e5a0;
  --st-red:      #ff4d6a;
  --st-text:     #edeaff;
  --st-muted:    #5e5a82;
  --st-border:   rgba(108, 71, 255, 0.13);
}
Enter fullscreen mode Exit fullscreen mode

The UI (sidebar, KPIs, allocation bars, activity feed, profile dropdown) is pure CSS on top of these tokens. Charts are the only part that talks to an external service.


How ProvChart is wired in

1. Server-side proxy (key stays private)

// api/proxy-server.js (simplified)
const res = await fetch('https://provchart-api.devtem.org/api/v1/generate', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.PROVCHART_API_KEY,
  },
  body: JSON.stringify(payload),
});
Enter fullscreen mode Exit fullscreen mode

The browser only calls /api/chart. Never expose a live key in frontend bundles.

2. Client payload (real numbers, not 0–100)

{
  type: 'area',
  theme: 'midnight',
  height: 260,
  axisX: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Now'],
  series: [
    { name: 'Portfolio', color: '#6c47ff', points: [74200, 76800, , 84201] },
    { name: 'Benchmark', color: '#00c9b8', points: [72800, 74500, , 81000] },
  ],
  legend: true,
  grid: true,
}
Enter fullscreen mode Exit fullscreen mode

ProvChart auto-formats large values (20K, 1.3K, 2M, 1.09B…). You send raw numbers; you do not pre-format with k / M / B.

3. Inject HTML + CSS

const { html, css } = await res.json();
host.innerHTML = html;
// each chart gets its own <style> so instances never clobber each other
Enter fullscreen mode Exit fullscreen mode

Each host (#main-chart-host, #spark-btc-host, …) keeps a scoped style tag. That avoids the classic “last chart wins and the others go blank” bug.


Data shape: 9 points, clear narrative

Instead of 24 noisy points, every series uses 9 points with a deliberate arc:

  • Downfall — a clear dip
  • High rate — a strong recovery into “Now”

Example (1W portfolio):

portfolio: [74200, 76800, 75500, 72800, 71500, 76200, 79800, 82500, 84201]
//          Mon     Tue    Wed    Thu    Fri    Sat    Sun    Mon    Now
//                         ↘ dip ─────────↗ strong climb
Enter fullscreen mode Exit fullscreen mode

Labels stay short and aligned (MonNow). No client-side slicing or thinning.


Dashboard features in the template

  • Period tabs: 1D / 1W / 1M / 3M / 1Y (each re-requests ProvChart)
  • KPI row + overview stats strip
  • Main multi-series area chart (Portfolio vs Benchmark)
  • BTC / ETH spark area charts
  • Allocation bars + recent activity feed
  • Sidebar with profile dropdown
  • Live clock, responsive layout, same st-core visual language

Everything is vanilla JS modules + CSS. No React/Vue required.


Getting started

git clone https://github.com/Figsh/dashboard-project.git
cd dashboard-project
npm install

cp .env.example .env
# or export PROVCHART_API_KEY="your_api_key"
# add PROVCHART_API_KEY from https://chart.devtem.org/dashboard

# Terminal 1 — proxy
npm run proxy

# Terminal 2 — Vite
npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:5173.

Free tier note: ProvChart free accounts get a small number of generations per month.


Why this approach works

  1. First paint — charts appear with the CSS; no wait for a chart library.
  2. Bundle size — zero charting JS on the page.
  3. Crawlability — the chart structure is real HTML.
  4. Theme control — st-core tokens + ProvChart theme: "midnight" keep the look consistent.
  5. Security — API key only lives on the proxy / edge function.

You still get dynamic period switching and multi-series visuals; you just don’t pay the usual JavaScript tax.


Repo & next steps

Fork it, swap the datasets, point the proxy at your own backend, or pre-generate SVGs with the ProvChart GitHub Action for static docs.

Lightweight dashboards don’t have to look lightweight. With ProvChart and a solid token set, they can look like a product — and still load like a static page.

Top comments (0)