Harkje is a small Vite + React app for generating and visualizing organizational charts.
It includes:
- A sidebar for generating or editing the org structure as a flat list.
- A D3-based org chart renderer with pan/zoom, click-to-collapse, and PNG export.
- A local, deterministic random generator (no API keys, no external services).
Public repository (PRs welcome):
- Vite + React + TypeScript
- D3 (
d3) for layout rendering and zoom/pan html-to-imagefor exporting the chart as PNG- Tailwind via CDN (see
index.html)
Harkje has two separate theme systems:
- Site theme (Light / Dark): affects the app UI (sidebar + toolbar).
- Chart theme (Light / Soft / Warm / Pencil / Classic / Dark / High Contrast): affects the org chart renderer and PNG export.
- UI theme tokens are defined as CSS variables in
index.html(the--ui-*tokens). - The active site theme is applied by setting
data-site-theme="..."on the<html>element. - The selection is persisted in
localStorageunderharkje.siteTheme.
Harkje supports a small built-in chart theme system (Light / Soft / Warm / Pencil / Classic / Dark / High Contrast) that works with the org chart renderer and PNG export.
- Theme tokens are defined as CSS variables in
index.html(using[data-chart-theme="..."]). - The active theme is applied to the chart by setting
data-chart-theme="..."on the chart container element. - The selection is persisted in
localStorageunderharkje.chartTheme.
Adding a new theme:
- Add a new
[data-chart-theme="yourThemeId"] { ... }block inindex.htmlwith the same token names. - Add the theme id + label to
CHART_THEMESintheme.tsx.
Note: for SVG link lines the app resolves --chart-link to a concrete color at runtime (more reliable for export).
Key files:
index.tsx: React entrypointApp.tsx: top-level state + layout (sidebar + chart)components/InputPanel.tsx: generator/editor UI; converts between flat list and treecomponents/OrgChart.tsx: custom layout engine + SVG rendering + exportservices/geminiService.ts: local org generator (keeps historical name)types.ts:OrgNode,FlatNode,LayoutDirection
There are two representations of the org:
- Tree (
OrgNode) used by the chart renderer (nested viachildren). - Flat list (
FlatNode[]) used by the editor/generator (parentIdpoints to a manager id; the root usesparentId: "null"ornull).
InputPanel keeps these in sync:
flattenTree()convertsOrgNode→FlatNode[]for the editor.buildTree()convertsFlatNode[]→OrgNodefor rendering.
The sidebar includes a List Editor that edits the org as a JSON array of FlatNode objects.
- Use
"parentId": "null"(string) or"parentId": nullfor the root. - Keep
idvalues as strings.
Example:
[
{"id":"1","parentId":"null","name":"Jane Doe","title":"CEO","department":"Executive","details":"Leads the company"},
{"id":"2","parentId":"1","name":"John Smith","title":"Engineering Manager","department":"Engineering","details":"Runs the platform team"}
]Note: if the input implies multiple roots (e.g. missing/unknown managers), the app will pick a best-effort root (heuristic prefers titles like "CEO").
Prerequisites:
- Node.js 20+ (recommended)
Install and run:
npm install
npm run devThen open the dev server URL (default: http://localhost:3000).
Note: don’t run the source with VS Code “Live Server”. The app entry is index.tsx, which needs Vite to bundle/transpile.
npm run dev # Start dev server
npm run build # Build to dist/
npm run preview # Preview the production build locallyThe generator lives in services/geminiService.ts (name kept to avoid churn). It exports:
generateOrgStructure(description: string): produces a deterministic randomized org seeded by the description.generateRandomOrgStructure(size, theme): produces a deterministic randomized org based on size/theme.
Both return a FlatNode[] that forms a valid tree with exactly one root.
The chart component exposes an imperative ref API:
exportImage(): exports the current chart viewport to a PNG usinghtml-to-image.
Export details:
- The exported PNG is cropped to the chart bounds.
- The PNG background is transparent (good for presentations).
- The export reflects the current theme for node cards and link lines.
The download button in App.tsx calls this method.
The floating toolbar in the top-right provides:
- Site theme selector (Light / Dark)
- Chart theme selector (Light / Soft / Warm / Pencil / Classic / Dark / High Contrast)
- Target aspect ratio slider: influences how the layout engine wraps/grids large child groups
- Download image: exports a PNG
This repo includes a GitHub Actions workflow that builds and deploys dist/ to GitHub Pages:
.github/workflows/deploy-pages.yml
Setup:
- Push to
main. - In GitHub: Settings → Pages.
- Under Build and deployment, set Source to GitHub Actions.
Your site will be published at:
https://<owner>.github.io/<repo>/
Common extension points:
- Node card UI: update the HTML template in
components/OrgChart.tsx. - Layout behavior: update
computeBalancedLayout()incomponents/OrgChart.tsx. - Input fields: extend
FlatNode/OrgNodeintypes.ts, then updateflattenTree()+buildTree().