Skip to content

Commit 7667ab4

Browse files
aboydnwgadomski
andauthored
chore: Modularize frontend architecture and remove ORCA code (#33)
## Summary This PR refactors the contributor network visualization from a 3,400+ line monolithic `index.js` into a modular, maintainable architecture with 32 focused ES6 modules. The main entry point has been reduced by **~57%** (from 3,400+ lines to 1,505 lines), with complex logic extracted into dedicated, testable modules. This refactoring also includes significant code cleanup, removing **~500+ lines of ORCA-specific code** that was inherited from the original visualization but not used in our implementation. This includes ORCA data loading, ORCA-specific positioning logic, dual ring visualization, and highlight backgrounds. <sup>1</sup> *Note: Vite was initially added during development to test bundling, but we ultimately decided against it to reduce complexity and use native ES modules instead.* ### Code Cleanup: ORCA-Specific Code Removal **Removed:** - ORCA data loading and processing logic - ORCA-specific positioning (`RADIUS_CONTRIBUTOR_NON_ORCA`, `ORCA_PRESENT` flag) - Dual ring visualization (ORCA vs non-ORCA contributors) - ORCA highlight backgrounds and opacity reduction logic - ORCA-specific tooltip content - `orca_received` and `orca_impacted` data properties - Remaining contributors ring drawing (not used in our visualization) **Renamed for Clarity:** - `ORCA_RING_WIDTH` → `CONTRIBUTOR_RING_WIDTH` (generic contributor ring) - `createORCAVisual` → `createContributorNetworkVisual` - `debug-orca` flag → `debug-contributor-network` ### Architecture Changes #### 1. **Data Preparation Module** (`src/js/data/prepare.js`) - Extracted `prepareData()` function (~515 lines → 673 lines with documentation) - Handles all data transformation, normalization, and node creation - Returns structured data object instead of mutating global state - Includes comprehensive input validation and error handling #### 2. **Layout & Positioning Module** (`src/js/layout/positioning.js`) - Extracted `positionContributorNodes()` function (~117 lines → 179 lines) - Calculates contributor ring radius and positions nodes - Includes configuration constants and validation - Returns calculated values instead of mutating globals #### 3. **Render Orchestration Module** (`src/js/render/draw.js`) - Extracted `draw()` function (~166 lines → 198 lines) - Orchestrates the complete rendering pipeline - Uses dependency injection pattern for render functions - Includes validation and error checking ### Build System Changes #### Native ES Modules (No Bundler) - After testing Vite bundling, switched to use native ES modules instead #### Updated Build Process - Modified `src/contributor_network/cli.py` to copy `src/js/` directory to `dist/` - Updated HTML template to properly load ES modules with `type="module"` - Added module load event handling to ensure proper initialization order ## File Structure ``` contributor-network/ ├── python/ # Python backend │ ├── contributor_network/ # CLI package │ ├── tests/ # Python tests │ └── templates/ # Jinja2 HTML templates ├── js/ # JavaScript frontend │ ├── chart.js # Main D3.js visualization (was index.js) │ ├── index.js # Module re-exports │ ├── __tests__/ # JS tests │ ├── config/ # Theme and scales │ ├── data/ # Data preparation │ ├── render/ # Canvas rendering │ └── ... ├── assets/ # Static assets │ ├── css/ # Stylesheets │ ├── data/ # CSV data files │ ├── img/ # Images │ └── lib/ # Vendored D3 libraries ├── index.html # Entry point ├── pyproject.toml # Python config (points to python/) ├── package.json # JS config ├── config.toml, veda.toml # Project configs └── README.md, LICENSE, etc. ``` ## Migration Notes ### For Developers 1. **Import Paths:** All imports now use relative paths from `src/js/` 2. **Module Structure:** New code should follow the established module structure ### For Build Process The build command remains the same: ```bash uv run contributor-network build data dist ``` The build process now: 1. Copies CSV data files (`top_contributors.csv`, `repositories.csv`, `links.csv`) to the destination folder 2. Copies `index.js` (main entry point) to the destination 3. Copies `src/js/` modules to `{destination}/src/js/` for native ES module imports 4. Copies CSS, D3 library files, and images to the destination 5. Generates `index.html` from the Jinja2 template with proper ES module script tags (`type="module"`) --------- Co-authored-by: Pete Gadomski <pete.gadomski@gmail.com>
1 parent dbb86d3 commit 7667ab4

File tree

498 files changed

+11446
-3815
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

498 files changed

+11446
-3815
lines changed

.DS_Store

-6 KB
Binary file not shown.

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ jobs:
1919
git config user.name 'github-actions[bot]'
2020
git config user.email 'github-actions[bot]@users.noreply.github.com'
2121
git checkout -b build-data
22-
uv run contributor-network data data
23-
uv run contributor-network csvs data
22+
uv run contributor-network assets/data assets/data
23+
uv run contributor-network csvs assets/data
2424
git add .
2525
git commit -m "chore: update data"
2626
git push -u origin build-data

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ jobs:
2020
run: uv run mypy
2121
- name: Test
2222
run: uv run pytest
23+
- name: Build
24+
run: uv run contributor-network build assets/data dist

.github/workflows/pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- uses: actions/configure-pages@v5
2727
- uses: astral-sh/setup-uv@v6
2828
- name: Build
29-
run: uv run contributor-network build data dist
29+
run: uv run contributor-network build assets/data dist
3030
- uses: actions/upload-pages-artifact@v3
3131
with:
3232
path: "dist"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,8 @@ __marimo__/
215215
# Streamlit
216216
.streamlit/secrets.toml
217217

218+
# Node.js
219+
node_modules/
220+
221+
# macOS
222+
.DS_Store

CLAUDE.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,42 @@ uv run ruff check --fix .
3636

3737
# Run tests
3838
uv run pytest
39-
uv run pytest tests/test_config.py::test_function_name # Single test
39+
uv run pytest python/tests/test_config.py::test_function_name # Single test
4040
```
4141

4242
## Architecture
4343

4444
**Data flow**: GitHub API → Python CLI → JSON files → CSV files → D3.js visualization
4545

46-
- `src/contributor_network/cli.py` - Click-based CLI with 5 subcommands
47-
- `src/contributor_network/config.py` - Pydantic models for TOML configuration
48-
- `src/contributor_network/models.py` - Data models (Link, Repository)
49-
- `src/contributor_network/client.py` - GitHub API client wrapper
50-
- `index.js` - D3.js visualization (vanilla JS, no build step)
51-
- `templates/` - Jinja2 HTML templates
46+
### Folder Structure
47+
48+
```
49+
python/ # Python backend
50+
contributor_network/ # CLI package
51+
tests/ # Python tests
52+
templates/ # Jinja2 HTML templates
53+
js/ # JavaScript frontend
54+
chart.js # Main D3.js visualization
55+
config/ # Theme and scale configuration
56+
data/ # Data preparation and filtering
57+
render/ # Canvas rendering modules
58+
simulations/ # D3 force simulations
59+
...
60+
assets/ # Static assets
61+
css/ # Stylesheets
62+
data/ # CSV data files
63+
img/ # Images
64+
lib/ # Vendored D3 libraries
65+
```
66+
67+
### Key Files
68+
69+
- `python/contributor_network/cli.py` - Click-based CLI with 5 subcommands
70+
- `python/contributor_network/config.py` - Pydantic models for TOML configuration
71+
- `python/contributor_network/models.py` - Data models (Link, Repository)
72+
- `python/contributor_network/client.py` - GitHub API client wrapper
73+
- `js/chart.js` - D3.js visualization entry point
74+
- `python/templates/` - Jinja2 HTML templates
5275
- `config.toml`, `veda.toml` - Repository and contributor configuration
5376

5477
## Code Style

README.md

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ This visual is derived from the excellent [ORCA top-contributor-network](https:/
1616
### View Locally
1717

1818
```shell
19-
cd dist
2019
python -m http.server 8000
2120
```
2221

23-
Then open <http://localhost:8000/>.
22+
Then open <http://localhost:8000/> (the root index.html)
2423

2524
## CLI Commands
2625

@@ -51,7 +50,7 @@ Fetch contribution data from GitHub for all configured repositories:
5150

5251
```shell
5352
export GITHUB_TOKEN="your_token_here"
54-
uv run contributor-network data data
53+
uv run contributor-network assets/data assets/data
5554
```
5655

5756
Options:
@@ -62,15 +61,15 @@ Options:
6261
Generate CSV files from the fetched JSON data:
6362

6463
```shell
65-
uv run contributor-network csvs data
64+
uv run contributor-network csvs assets/data
6665
```
6766

6867
### `build`
6968

7069
Build the static site to the `dist/` folder:
7170

7271
```shell
73-
uv run contributor-network build data dist
72+
uv run contributor-network build assets/data dist
7473
```
7574

7675
## Full Workflow
@@ -87,13 +86,13 @@ uv run contributor-network discover --min-contributors 2
8786
# 3. Edit config.toml to add/remove repos or contributors
8887

8988
# 4. Fetch data from GitHub
90-
uv run contributor-network data data
89+
uv run contributor-network assets/data assets/data
9190

9291
# 5. Generate CSVs
93-
uv run contributor-network csvs data
92+
uv run contributor-network csvs assets/data
9493

9594
# 6. Build the site
96-
uv run contributor-network build data dist
95+
uv run contributor-network build assets/data dist
9796

9897
# 7. Preview locally
9998
cd dist && python -m http.server 8000
@@ -109,6 +108,46 @@ Edit `config.toml` to configure:
109108

110109
## Development
111110

111+
### Architecture
112+
113+
The visualization code is organized into modular ES6 modules in `src/js/`:
114+
115+
```
116+
src/js/
117+
├── config/ # Configuration (theme, scales)
118+
├── data/ # Data filtering and utilities
119+
├── interaction/ # Mouse hover and click handling
120+
├── layout/ # Canvas sizing and layout
121+
├── render/ # Drawing functions (shapes, text, labels)
122+
├── simulations/ # D3 force simulations
123+
├── state/ # State management
124+
├── utils/ # Utilities (helpers, validation, formatters, debug)
125+
└── __tests__/ # Unit tests
126+
```
127+
128+
The main entry point is `index.js` which:
129+
1. Loads dependencies (D3, etc.)
130+
2. Imports all modular components
131+
3. Exports `createContributorNetworkVisual` function
132+
133+
The visualization is used in `dist/index.html` to render the interactive network.
134+
135+
### Running Tests
136+
137+
```shell
138+
npm test
139+
```
140+
141+
Tests use Vitest and cover filtering, validation, and utility functions.
142+
143+
### Making Changes
144+
145+
When modifying the visualization:
146+
1. Edit files in `src/js/`
147+
2. Changes are immediately available in the browser (no build step needed)
148+
3. Refresh `http://localhost:8000/` to see updates
149+
4. Run `npm test` to verify changes don't break tests
150+
112151
### Code Quality
113152

114153
```shell

css/style.css renamed to assets/css/style.css

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,14 +362,63 @@ li#item-remaining::before {
362362
/*************** CHART ***************/
363363
/*************************************/
364364

365-
/* This is all done within the createORCAVisual function */
365+
/* This is all done within the createContributorNetworkVisual function */
366366

367367
#chart-container {
368368
position: relative;
369369
background-color: var(--color-background);
370370
width: 100%;
371371
min-height: 800px;
372372
padding: 20px;
373+
box-sizing: border-box;
374+
overflow: hidden;
375+
}
376+
377+
#chart-zoom-controls {
378+
position: absolute;
379+
top: 16px;
380+
right: 16px;
381+
display: flex;
382+
flex-direction: column;
383+
gap: 8px;
384+
z-index: 10;
385+
}
386+
387+
#chart-zoom-controls button {
388+
width: 36px;
389+
height: 36px;
390+
border-radius: 6px;
391+
border: 1px solid #ddd;
392+
background: #fff;
393+
color: #443F3F;
394+
font-size: 20px;
395+
font-weight: 700;
396+
line-height: 1;
397+
cursor: pointer;
398+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
399+
transition: transform 120ms ease, border-color 120ms ease;
400+
}
401+
402+
#chart-zoom-controls svg {
403+
width: 18px;
404+
height: 18px;
405+
display: block;
406+
margin: 0 auto;
407+
}
408+
409+
#zoom-reset {
410+
width: 36px;
411+
height: 36px;
412+
padding: 0;
413+
}
414+
415+
#chart-zoom-controls button:hover {
416+
border-color: #CF3F02;
417+
transform: translateY(-1px);
418+
}
419+
420+
#chart-zoom-controls button:active {
421+
transform: translateY(0);
373422
}
374423

375424
#chart-zoom-controls {
@@ -379,7 +428,7 @@ li#item-remaining::before {
379428
display: flex;
380429
flex-direction: column;
381430
gap: 8px;
382-
z-index: 2;
431+
z-index: 10;
383432
}
384433

385434
#chart-zoom-controls button {
@@ -421,12 +470,12 @@ li#item-remaining::before {
421470

422471
#chart-container canvas {
423472
display: block;
424-
margin: 0;
425473
}
426474

427475
#canvas, #canvas-click {
428476
position: absolute;
429477
top: 0;
478+
left: 0;
430479
pointer-events: none;
431480
z-index: 0;
432481
transition: opacity 200ms ease-in;

0 commit comments

Comments
 (0)