Metadata-Version: 2.4
Name: als-computing-icons
Version: 0.2.3
Summary: ALS Computing icon library for Python, Dash, and Jupyter
Project-URL: Homepage, https://github.com/als-computing/publish-npm-icons
Project-URL: Repository, https://github.com/als-computing/publish-npm-icons
License: MIT
Keywords: als,beamline,computing,figma,icons,svg
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics
Classifier: Typing :: Typed
Requires-Python: >=3.8
Provides-Extra: dash
Requires-Dist: dash>=2.0; extra == 'dash'
Description-Content-Type: text/markdown

# ALS Computing Icons

**ALS Computing Icons** is a collection of SVG icons exported from Figma, automatically optimized and published to both **npm** and **PyPI** on every push to `main`.

- **npm:** `@als-computing/icons`
- **PyPI:** `als-computing-icons`

Every icon is processed with SVGO and has black fills replaced with `currentColor` so you can tint them from CSS.

---

## Table of Contents

1. [How the pipeline works](#how-the-pipeline-works)
2. [Adding or updating icons](#adding-or-updating-icons)
   - [Option A — Figma export (recommended)](#option-a--figma-export-recommended)
   - [Option B — Manual SVG drop](#option-b--manual-svg-drop)
3. [One-time setup (do this once when forking / first deploying)](#one-time-setup)
   - [npm Automation token](#1-create-an-npm-automation-token)
   - [PyPI API token](#2-create-a-pypi-api-token)
   - [GitHub personal access token (AUTO_MERGE_PAT)](#3-create-a-github-personal-access-token-auto_merge_pat)
   - [Add secrets to GitHub](#4-add-all-tokens-to-github-secrets)
   - [Allow Actions to push back to the repo](#5-allow-actions-to-write-to-the-repo)
   - [Configure the IconBridge Figma plugin](#6-configure-the-iconbridge-figma-plugin)
4. [Using the npm package](#using-the-npm-package)
5. [Using the PyPI package](#using-the-pypi-package)
6. [Local development](#local-development)
7. [Folder structure](#folder-structure)
8. [Troubleshooting](#troubleshooting)
9. [License](#license)

---

## How the pipeline works

```
You export SVGs from Figma (IconBridge plugin)  ──OR──  drop SVGs into assets/
        │
        ▼
  git push to main
        │
        ▼
  GitHub Actions
        │
        ├─ npm run optimize   → optimized-assets/  (SVGO + currentColor)
     ├─ npm run build      → dist/ + Dash bundle + Python package files
        │
        ├─ If anything in dist/ changed:
        │     ├─ Bump patch version in package.json
        │     ├─ git commit + tag + push  (uses AUTO_MERGE_PAT)
        │     ├─ Publish to npm  (@als-computing/icons)
        │     ├─ Create GitHub Release
        │     └─ Publish to PyPI (als-computing-icons)
        │
        └─ Done — both packages now have the new icons
```

The version number is always kept in sync: whatever patch version npm bumps to, the Python package gets the exact same version.

---

## Adding or updating icons

### Option A — Figma export (recommended)

Use the **IconBridge – Automated Icon Handoff from Figma to GitHub** plugin to push icons directly from Figma into the `assets/` folder of this repo.

> **Before you start:** Your icons must be Figma **components** (they appear with a purple outline in the layers panel). To convert an icon to a component, right-click it and select **Create component**.

1. In Figma, select all the icon components you want to export (Cmd/Ctrl + click).
2. Open the **IconBridge** plugin (right-click → Plugins → IconBridge, or use the bottom toolbar).
3. In the **Export Icon** tab your selected icons should appear. If not, click **Sync**.
4. Scroll down and click **Export to GitHub**.
5. The plugin commits the SVGs to `assets/` and GitHub Actions takes over automatically.

You can watch the pipeline run under the **Actions** tab of the repository.

### Option B — Manual SVG drop

1. Copy your `.svg` files into the **`assets/`** folder.
2. Commit and push to `main`.
3. The GitHub Actions workflow runs automatically. No manual steps needed.

> **Tip:** File names become Python/JS variable names. Spaces and special characters are replaced with underscores. For example, `linear stage.svg` becomes `linear_stage`.

---

## One-time setup

Do these steps once when you first set up this repo (or fork it). After that, every push is fully automatic.

---

### 1. Create an npm Automation token

> You need this so GitHub Actions can publish to npm **without** triggering a one-time password (OTP) prompt. A regular "Publish" token will fail with `EOTP` in CI — Automation tokens are specifically designed to skip OTP.

1. Log in at [npmjs.com](https://www.npmjs.com).
2. Click your profile picture (top-right) → **Access Tokens**.
3. Click **Generate New Token** → choose **Granular Access Token**.
   - **Token name:** e.g. `github-actions-publish`
   - **Expiration:** set to your preference (365 days is common)
   - **Bypass two-factor authentication (2FA):** ✅ **check this box** — this is what allows CI to publish without an OTP prompt
   - **Packages and scopes:** select **Read and write**
   - **Organizations:** grant access to `als-computing` with **Read and write**
4. Click **Generate Token** and **copy it immediately** — you won't see it again.

---

### 2. Create a PyPI API token

> First-time publishing requires an account-scoped token because the project doesn't exist yet on PyPI. After the first successful publish you can optionally narrow it to just the `als-computing-icons` project.

1. Log in at [pypi.org](https://pypi.org).
2. Click your username (top-right) → **Account settings**.
3. Scroll to **API tokens** → click **Add API token**.
   - **Token name:** e.g. `github-actions`
   - **Scope:** **Entire account** (for the first publish; change to project-scoped after)
4. Click **Create token** and **copy it immediately** — it starts with `pypi-`.

---

### 3. Create a GitHub personal access token (AUTO_MERGE_PAT)

The workflow commits the bumped version and built files back to the repo. This requires a personal access token (PAT) stored as `AUTO_MERGE_PAT`.

1. On GitHub, click your profile → **Settings** → scroll to the bottom → **Developer settings**.
2. Go to **Personal access tokens** → **Tokens (classic)**.
3. Click **Generate new token (classic)**.
   - **Note:** e.g. `auto-merge-als`
   - **Expiration:** set to your preference
   - **Scopes:** check **repo** (all sub-scopes) and **workflow**
4. Click **Generate token** and **copy it immediately**.

---

### 4. Add all tokens to GitHub Secrets

1. Go to your GitHub repository → **Settings** → **Secrets and variables** → **Actions**.
2. Click **New repository secret** and add each one:

| Secret name | Value |
|---|---|
| `NPM_TOKEN` | The npm Automation token from step 1 |
| `PYPI_TOKEN` | The PyPI API token from step 2 |
| `AUTO_MERGE_PAT` | The GitHub classic PAT from step 3 |

> Secret names must match exactly — the workflow references them by these names.

> **Important:** Make sure **GitHub Actions is enabled** for the repository before adding secrets (repo **Settings** → **Actions** → **General**).

---

### 5. Allow Actions to write to the repo

The workflow bumps the version, commits `dist/` and `package.json`, and pushes a git tag. GitHub blocks this by default.

1. In your repo, go to **Settings** → **Actions** → **General**.
2. Scroll to **Workflow permissions**.
3. Select **Read and write permissions**.
4. Click **Save**.

---

### 6. Configure the IconBridge Figma plugin

This step connects the Figma plugin to your repository so icons can be exported directly from Figma.

1. In Figma, install the **IconBridge – Automated Icon Handoff from Figma to GitHub** plugin.
2. Open the plugin and go to the **GitHub Settings** tab.
3. Fill in the fields:
   - **GitHub Token:** paste the `AUTO_MERGE_PAT` classic PAT you created in step 3
   - **Repository:** `als-computing/publish-npm-icons`
   - **Path (optional):** `assets`
4. Click **Save Settings**.

---

## Using the npm package (JavaScript / React)

```sh
npm install @als-computing/icons
```

```js
// ESM
import { motor, cluster } from '@als-computing/icons';

// CommonJS
const { motor } = require('@als-computing/icons');

// Render in React
<span dangerouslySetInnerHTML={{ __html: motor }} style={{ color: 'red' }} />
```

**React component example:**

```jsx
import React from 'react';
import { motor, cluster } from '@als-computing/icons';

export default function IconDemo() {
   return (
      <div style={{ display: 'flex', gap: 12, color: 'steelblue' }}>
         <span dangerouslySetInnerHTML={{ __html: motor }} />
         <span dangerouslySetInnerHTML={{ __html: cluster }} />
      </div>
   );
}
```

---

## Using the PyPI package (Python)

```sh
pip install als-computing-icons
```

```python
from als_computing_icons import motor, cluster

# Each variable is the raw SVG string
print(motor)  # <svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>
```

**Lookup by icon name:**

```python
from als_computing_icons import get_icon, icon_names

print(icon_names())
print(get_icon("motor"))
print(get_icon("beamstopx"))  # case-insensitive lookup
```

**Rendering in a Jupyter notebook:**

```python
from IPython.display import HTML
from als_computing_icons import motor

HTML(f'<span style="color: steelblue; font-size: 48px">{motor}</span>')
```

## Using in Dash

### Native Dash component (recommended)

```python
from dash import Dash, html
from als_computing_icons import ALSIcon, als_icon

app = Dash(__name__)
app.layout = html.Div([
   ALSIcon(icon="motor", color="steelblue", width=48),
   ALSIcon(icon="cluster", color="currentColor", width=48),
   als_icon("beamstopX", color="#ff5656", width=48),
])

if __name__ == "__main__":
    app.run(debug=True, port=8050)
```

### Legacy helper (still supported)

```python
from als_computing_icons import motor, icon_img

icon_img(motor, color="#333", width=36)
```

---

## Local development

```sh
# Install JS dependencies
npm install

# Optimize SVGs (assets/ → optimized-assets/)
npm run optimize

# Build the JS/TS package (optimized-assets/ → dist/)
npm run build

# Run Dash smoke test example locally
PYTHONPATH=./python python examples/dash_app_test.py

# Build and package the Python wheel locally
cd python && python3 -m build
```

---

## Folder structure

```
assets/                   ← DROP YOUR SVGs HERE (or export via IconBridge)
optimized-assets/         ← auto-generated by `npm run optimize`
dist/                     ← auto-generated JS/TS package output
python/
  pyproject.toml          ← Python package config (hatchling)
  als_computing_icons/
      ALSIcon.py            ← native Dash component wrapper
    __init__.py           ← auto-generated, one variable per icon
      dist/                 ← Dash JS bundle served by Dash app
    py.typed              ← PEP 561 type marker
scripts/
  optimize-svg.js         ← SVGO pass; replaces black → currentColor
  build.js                ← generates dist/ (JS/TS)
  build_python.js         ← generates python/als_computing_icons/__init__.py
  sync-assets.js          ← optional Figma sync helper
.github/workflows/
   trigger-build.yml       ← the main CI pipeline
package.json
```

---

## Troubleshooting

| Error | Cause | Fix |
|---|---|---|
| `npm error code EOTP` | npm token does not bypass 2FA | Re-create the npm token and check the **Bypass two-factor authentication** box |
| `403 Forbidden` on PyPI | Token is project-scoped but project doesn't exist yet | Use an **Entire account** scoped token for the first publish |
| `HttpError: Resource not accessible by integration` | Actions don't have write permission | Enable **Read and write permissions** in repo Settings → Actions → General |
| Dash app is blank / icons don't render | Dash component bundle not loaded | Ensure package version includes the Dash metadata fix (>= `0.2.1`) and hard-refresh the browser |
| `optimized-assets/ missing or empty` | SVGs weren't committed to `assets/` | Add `.svg` files to `assets/` and push, or re-export via IconBridge |
| Python variable name clash | Two SVG files sanitise to the same identifier | Rename one of the source files to make names unique |
| Icons don't appear in IconBridge "Export Icon" tab | Icon is not a Figma component | Right-click the icon → **Create component**, then click **Sync** in the plugin |
| IconBridge export fails | GitHub token missing or incorrect repo path | Check the **GitHub Settings** tab in IconBridge — verify token, repo, and path |

---

## License

MIT © ALS Computing