@glossarist/concept-browser 0.7.6 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,28 +1,45 @@
1
- # Glossarist Vocabulary Browser
1
+ # Glossarist Concept Browser
2
2
 
3
- A statically deployable single-page application for browsing ISO/IEC terminology datasets. Built with Vue 3, TypeScript, and Tailwind CSS. Add new datasets with zero code changes — just edit `datasets.yml`.
3
+ A statically deployable single-page application for browsing terminology datasets. Built with Vue 3, TypeScript, and Tailwind CSS. Add new datasets with zero code changes — just configure `site-config.yml`.
4
4
 
5
- **Live site:** <https://www.geolexica.org>
6
-
7
- Glossarist is the software; deployment to `www.geolexica.org` happens through the [geolexica.org](https://github.com/geolexica/geolexica.org) repository, which sources the built SPA and deploys via S3 + CloudFront.
5
+ **Live sites:**
6
+ - [GeoLexica](https://www.geolexica.org) — IEC Electropedia + ISO/TC 211 + more
7
+ - [VIML](https://metanorma.github.io/oiml-viml/) OIML International Vocabulary of Legal Metrology
8
+ - [OIML Terms](https://metanorma.github.io/oiml-terms/) — OIML G 18 terminology
8
9
 
9
10
  ---
10
11
 
11
12
  ## Features
12
13
 
13
14
  - **Multi-dataset browsing** — Concepts from multiple terminology registers in one place
14
- - **Full multilingual support** — Definitions, notes, and examples in all available languages
15
+ - **Full multilingual support** — Definitions, notes, and examples in all available languages with i18n UI
15
16
  - **Concept history timeline** — Review dates, decisions, and change notes per language
16
17
  - **Cross-reference graph** — D3 force-directed graph showing concept relationships with dataset filtering
18
+ - **Rich sidebar provenance** — Publication reference, owner, status, concept/language counts from manifest data
17
19
  - **Math rendering** — KaTeX rendering for AsciiMath notation in definitions (`stem:[...]`)
18
- - **Responsive design** — Mobile-first layout with integrated navigation
20
+ - **Responsive design** — Mobile-first layout with light/dark mode
19
21
  - **Static deployment** — No server required. Deploy to any static host
20
22
 
21
23
  ---
22
24
 
23
- ## Quick Start
25
+ ## Quick Start (deployment repo)
26
+
27
+ A deployment repo is a separate repository that provides a `site-config.yml`, dataset source files, and content pages. The concept-browser is installed as an npm package.
24
28
 
25
29
  ```bash
30
+ # In your deployment repo:
31
+ npm install --ignore-scripts @glossarist/concept-browser
32
+ npm install --prefix node_modules/@glossarist/concept-browser sharp 2>/dev/null || true
33
+ npx concept-browser build
34
+ ```
35
+
36
+ The CLI reads `site-config.yml` from the working directory, fetches/generates data, and builds the SPA into `dist/`.
37
+
38
+ ### Quick Start (development)
39
+
40
+ ```bash
41
+ git clone https://github.com/glossarist/concept-browser.git
42
+ cd concept-browser
26
43
  npm install
27
44
  npm run dev
28
45
  # Open http://localhost:5173
@@ -32,317 +49,250 @@ The dev server serves pre-built data from `public/data/`. If no data is present
32
49
 
33
50
  ---
34
51
 
35
- ## Commands
52
+ ## CLI Reference
36
53
 
37
- | Command | Description |
38
- |---------|-------------|
39
- | `npm run dev` | Start Vite dev server on port 5173 |
40
- | `npm run build` | Type-check (`vue-tsc`) + Vite build + generate `404.html` |
41
- | `npm run preview` | Preview production build locally |
42
- | `npm test` | Run tests (Vitest with happy-dom) |
43
- | `npm run test:watch` | Run tests in watch mode |
44
- | `npm run fetch-datasets` | Clone/update source repos, harmonize concepts to canonical YAML |
45
- | `npm run generate-data` | Convert harmonized YAML → JSON-LD static files |
46
- | `npm run build:full` | Full pipeline: fetch + generate + build-edges + build |
54
+ ```
55
+ concept-browser <command> [options]
56
+
57
+ Commands:
58
+ fetch Fetch/update datasets (from GCR packages, local paths, or source repos)
59
+ generate Convert harmonized YAML concepts to JSON-LD static files
60
+ edges Build cross-reference edges from generated concept data
61
+ build Full pipeline: fetch + generate + edges + vite build
62
+ site Same as build (alias)
63
+
64
+ Options:
65
+ --site <id> Site config ID (looks for site-config.yml in CWD)
66
+
67
+ Environment:
68
+ SITE_CONFIG Site config file path (highest priority)
69
+ SITE_ID Site config ID (same as --site)
70
+ GITHUB_TOKEN GitHub token for private repos
71
+ ```
47
72
 
48
73
  ---
49
74
 
50
75
  ## Data Pipeline
51
76
 
52
77
  ```
53
- datasets.yml
54
- └─> scripts/fetch-datasets.mjs (clone + harmonize)
78
+ site-config.yml
79
+ └─> scripts/fetch-datasets.mjs (fetch from GCR, localPath, or sourceRepo)
55
80
  └─> .datasets/{id}/concepts/*.yaml
56
- └─> scripts/generate-data.mjs (YAML → JSON-LD)
81
+ └─> scripts/generate-data.mjs (YAML → JSON-LD)
57
82
  └─> public/data/{id}/
58
- ├── manifest.json Dataset metadata
83
+ ├── manifest.json Dataset metadata (ref, owner, stats)
59
84
  ├── index.json Concept listing (chunked for large sets)
60
85
  ├── edges.json Pre-computed cross-reference + domain edges
61
86
  ├── domain-nodes.json Domain classification nodes
62
87
  └── concepts/*.json Individual concept documents
63
- └─> scripts/build-edges.js (extract graph + domain edges)
88
+ └─> scripts/build-edges.js (extract graph + domain edges)
64
89
  ```
65
90
 
66
- ### Step-by-step
91
+ ---
67
92
 
68
- ```bash
69
- # 1. Fetch source repos and harmonize concepts
70
- npm run fetch-datasets
93
+ ## Configuration: `site-config.yml`
71
94
 
72
- # 2. Generate static JSON-LD data files
73
- npm run generate-data
95
+ All configuration lives in a single file. The CLI reads it from the current working directory.
74
96
 
75
- # 3. Pre-compute cross-reference edges
76
- node scripts/build-edges.js
97
+ ### Top-level fields
77
98
 
78
- # 4. Build the SPA
79
- npm run build
99
+ ```yaml
100
+ id: viml # Site identifier
101
+ domain: viml.oiml.info # Primary domain
102
+ basePath: /oiml-viml/ # URL subpath for GitHub Pages deployment
103
+ title: VIML # Site title
104
+ subtitle: International Vocabulary... # Short description
105
+ description: Terminology from... # Longer description
106
+
107
+ uiLanguages: # Available UI languages
108
+ - code: eng
109
+ label: English
110
+ - code: fra
111
+ label: Français
112
+
113
+ translations: # Localized title/subtitle/description
114
+ fra:
115
+ subtitle: Vocabulaire international de métrologie légale
116
+ description: Terminologie du Vocabulaire international...
117
+
118
+ defaults:
119
+ language: eng # Default concept language
120
+
121
+ copyright: "OIML" # Footer copyright text
80
122
  ```
81
123
 
82
- Or use the single-command pipeline:
124
+ ### Dataset configuration
83
125
 
84
- ```bash
85
- npm run build:full
126
+ ```yaml
127
+ datasets:
128
+ - id: viml
129
+ uri: "urn:oiml:pub:v:1:2022"
130
+ sourceRepo: https://github.com/metanorma/oiml-viml
131
+ localPath: viml-glossarist # Local dataset directory (relative to CWD)
132
+ title: "VIML — International Vocabulary of Legal Metrology"
133
+ description: "Terminology definitions from..."
134
+ owner: OIML
135
+ ref: "OIML V 1:2022" # Publication reference (shown in sidebar provenance)
136
+ color: "#004996"
137
+ tags: [metrology, legal, oiml]
138
+ languageOrder: [eng, fra]
86
139
  ```
87
140
 
88
- ### Local dataset override
89
-
90
- To use a local checkout instead of cloning from GitHub:
141
+ #### Dataset field reference
91
142
 
92
- ```bash
93
- DATASET_SOURCE_IEV=/path/to/local/iev-data npm run fetch-datasets
94
- ```
95
-
96
- Replace `IEV` with the uppercase dataset ID.
143
+ | Field | Required | Description |
144
+ |-------|----------|-------------|
145
+ | `id` | yes | URL-safe identifier used in routes and data paths |
146
+ | `uri` | no | URI pattern for this dataset |
147
+ | `sourceRepo` | no | Git repository URL containing concept YAML files |
148
+ | `gcrPackage` | no | URL to a pre-built `.gcr` ZIP archive (alternative to sourceRepo) |
149
+ | `localPath` | no | Local directory with `concepts/` and `register.yaml` (relative to CWD) |
150
+ | `title` | no | Display name. Falls back to `register.yaml` name field |
151
+ | `description` | no | Shown on home page and about page |
152
+ | `owner` | no | Organization name shown in sidebar provenance |
153
+ | `ref` | no | Publication reference shown in sidebar provenance (e.g., "OIML V 1:2022") |
154
+ | `color` | no | Hex color for UI accent. Auto-assigned if omitted |
155
+ | `tags` | no | Array of labels shown on dataset card |
156
+ | `languageOrder` | no | Array of ISO 639-2 codes controlling display order |
157
+ | `translations` | no | Localized title and description per language |
97
158
 
98
- ---
159
+ #### Dataset source resolution
99
160
 
100
- ## Configuration: `datasets.yml`
161
+ The CLI resolves dataset sources in this priority order:
101
162
 
102
- All dataset configuration lives in a single file. Adding a new dataset requires **zero code changes** just add an entry to `datasets.yml` and run the pipeline.
163
+ 1. **`.gcr/{id}.gcr`** on diskextract to `.datasets/{id}/`
164
+ 2. **`gcrPackage`** URL — download and extract
165
+ 3. **`localPath`** — copy `concepts/` and `register.yaml` from a local directory
166
+ 4. **`sourceRepo`** — git clone to `.datasets/{id}/`
103
167
 
104
- ### Branding and favicon
168
+ ### Base path for subpath deployment
105
169
 
106
- The `site-config.yml` `branding` section controls the site's visual identity:
170
+ Set `basePath` in `site-config.yml` to deploy to a subdirectory (e.g., GitHub Pages at `metanorma.github.io/my-site/`):
107
171
 
108
172
  ```yaml
109
- branding:
110
- primaryColor: "#d97706"
111
- darkColor: "#1a1a2e"
112
- logo:
113
- path: /logos/my-logo.svg # URL path served to browsers
114
- alt: "My Org"
115
- localPath: logos/my-logo.svg # Local file used as favicon source
116
- favicon: logos/my-favicon.svg # Optional — overrides logo.localPath for favicon generation
173
+ basePath: /my-site/
117
174
  ```
118
175
 
119
- During build, favicons are auto-generated from a single SVG source using the [`favicons`](https://npmjs.com/package/favicons) package. The resolution order is:
176
+ This configures Vite's `base` so all asset paths, router paths, and data fetches use the correct prefix. The `BASE_PATH` environment variable can override this if needed.
120
177
 
121
- 1. `branding.favicon` explicit path to favicon source SVG
122
- 2. `branding.logo.localPath` — falls back to the site logo
123
- 3. Package default `public/favicon.svg`
124
-
125
- The build produces: `favicon.ico`, `favicon.svg`, `favicon-{16,32,48}x{16,32,48}.png`, `apple-touch-icon-*.png` (all standard iOS sizes), and injects the corresponding `<link>` and `<meta>` tags into `index.html` via a Vite plugin.
126
-
127
- ### Full reference
178
+ ### Branding and favicon
128
179
 
129
180
  ```yaml
130
- datasets:
131
- - id: my-dataset # required — URL-safe identifier
132
- sourceRepo: https://github.com/org/repo # required — Git repo with concept YAML
133
- # OR use a pre-built GCR package:
134
- gcrPackage: https://github.com/org/repo/releases/latest/download/pkg.gcr
135
-
136
- title: "My Glossary" # optional — falls back to register.yaml name
137
- description: "Description of dataset" # optional — shown on home and about pages
138
- owner: My Organization # optional — shown in badges and about page
139
- color: "#6366f1" # optional — hex color for UI accent (default: auto-assigned)
140
- tags: [tag1, tag2] # optional — shown on dataset card
141
- existingSiteUrl: https://example.org # optional — link to existing site for this dataset
142
- externalConceptUrlTemplate: "https://example.org/concepts/{conceptId}/" # optional — per-concept external link
143
- languageOrder: [eng, fra, deu, spa] # optional custom language tab ordering
181
+ branding:
182
+ primaryColor: "#004996"
183
+ darkColor: "#003366"
184
+ fonts:
185
+ header:
186
+ family: "Source Serif 4"
187
+ source: "google"
188
+ weights: [400, 600]
189
+ body:
190
+ family: "Source Sans 3"
191
+ source: "google"
192
+ weights: [400, 500, 700]
193
+ logo:
194
+ path: /logos/oiml-logo.svg # URL path served to browsers
195
+ alt: OIML
196
+ localPath: logos/oiml-logo.svg # Local file for favicon generation
197
+ localLight: logos/oiml-logo-icon-light.svg # Light variant (dark mode)
198
+ localDark: logos/oiml-logo-icon-dark.svg # Dark variant (light mode)
199
+ ownerName: OIML
200
+ ownerUrl: "https://www.oiml.org"
144
201
  ```
145
202
 
146
- ### Field details
147
-
148
- | Field | Required | Description |
149
- |-------|----------|-------------|
150
- | `id` | yes | URL-safe identifier used in routes (`/dataset/{id}/concept/...`) and data paths (`public/data/{id}/`) |
151
- | `sourceRepo` | yes* | Git repository URL containing concept YAML files in `concepts/` directory. `gcrPackage` is an alternative. |
152
- | `gcrPackage` | no | URL to a pre-built `.gcr` ZIP archive. Used instead of `sourceRepo` when available. See `docs/gcr-spec.md`. |
153
- | `title` | no | Display name. Falls back to `name` field in the repo's `register.yaml`. |
154
- | `description` | no | Shown on the home page dataset card and the about page. |
155
- | `owner` | no | Organization name shown in concept badges and the about page. |
156
- | `color` | no | Hex color (`#RRGGBB`) for dataset accent. Used for graph nodes, sidebar highlights, and card borders. Auto-assigned if omitted. |
157
- | `tags` | no | Array of short labels shown on the dataset card. |
158
- | `existingSiteUrl` | no | Link to the dataset's existing website, shown as a badge on the dataset page. |
159
- | `externalConceptUrlTemplate` | no | URL template for linking to the official source of each concept. `{conceptId}` is replaced with the concept ID. |
160
- | `languageOrder` | no | Array of ISO 639-2 language codes controlling the display order on concept pages. Without this, languages default to English-first then alphabetical. |
203
+ Favicons are auto-generated from the logo SVG using the `favicons` package. Resolution order: `branding.favicon` → `branding.logo.localPath` → package default `public/favicon.svg`.
161
204
 
162
205
  ### Site features
163
206
 
164
- The `features` section in `site-config.yml` toggles functionality and customizes branding:
165
-
166
207
  ```yaml
167
208
  features:
168
- news: true # enable news posts (requires newsDir)
209
+ news: false # enable news posts
169
210
  stats: true # show statistics dashboard
170
211
  graph: true # enable concept graph visualization
171
212
  about: true # enable about page
172
213
  search: true # enable full-text search
173
- poweredBy: # customize the sidebar/footer credit link
174
- message: "Powered by Acme Corp"
175
- url: "https://example.com"
214
+ poweredBy:
215
+ title: "Glossarist"
216
+ url: "https://glossarist.org"
176
217
  ```
177
218
 
178
- | Field | Default | Description |
179
- |-------|---------|-------------|
180
- | `poweredBy.message` | `Built with the Glossarist Concept Browser` | Link text shown in sidebar and footer |
181
- | `poweredBy.url` | `https://github.com/glossarist/concept-browser` | Link href |
219
+ ### Content pages
182
220
 
183
- Omit the `poweredBy` block to use defaults. The `message` becomes the full text of a clickable link — there is no hardcoded prefix.
221
+ ```yaml
222
+ pages:
223
+ - type: about
224
+ route: about
225
+ title: About
226
+ icon: info
227
+ source: about.md
228
+ translations:
229
+ fra:
230
+ title: À propos
231
+ source: about-fra.md
232
+ ```
184
233
 
185
234
  ### Cross-reference mapping
186
235
 
187
- The top-level `crossReferences` section maps inline references to dataset IDs:
188
-
189
236
  ```yaml
190
237
  crossReferences:
191
238
  refPrefixMap:
192
- IEV: iev # {{term, IEV:xxx}} → glossarist.org/iev/concept/xxx
239
+ IEV: iev
193
240
  urnStandardMap:
194
- "14812": isotc204 # urn:iso:std:iso:14812:... → isotc204
241
+ "14812": isotc204
195
242
  ```
196
243
 
197
244
  ---
198
245
 
199
- ## Adding a New Dataset
200
-
201
- 1. Add an entry to `datasets.yml` (see configuration above)
202
- 2. Run `npm run fetch-datasets && npm run generate-data && node scripts/build-edges.js`
203
- 3. Verify with `npm run dev`
204
- 4. Commit and push
205
-
206
- For the full guide, see [Adding a Dataset](docs/adding-a-dataset.md).
207
-
208
- ### Source repository requirements
209
-
210
- The source repository must contain:
211
-
212
- - `concepts/` directory with YAML concept files (one per concept)
213
- - Optionally `register.yaml` with dataset metadata
214
-
215
- Concepts must conform to the [canonical format](docs/dataset-schema.md). The harmonization step in `fetch-datasets` normalizes common variants automatically.
216
-
217
- ---
218
-
219
- ## Included Datasets
220
-
221
- | Dataset | Concepts | Languages | Description |
222
- |---------|----------|-----------|-------------|
223
- | IEC Electropedia (IEV) | 22,228 | 17 | World's most comprehensive electrotechnical terminology database |
224
- | ISO/TC 211 Multi-Lingual Glossary | 1,302 | 5+ | Geographic information terminology |
225
- | ISO/TC 204 ITS Vocabulary | 312 | 1 | Intelligent transport systems terminology |
226
- | OSGeo Lexicon | 444 | 1 | Open Source Geospatial Foundation glossary |
227
-
228
- ---
229
-
230
246
  ## Deployment
231
247
 
232
- ### Architecture
233
-
234
- ```
235
- glossarist/vocabulary-browser geolexica/geolexica.org
236
- (Glossarist software) (Deployment target)
237
- ───────────────────── ──────────────────────
238
- Push to main Push to main / repository_dispatch
239
- │ │
240
- ├─ .github/workflows/deploy.yml │
241
- │ fetch + generate + build │
242
- │ → deploys to GitHub Pages (preview)│
243
- │ → triggers geolexica.org dispatch │
244
- │ │
245
- └──── repository_dispatch ─────────> build_deploy.yml
246
- checkout vocabulary-browser
247
- fetch + generate + build
248
- → GitHub Pages → www.geolexica.org
249
- ```
250
-
251
- The vocabulary-browser repository is the **Glossarist software**. The [geolexica.org](https://github.com/geolexica/geolexica.org) repository is the **deployment target** — its workflow checks out vocabulary-browser, builds it, and deploys to GitHub Pages at `www.geolexica.org`.
248
+ ### GitHub Pages (recommended)
252
249
 
253
- ### Production deployment (www.geolexica.org)
250
+ 1. Create a deployment repo with `site-config.yml`, dataset source, and content pages
251
+ 2. Add a GitHub Actions workflow:
254
252
 
255
- Deployments are managed by the `geolexica.org` repository's `build_deploy.yml` workflow:
256
-
257
- 1. Checks out `glossarist/vocabulary-browser` at `main`
258
- 2. Installs dependencies (`npm ci`)
259
- 3. Fetches datasets and generates data
260
- 4. Builds the SPA
261
- 5. Deploys `dist/` to GitHub Pages
262
-
263
- The workflow triggers on:
264
- - Push to `main` in the geolexica.org repo
265
- - `repository_dispatch` from vocabulary-browser (automatic when vocabulary-browser pushes to main)
266
- - Manual trigger via the "Run workflow" button
267
-
268
- See [geolexica/geolexica.org](https://github.com/geolexica/geolexica.org) for Pages configuration.
269
-
270
- ### This repository's build workflow
271
-
272
- `.github/workflows/deploy.yml` runs on push to `main`:
273
-
274
- 1. Checks out the code
275
- 2. Runs `npm ci`
276
- 3. Fetches datasets (`npm run fetch-datasets`)
277
- 4. Builds GCR packages (`npm run build-gcr:all`)
278
- 5. Generates data (`npm run generate-data`)
279
- 6. Extracts edges (`node scripts/build-edges.js`)
280
- 7. Builds the SPA (`npm run build`)
281
- 8. Deploys to GitHub Pages (preview at the repository's Pages URL)
282
- 9. Triggers `geolexica.org` deployment via `repository_dispatch`
283
-
284
- ### Custom base path
285
-
286
- By default the app deploys to the root (`/`). To deploy to a subdirectory (e.g., `/vocab/`):
287
-
288
- ```bash
289
- BASE_PATH=/vocab/ npm run build
290
- ```
291
-
292
- This sets the Vite `base` config so all asset paths are prefixed correctly.
293
-
294
- **How it works:**
295
-
296
- The `BASE_PATH` environment variable controls subpath deployment through two mechanisms:
297
-
298
- 1. **Build time (Node.js scripts):** `generate-data.mjs` uses `BASE_PATH` to prefix logo paths in the generated `site-config.json`. The favicon generation in `cli/index.mjs` also prefixes favicon link hrefs. These are build-time rewrites because they produce static JSON/HTML that can't use Vite's runtime resolution.
299
-
300
- 2. **Runtime (browser):** The Vue app uses `import.meta.env.BASE_URL` (a Vite compile-time constant derived from `base`) to prefix all `fetch()` paths. This includes:
301
- - `datasets.json` (dataset registry)
302
- - `site-config.json` (branding, features)
303
- - `data/{id}/...` (concept data via `DatasetAdapter`)
304
- - `pages/*.json` (content pages)
305
- - `news.json` (news feed)
306
- - `data/{id}/bibliography.json` and `data/{id}/images/*` (render-time resources)
307
-
308
- The Vite `base` config normalizes trailing slashes automatically, so `BASE_PATH=/vocab` and `BASE_PATH=/vocab/` both work. The value is passed through to `import.meta.env.BASE_URL` which always ends with `/`.
309
-
310
- **CLI usage:**
311
-
312
- When using the `concept-browser` CLI from a deployment repo (not the package source):
313
-
314
- ```bash
315
- git clone --branch fix/subpath-base-url --depth 1 https://github.com/glossarist/concept-browser.git /tmp/cb
316
- cd /tmp/cb && npm install --ignore-scripts
317
- npm install --prefix /tmp/cb sharp 2>/dev/null || true
318
-
319
- # Build from the deployment repo's working directory
320
- cd /path/to/deployment-repo
321
- node /tmp/cb/cli/index.mjs build
253
+ ```yaml
254
+ jobs:
255
+ build:
256
+ runs-on: ubuntu-latest
257
+ steps:
258
+ - uses: actions/checkout@v4
259
+ - uses: actions/setup-node@v4
260
+ with:
261
+ node-version: 20
262
+ - name: Install concept-browser
263
+ run: |
264
+ npm install --ignore-scripts @glossarist/concept-browser
265
+ npm install --prefix node_modules/@glossarist/concept-browser sharp 2>/dev/null || true
266
+ - name: Build site
267
+ run: npx concept-browser build
268
+ env:
269
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
270
+ - name: Upload artifact
271
+ uses: actions/upload-pages-artifact@v3
272
+ with:
273
+ path: dist
274
+ deploy:
275
+ needs: build
276
+ runs-on: ubuntu-latest
277
+ if: ${{ github.ref == 'refs/heads/main' }}
278
+ steps:
279
+ - uses: actions/deploy-pages@v4
322
280
  ```
323
281
 
324
- The CLI looks for `site-config.yml` in the CWD first, then falls back to the package's own `site-config.yml`.
282
+ All configuration (base path, dataset sources, branding) comes from `site-config.yml` no dataset-specific environment variables needed.
325
283
 
326
284
  ### Other hosting platforms
327
285
 
328
- The build produces static files in `dist/` with an SPA `404.html` fallback. Deploy `dist/` to any static host:
286
+ The build produces static files in `dist/` with an SPA `404.html` fallback:
329
287
 
330
- - **Netlify:** Set build command to `npm run build:full`, publish directory to `dist`, add `_redirects` file with `/* /index.html 200`
331
- - **Vercel:** Set framework to Vite, build command to `npm run build:full`, output directory to `dist`
332
- - **AWS S3 + CloudFront:** Upload `dist/` to S3, set error document to `index.html`, configure CloudFront for SPA routing
333
- - **GitHub Pages:** Set **Settings → Pages → Source** to "GitHub Actions", then push to `main`
334
- - **Any static host:** Upload `dist/` and configure all 404s to serve `index.html`
288
+ - **Netlify:** Build command `npx concept-browser build`, publish directory `dist`, add `_redirects` with `/* /index.html 200`
289
+ - **Vercel:** Framework Vite, build command `npx concept-browser build`, output directory `dist`
290
+ - **AWS S3 + CloudFront:** Upload `dist/`, error document `index.html`, configure CloudFront for SPA routing
335
291
 
336
292
  ---
337
293
 
338
294
  ## Architecture
339
295
 
340
- See [Architecture Documentation](docs/architecture.md) for:
341
- - System architecture diagrams
342
- - Component hierarchy
343
- - Data pipeline details
344
- - Adapter pattern and graph engine internals
345
-
346
296
  ### Tech Stack
347
297
 
348
298
  - **Vue 3** + **TypeScript** + **Vite**
@@ -351,46 +301,49 @@ See [Architecture Documentation](docs/architecture.md) for:
351
301
  - **Tailwind CSS 3** (utility-first styling)
352
302
  - **D3.js** (force-directed graph)
353
303
  - **KaTeX** (math rendering)
354
- - **DM Serif Display** + **DM Sans** + **JetBrains Mono** (typography)
355
304
 
356
305
  ### Project structure
357
306
 
358
307
  ```
359
308
  src/
360
309
  ├── adapters/ Data access layer (DatasetAdapter, AdapterFactory, UriRouter)
361
- ├── components/ Reusable Vue components (ConceptDetail, GraphPanel, SearchBar, etc.)
362
- ├── graph/ Graph engine for concept relationships (GraphEngine.ts)
310
+ ├── components/ Vue components (AppSidebar, AppFooter, ConceptDetail, GraphPanel, etc.)
311
+ ├── graph/ Graph engine for concept relationships
363
312
  ├── stores/ Pinia stores (vocabulary, ui)
364
313
  ├── views/ Page-level components (HomeView, DatasetView, ConceptView, etc.)
314
+ ├── i18n/ Internationalization (YAML locale files, auto-discovered)
365
315
  ├── utils/ Utilities (math rendering, language names, dataset styling)
366
316
  └── style.css Global styles and Tailwind layers
367
317
 
318
+ cli/
319
+ └── index.mjs CLI entry point (fetch, generate, edges, build commands)
320
+
368
321
  scripts/
369
- ├── fetch-datasets.mjs Clone + harmonize source repos
370
- ├── generate-data.mjs Convert YAML → JSON-LD
322
+ ├── fetch-datasets.mjs Clone + harmonize source repos, resolve localPath/GCR
323
+ ├── generate-data.mjs Convert YAML → JSON-LD, generate manifest with provenance data
371
324
  ├── build-edges.js Extract cross-reference edges
372
- ├── build-gcr.mjs Build GCR packages (optional)
373
325
  └── generate-404.js SPA fallback for GitHub Pages
374
-
375
- docs/
376
- ├── adding-a-dataset.md Step-by-step guide for adding datasets
377
- ├── dataset-schema.md Canonical concept YAML format reference
378
- ├── gcr-spec.md GCR packaging format specification
379
- └── architecture.md Full architecture documentation
380
326
  ```
381
327
 
382
328
  ---
383
329
 
330
+ ## i18n
331
+
332
+ UI translations are YAML files in `src/i18n/locales/`, auto-discovered via `import.meta.glob`. To add a new language:
333
+
334
+ 1. Copy `eng.yml` to `{lang-code}.yml`
335
+ 2. Translate all values
336
+ 3. Add the language to `uiLanguages` in `site-config.yml`
337
+
338
+ ---
339
+
384
340
  ## Testing
385
341
 
386
342
  ```bash
387
- npm test # Run all tests
343
+ npm test # Run all tests (Vitest with happy-dom)
388
344
  npm run test:watch # Watch mode
389
- npx vitest run src/__tests__/graph.test.ts # Single test file
390
345
  ```
391
346
 
392
- Tests use Vitest with happy-dom environment. Vue Test Utils for component tests.
393
-
394
347
  ---
395
348
 
396
349
  ## License
package/cli/index.mjs CHANGED
@@ -17,7 +17,6 @@
17
17
  * SITE_CONFIG Path to site config file (overrides --site)
18
18
  * SITE_ID Site config ID (overrides --site)
19
19
  * GITHUB_TOKEN GitHub token for private repos
20
- * DATASET_SOURCE_{ID} Override dataset source with local path
21
20
  */
22
21
 
23
22
  import { loadSiteConfig } from '../scripts/load-site-config.mjs';
@@ -69,8 +68,7 @@ Options:
69
68
  Environment:
70
69
  SITE_CONFIG Site config file path (highest priority)
71
70
  SITE_ID Site config ID (same as --site)
72
- GITHUB_TOKEN GitHub token for private repos
73
- DATASET_SOURCE_{ID} Override dataset source with local path`);
71
+ GITHUB_TOKEN GitHub token for private repos`);
74
72
  process.exit(cmd ? 0 : 1);
75
73
  }
76
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glossarist/concept-browser",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
4
4
  "description": "Vue SPA for browsing Glossarist terminology datasets with cross-reference resolution, graph visualization, and multi-language support",
5
5
  "type": "module",
6
6
  "bin": {
@@ -88,6 +88,7 @@ export interface DatasetConfig {
88
88
  uriAliases?: string[];
89
89
  gcrPackage: string;
90
90
  sourceRepo?: string;
91
+ localPath?: string;
91
92
  title: string;
92
93
  description?: string;
93
94
  owner?: string;
@@ -144,6 +145,7 @@ export interface SiteConfig {
144
145
  id: string;
145
146
  domain: string;
146
147
  uriBase?: string;
148
+ basePath?: string;
147
149
  title: string;
148
150
  subtitle?: string;
149
151
  description?: string;