@glossarist/concept-browser 0.7.74 → 0.7.76

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.
Files changed (2) hide show
  1. package/README.md +125 -449
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,519 +1,195 @@
1
1
  # Glossarist Concept Browser
2
2
 
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`.
3
+ A statically deployable terminology browser. Install as an npm package, configure via YAML, build, deploy.
4
4
 
5
- **Live sites:**
6
- - [GeoLexica](https://www.geolexica.org) — IEC Electropedia + ISO/TC 211 + more
7
- - [VIML](https://www.oimlsmart.org/vocab/) — OIML International Vocabulary of Legal Metrology
8
- - [OIML Terms](https://metanorma.github.io/oiml-terms/) — OIML G 18 terminology
9
-
10
- ---
11
-
12
- ## Features
13
-
14
- - **Multi-dataset browsing** — Concepts from multiple terminology registers in one place
15
- - **Full multilingual support** — Definitions, notes, and examples in all available languages with i18n UI
16
- - **Concept history timeline** — Review dates, decisions, and change notes per language
17
- - **Relation sphere** — 3D sphere visualization of a concept's neighborhood with d3 force simulation, per-relation-type colors, and degree filtering
18
- - **Edition series** — Sidebar timeline for vocabulary edition groups (e.g. VIML 1968/2000/2013/2022) with current-edition markers and supersession chain navigation
19
- - **Cross-reference graph** — D3 force-directed graph showing concept relationships with dataset filtering
20
- - **Dataset groups** — Organize datasets into lineage series, topic bundles, publication families, or curated collections. Each group kind has distinct sidebar rendering
21
- - **Light/dark mode colors** — Per-dataset `{ light, dark }` color pairs. Per-relation-type colors configurable via site-config
22
- - **RDF / SHACL outputs** — Every concept emits SHACL-conformant Turtle + JSON-LD. Dataset-level `dcat:Dataset`, group-level `dcat:DatasetSeries`/`dcat:Catalog`, vocabulary SKOS ConceptSchemes, bibliography `dcterms:BibliographicResource`, build provenance `prov:Activity`
23
- - **Rich sidebar provenance** — Publication reference, owner, status, concept/language counts, sections tree from manifest data
24
- - **Math rendering** — KaTeX rendering for AsciiMath notation in definitions (`stem:[...]`)
25
- - **Responsive design** — Mobile-first layout with light/dark mode
26
- - **Static deployment** — No server required. Deploy to any static host
27
-
28
- ---
29
-
30
- ## Quick Start (deployment repo)
31
-
32
- 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.
5
+ ## Quick Start
33
6
 
34
7
  ```bash
35
- # In your deployment repo:
36
- npm install --ignore-scripts @glossarist/concept-browser
37
- npm install --prefix node_modules/@glossarist/concept-browser sharp 2>/dev/null || true
38
- npx concept-browser build
39
- ```
40
-
41
- The CLI reads `site-config.yml` from the working directory, fetches/generates data, and builds the SPA into `dist/`.
8
+ # 1. Create your project
9
+ mkdir my-dictionary && cd my-dictionary
10
+ npm init -y
11
+
12
+ # 2. Install
13
+ npm install @glossarist/concept-browser
14
+
15
+ # 3. Create site-config.yml
16
+ cat > site-config.yml << 'EOF'
17
+ id: my-dictionary
18
+ title: My Dictionary
19
+ uri_base: https://example.com
20
+ datasets:
21
+ - id: my-vocab
22
+ title: My Vocabulary
23
+ local_path: datasets/my-vocab # or gcr_package: https://...
24
+ EOF
42
25
 
43
- ### Quick Start (development)
26
+ # 4. Build
27
+ npx concept-browser build
44
28
 
45
- ```bash
46
- git clone https://github.com/glossarist/concept-browser.git
47
- cd concept-browser
48
- npm install
49
- npm run dev
50
- # Open http://localhost:5173
29
+ # 5. Deploy
30
+ # Upload dist/ to any static host (GitHub Pages, Netlify, S3, etc.)
51
31
  ```
52
32
 
53
- The dev server serves pre-built data from `public/data/`. If no data is present yet, run the data pipeline first (see below).
54
-
55
- ---
56
-
57
- ## CLI Reference
33
+ ## How It Works
58
34
 
59
35
  ```
60
- concept-browser <command> [options]
61
-
62
- Commands:
63
- fetch Fetch/update datasets (from GCR packages, local paths, or source repos)
64
- generate Convert harmonized YAML concepts to JSON-LD static files + RDF artifacts
65
- edges Build cross-reference edges from generated concept data
66
- build Full pipeline: fetch + generate + edges + vite build
67
- site Same as build (alias)
68
- doctor Run diagnostic checks (node version, deps, shapes, data integrity)
69
- normalize NFC-normalize YAML concept files in-place
70
-
71
- Options:
72
- --site <id> Site config ID (looks for site-config.yml in CWD)
73
-
74
- Environment:
75
- SITE_CONFIG Site config file path (highest priority)
76
- SITE_ID Site config ID (same as --site)
77
- GITHUB_TOKEN GitHub token for private repos
36
+ Your project (CWD) Package (read-only)
37
+ ├── site-config.yml ──┐
38
+ ├── datasets/ ─┤
39
+ │ └── my-vocab/ ─┤ ┌──────────────────────────┐
40
+ │ └── concepts/*.yaml ─┤ │ @glossarist/concept-browser │
41
+ ├── public/ ─┤ ──> │ │
42
+ │ └── (logos, favicons) ─┤ │ generate-data.mjs │
43
+ ├── .cb-content/ ← generated │ │ bridge-to-astro.mjs │
44
+ └── dist/ ← output │ │ astro build │
45
+ ──┘ └──────────────────────────┘
78
46
  ```
79
47
 
80
- ---
48
+ The package reads your config and data, generates `.cb-content/` (content collections) and `dist/` (static site) in your project. The package itself (`node_modules/`) is never modified.
81
49
 
82
- ## Data Pipeline
50
+ ## Configuration
83
51
 
84
- ```
85
- site-config.yml
86
- └─> scripts/fetch-datasets.mjs (fetch from GCR, localPath, or sourceRepo)
87
- └─> .datasets/{id}/concepts/*.yaml
88
- └─> scripts/generate-data.mjs (YAML → JSON-LD + RDF artifacts)
89
- └─> public/data/{id}/
90
- ├── manifest.json Dataset metadata (ref, owner, stats)
91
- ├── index.json Concept listing (chunked for large sets)
92
- ├── edges.json Pre-computed cross-reference + domain edges
93
- ├── domain-nodes.json Domain classification nodes
94
- ├── {register}.ttl Dataset-level RDF (dcat:Dataset + skos:ConceptScheme + sections)
95
- ├── bib.ttl Bibliography graph (dcterms:BibliographicResource)
96
- └── concepts/*.json Individual concept documents
97
- └─> public/data/_vocab.ttl Vocabulary graph (SKOS ConceptSchemes)
98
- └─> public/data/activity/ Build provenance (prov:Activity per build)
99
- └─> public/data/agents.ttl Contributor records (foaf:Person)
100
- └─> public/data/versions.ttl Version chain (prov:Entity)
101
- └─> scripts/build-edges.js (extract graph + domain edges)
102
- ```
103
-
104
- ---
52
+ Everything is in `site-config.yml`. See [`site-config.example.yml`](site-config.example.yml) for all options.
105
53
 
106
- ## Configuration: `site-config.yml`
54
+ ### Dataset location
107
55
 
108
- All configuration lives in a single file. The CLI reads it from the current working directory.
109
-
110
- ### Top-level fields
56
+ Each dataset specifies where its source data lives. Three options:
111
57
 
112
58
  ```yaml
113
- id: viml # Site identifier
114
- domain: viml.oiml.info # Primary domain
115
- basePath: /oiml-viml/ # URL subpath for GitHub Pages deployment
116
- title: VIML # Site title
117
- subtitle: International Vocabulary... # Short description
118
- description: Terminology from... # Longer description
119
-
120
- uiLanguages: # Available UI languages
121
- - code: eng
122
- label: English
123
- - code: fra
124
- label: Français
125
-
126
- translations: # Localized title/subtitle/description
127
- fra:
128
- subtitle: Vocabulaire international de métrologie légale
129
- description: Terminologie du Vocabulaire international...
130
-
131
- defaults:
132
- language: eng # Default concept language
133
-
134
- copyright: "OIML" # Footer copyright text
135
- ```
59
+ datasets:
60
+ # Option A: Local directory with concepts/*.yaml
61
+ - id: my-vocab
62
+ local_path: datasets/my-vocab # relative to project root
136
63
 
137
- ### Dataset configuration
64
+ # Option B: GCR package (auto-downloaded at build time)
65
+ - id: iev
66
+ gcr_package: https://github.com/org/repo/releases/download/v1.0/my-vocab.gcr
138
67
 
139
- ```yaml
140
- datasets:
141
- - id: viml
142
- uri: "urn:oiml:pub:v:1:2022"
143
- sourceRepo: https://github.com/metanorma/oiml-viml
144
- localPath: viml-glossarist # Local dataset directory (relative to CWD)
145
- title: "VIML — International Vocabulary of Legal Metrology"
146
- description: "Terminology definitions from..."
147
- owner: OIML
148
- ref: "OIML V 1:2022" # Publication reference (shown in sidebar provenance)
149
- color: "#004996"
150
- tags: [metrology, legal, oiml]
151
- languageOrder: [eng, fra]
68
+ # Option C: Git repository (cloned at build time)
69
+ - id: iso-terms
70
+ source_repo: https://github.com/org/iso-terms
152
71
  ```
153
72
 
154
- #### Dataset field reference
73
+ ### Colors
155
74
 
156
- | Field | Required | Description |
157
- |-------|----------|-------------|
158
- | `id` | yes | URL-safe identifier used in routes and data paths |
159
- | `uri` | no | URI pattern for this dataset |
160
- | `sourceRepo` | no | Git repository URL containing concept YAML files |
161
- | `gcrPackage` | no | URL to a pre-built `.gcr` ZIP archive (alternative to sourceRepo) |
162
- | `localPath` | no | Local directory with `concepts/` and `register.yaml` (relative to CWD) |
163
- | `title` | no | Display name. Falls back to `register.yaml` name field |
164
- | `description` | no | Shown on home page and about page |
165
- | `owner` | no | Organization name shown in sidebar provenance |
166
- | `ref` | no | Publication reference shown in sidebar provenance (e.g., "OIML V 1:2022") |
167
- | `color` | no | Accent color — single hex (`"#004996"`) or `{ light, dark }` pair |
168
- | `tags` | no | Array of labels shown on dataset card |
169
- | `languageOrder` | no | Array of ISO 639-2 codes controlling display order |
170
- | `translations` | no | Localized title and description per language |
75
+ Each dataset can have a color — single hex or light/dark pair:
171
76
 
172
- #### Dataset source resolution
173
-
174
- The CLI resolves dataset sources in this priority order:
77
+ ```yaml
78
+ datasets:
79
+ - id: my-vocab
80
+ color: "#2563eb" # single color (both modes)
175
81
 
176
- 1. **`.gcr/{id}.gcr`** on disk — extract to `.datasets/{id}/`
177
- 2. **`gcrPackage`** URL — download and extract
178
- 3. **`localPath`** — copy `concepts/` and `register.yaml` from a local directory
179
- 4. **`sourceRepo`** — git clone to `.datasets/{id}/`
82
+ - id: legacy-vocab
83
+ color:
84
+ light: "#004996" # light mode
85
+ dark: "#3B82F6" # dark mode
86
+ ```
180
87
 
181
- ### Base path for subpath deployment
88
+ Colors appear in the sidebar (color dot per dataset), sphere cards (top bar + tint), badges, and relationship edges. If omitted, a palette color is assigned automatically.
182
89
 
183
- Set `basePath` in `site-config.yml` to deploy to a subdirectory (e.g., GitHub Pages at `metanorma.github.io/my-site/`):
90
+ Group colors work the same way:
184
91
 
185
92
  ```yaml
186
- basePath: /my-site/
93
+ dataset_groups:
94
+ - id: my-vocab-series
95
+ color: "#d97706"
187
96
  ```
188
97
 
189
- 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.
98
+ ### Logo
190
99
 
191
- ### Branding and favicon
100
+ Place logo SVGs/PNGs in `public/` and reference them in `branding`:
192
101
 
193
102
  ```yaml
194
103
  branding:
195
- primaryColor: "#004996"
196
- darkColor: "#003366"
197
- fonts:
198
- header:
199
- family: "Source Serif 4"
200
- source: "google"
201
- weights: [400, 600]
202
- body:
203
- family: "Source Sans 3"
204
- source: "google"
205
- weights: [400, 500, 700]
206
104
  logo:
207
- path: /logos/oiml-logo.svg # URL path served to browsers
208
- alt: OIML
209
- localPath: logos/oiml-logo.svg # Local file for favicon generation
210
- localLight: logos/oiml-logo-icon-light.svg # Light variant (dark mode)
211
- localDark: logos/oiml-logo-icon-dark.svg # Dark variant (light mode)
212
- ownerName: OIML
213
- ownerUrl: "https://www.oiml.org"
105
+ alt: My Dictionary
106
+ light: /images/logo-light.svg # shown in light mode
107
+ dark: /images/logo-dark.svg # shown in dark mode
214
108
  ```
215
109
 
216
- Favicons are auto-generated from the logo SVG using the `favicons` package. Resolution order: `branding.favicon` → `branding.logo.localPath` → package default `public/favicon.svg`.
110
+ If no logo is configured, the Glossarist logo is shown by default. The footer always shows the Glossarist logo ("Powered by Glossarist").
217
111
 
218
- ### Site features
112
+ Favicons work the same way — place `favicon.svg`, `favicon.ico`, and `apple-touch-icon*.png` in `public/`. If not provided, the Glossarist favicon is used.
219
113
 
220
- ```yaml
221
- features:
222
- news: false # enable news posts
223
- stats: true # show statistics dashboard
224
- graph: true # enable concept graph visualization
225
- about: true # enable about page
226
- search: true # enable full-text search
227
- poweredBy:
228
- title: "Glossarist"
229
- url: "https://glossarist.org"
230
- ```
114
+ ### About pages
231
115
 
232
- ### Content pages
116
+ Place JSON files in `public/pages/`:
233
117
 
234
- ```yaml
235
- pages:
236
- - type: about
237
- route: about
238
- title: About
239
- icon: info
240
- source: about.md
241
- translations:
242
- fra:
243
- title: À propos
244
- source: about-fra.md
245
118
  ```
246
-
247
- ### Dataset groups
248
-
249
- When a site has many datasets, you can group them in the sidebar navigation. Each group has a `kind` that determines its visual treatment and semantic assumptions.
250
-
251
- ```yaml
252
- datasetGroups:
253
- - id: viml
254
- label: "VIML — International Vocabulary of Legal Metrology"
255
- kind: lineage # edition series (same vocabulary, different years)
256
- current: viml-2022 # current edition for the series
257
- color:
258
- light: "#004996"
259
- dark: "#3B82F6"
260
- datasets: [viml-2022, viml-2013, viml-2000, viml-1968]
261
- translations:
262
- fra:
263
- label: "VIML — Vocabulaire international de métrologie légale"
264
-
265
- - id: vim
266
- label: "VIM — International Vocabulary of Metrology"
267
- kind: lineage
268
- current: vim-2012
269
- color:
270
- light: "#005A9C"
271
- dark: "#2196F3"
272
- datasets: [vim-2012, vim-2010, vim-2007, vim-1993]
119
+ public/
120
+ └── pages/
121
+ ├── about.json → /about
122
+ └── my-vocab-about.json → /my-vocab-about
273
123
  ```
274
124
 
275
- #### Group kinds
276
-
277
- | Kind | Glyph | Description | Sidebar rendering |
278
- |------|-------|-------------|-------------------|
279
- | `lineage` | ⏳ | Editions of the same vocabulary over time | Compact timeline with year badges + current-edition star (✦) |
280
- | `topic` | ◆ | Different vocabularies on the same subject | Standard list entries |
281
- | `family` | ✦ | Related vocabularies from the same publisher | Standard list entries |
282
- | `collection` | ❖ | Curated bundle of datasets | Standard list entries |
283
- | `default` | ▸ | No special semantics (backward compat) | Standard list entries |
284
-
285
- For `lineage` groups:
286
- - The `current` field identifies the newest valid edition. If omitted, the newest member by year is auto-detected.
287
- - Members are displayed as a timeline with year + reference + status badges.
288
- - When an edition is active, the full expansion (sub-pages, sections tree, provenance) appears below the timeline entry — same as non-series datasets.
289
- - A supersession chain card (`ConceptEditionRail`) appears in the concept detail sidebar, showing how the concept evolved across editions.
290
-
291
- #### Group field reference
292
-
293
- | Field | Required | Description |
294
- |-------|----------|-------------|
295
- | `id` | yes | Unique identifier for the group |
296
- | `label` | yes | Display name shown as the collapsible group header |
297
- | `kind` | no | Group kind: `lineage`, `topic`, `family`, `collection`, `default`. Defaults to `default` |
298
- | `current` | no | For `lineage`: dataset id of the current (newest valid) edition |
299
- | `description` | no | Short description of the group |
300
- | `color` | no | Accent color — single hex or `{ light, dark }` pair |
301
- | `datasets` | yes | Ordered array of dataset IDs belonging to this group |
302
- | `translations` | no | Localized label and description per language |
303
-
304
- Datasets not assigned to any group appear at the bottom of the dataset list.
125
+ Each file:
305
126
 
306
- ### Internationalization
307
-
308
- All localized text uses language maps — a `translations` field keyed by ISO 639-2 language codes. The top-level `title` and `description` fields hold the default-language text. The `translations` map provides overrides for additional languages:
309
-
310
- ```yaml
311
- datasets:
312
- - id: viml-2022
313
- title: "OIML V 1:2022"
314
- description: "Current edition with 135 terms..."
315
- translations:
316
- fra:
317
- title: "OIML V 1:2022"
318
- description: "Édition actuelle comprenant 135 termes..."
319
-
320
- datasetGroups:
321
- - id: viml
322
- label: "International Vocabulary of Legal Metrology"
323
- translations:
324
- fra:
325
- label: "Vocabulaire international de métrologie légale"
127
+ ```json
128
+ {
129
+ "title": "About This Dictionary",
130
+ "html": "<p>Content here. Supports full HTML.</p>"
131
+ }
326
132
  ```
327
133
 
328
- This pattern applies everywhere localized text appears: site-level translations, dataset translations, group translations, and page translations. Do not use language suffixes like `_fra` — use nested language maps instead.
134
+ The page appears in the sidebar navigation automatically.
329
135
 
330
- ### Color system
136
+ ### Full example
331
137
 
332
- Dataset and group colors accept either a single hex string (backward compat) or a `{ light, dark }` pair:
138
+ See [`site-config.example.yml`](site-config.example.yml) for all options including UI languages, fonts, features, and dataset groups.
333
139
 
334
- ```yaml
335
- # Single hex (applied to both modes)
336
- color: "#004996"
140
+ ## CLI Commands
337
141
 
338
- # Explicit light/dark pair
339
- color:
340
- light: "#004996"
341
- dark: "#3B82F6"
342
142
  ```
343
-
344
- Relationship-type colors default from `data/colors.json` but can be overridden per deployment:
345
-
346
- ```yaml
347
- colors:
348
- relationshipType:
349
- supersedes:
350
- light: "#FF0000"
351
- dark: "#FF5555"
352
- dataset:
353
- viml-2022:
354
- light: "#004996"
355
- dark: "#3B82F6"
143
+ npx concept-browser fetch # Download datasets from GCR/repos
144
+ npx concept-browser generate # Convert YAML → JSON-LD + RDF artifacts
145
+ npx concept-browser build # Full pipeline: fetch + generate + build site
356
146
  ```
357
147
 
358
- CSS variables are emitted on document root by `useColorTheme()`:
359
- - `--rel-{category}-{light|dark}` per relationship category
360
- - `--rel-type-{type}-{light|dark}` per relationship type
361
- - `--concept-status-{status}-{light|dark}` per concept status
362
- - `--group-kind-{kind}-{light|dark}` per group kind
363
- - `--ds-{light|dark}` per dataset (scoped via `[data-ds]`)
148
+ ## .gitignore for Your Project
364
149
 
365
- ### Cross-reference mapping
150
+ Add these to your project's `.gitignore`:
366
151
 
367
- ```yaml
368
- crossReferences:
369
- refPrefixMap:
370
- IEV: iev
371
- urnStandardMap:
372
- "14812": isotc204
373
152
  ```
374
-
375
- ---
376
-
377
- ## Deployment
378
-
379
- ### GitHub Pages (recommended)
380
-
381
- 1. Create a deployment repo with `site-config.yml`, dataset source, and content pages
382
- 2. Add a GitHub Actions workflow:
383
-
384
- ```yaml
385
- jobs:
386
- build:
387
- runs-on: ubuntu-latest
388
- steps:
389
- - uses: actions/checkout@v4
390
- - uses: actions/setup-node@v4
391
- with:
392
- node-version: 20
393
- - name: Install concept-browser
394
- run: |
395
- npm install --ignore-scripts @glossarist/concept-browser
396
- npm install --prefix node_modules/@glossarist/concept-browser sharp 2>/dev/null || true
397
- - name: Build site
398
- run: npx concept-browser build
399
- env:
400
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
401
- - name: Upload artifact
402
- uses: actions/upload-pages-artifact@v3
403
- with:
404
- path: dist
405
- deploy:
406
- needs: build
407
- runs-on: ubuntu-latest
408
- if: ${{ github.ref == 'refs/heads/main' }}
409
- steps:
410
- - uses: actions/deploy-pages@v4
153
+ .cb-content/
154
+ dist/
155
+ .datasets/
156
+ .gcr/
157
+ public/data/
411
158
  ```
412
159
 
413
- All configuration (base path, dataset sources, branding) comes from `site-config.yml` — no dataset-specific environment variables needed.
414
-
415
- ### Other hosting platforms
416
-
417
- The build produces static files in `dist/` with an SPA `404.html` fallback:
418
-
419
- - **Netlify:** Build command `npx concept-browser build`, publish directory `dist`, add `_redirects` with `/* /index.html 200`
420
- - **Vercel:** Framework Vite, build command `npx concept-browser build`, output directory `dist`
421
- - **AWS S3 + CloudFront:** Upload `dist/`, error document `index.html`, configure CloudFront for SPA routing
422
-
423
- ### Known deployments
424
-
425
- Sites currently powered by `@glossarist/concept-browser`. When cutting a release with breaking changes, bump `@glossarist/concept-browser` in each consumer repo and redeploy.
160
+ ## Data Format
426
161
 
427
- | Repo | Site |
428
- |---|---|
429
- | [`geolexica/geolexica.github.io`](https://github.com/geolexica/geolexica.github.io) | https://www.geolexica.org |
430
- | [`geolexica/isotc204.geolexica.org`](https://github.com/geolexica/isotc204.geolexica.org) | https://isotc204.geolexica.org |
431
- | [`geolexica/isotc211.geolexica.org`](https://github.com/geolexica/isotc211.geolexica.org) | https://isotc211.geolexica.org |
432
- | [`geolexica/osgeo.geolexica.org`](https://github.com/geolexica/osgeo.geolexica.org) | https://osgeo.geolexica.org |
433
- | [`oimlsmart/vocab`](https://github.com/oimlsmart/vocab) | https://www.oimlsmart.org/vocab/ (VIML)¹ |
434
- | [`metanorma/oiml-terms`](https://github.com/metanorma/oiml-terms) | https://metanorma.github.io/oiml-terms/ |
435
- | [`glossarist/iala-vocab`](https://github.com/glossarist/iala-vocab) | https://glossarist.github.io/iala-vocab/ |
436
- | [`metanorma/iso-10303-2-vocab`](https://github.com/metanorma/iso-10303-2-vocab) | https://metanorma.github.io/iso-10303-2-vocab/ |
437
-
438
- To add a new deployment here, open a PR against this README.
439
-
440
- ¹ The VIML deployment moved from `metanorma/oiml-viml` to [`oimlsmart/vocab`](https://github.com/oimlsmart/vocab) (GitHub redirects the old name automatically), and its live URL moved from `metanorma.github.io/oiml-viml/` to `www.oimlsmart.org/vocab/`. The old `metanorma.github.io/oiml-viml/` URL returns 404 (Pages doesn't follow repo renames across orgs).
441
-
442
- ---
443
-
444
- ## Architecture
445
-
446
- ### Tech Stack
447
-
448
- - **Vue 3** + **TypeScript** + **Vite**
449
- - **Pinia** (state management)
450
- - **Vue Router** (SPA navigation)
451
- - **Tailwind CSS 3** (utility-first styling)
452
- - **D3.js** (force-directed graph + relation sphere)
453
- - **KaTeX** (math rendering)
454
- - **n3** + **rdf-validate-shacl** (RDF parsing + SHACL validation)
455
- - **fast-check** (property-based fuzz testing)
456
- - **Vitest** with happy-dom
457
-
458
- ### Project structure
459
-
460
- ```
461
- src/
462
- ├── adapters/ Data access layer (DatasetAdapter, AdapterFactory, UriRouter)
463
- ├── components/ Vue components (AppSidebar, ConceptDetail, RelationSphere, etc.)
464
- │ ├── concept-rdf/ RDF graph IR + emitters + writers (concept, dataset, group, vocab, etc.)
465
- │ └── groups/ OCP group renderer dispatcher + per-kind sidebar components
466
- ├── composables/ Vue composables (useDatasetSeries, useColorTheme, useSphereProjection)
467
- ├── config/ Site config types, group-types registry, group-renderers registry
468
- ├── data/ Static data (taxonomies.json, colors.json, concept-model shapes)
469
- ├── graph/ Graph engine for concept relationships
470
- ├── stores/ Pinia stores (vocabulary, ui)
471
- ├── views/ Page-level components (HomeView, DatasetView, ConceptView, GroupView)
472
- ├── i18n/ Internationalization (YAML locale files, auto-discovered)
473
- └── utils/ Utilities (color-theme, dataset-style, relationship-categories, content-renderer)
474
-
475
- cli/
476
- └── index.mjs CLI entry point (fetch, generate, edges, build, doctor, normalize)
477
-
478
- scripts/
479
- ├── fetch-datasets.mjs Clone + harmonize source repos
480
- ├── generate-data.mjs Convert YAML → JSON-LD + RDF artifacts
481
- ├── build-edges.js Extract cross-reference edges
482
- ├── process-about-pages.mjs Compile markdown/AsciiDoc about pages
483
- ├── validate-shacl.mjs SHACL validation gate
484
- └── lib/ Build-time emitters (vocab, dataset, group, agents, version, etc.)
485
- ```
162
+ Each concept is a YAML file in `datasets/{id}/concepts/`:
486
163
 
164
+ ```yaml
487
165
  ---
488
-
489
- ## i18n
490
-
491
- UI translations are YAML files in `src/i18n/locales/`, auto-discovered via `import.meta.glob`. To add a new language:
492
-
493
- 1. Copy `eng.yml` to `{lang-code}.yml`
494
- 2. Translate all values
495
- 3. Add the language to `uiLanguages` in `site-config.yml`
496
-
166
+ data:
167
+ identifier: "1-1-1"
168
+ localized_concepts:
169
+ eng: <uuid>
170
+ sources:
171
+ - type: authoritative
172
+ origin:
173
+ ref:
174
+ source: "ISO 9000"
175
+ definition:
176
+ - content: "The concept definition text."
177
+ terms:
178
+ - type: expression
179
+ normative_status: preferred
180
+ designation: "quality"
181
+ language_code: eng
497
182
  ---
498
-
499
- ## Testing
500
-
501
- ```bash
502
- npm test # Run all tests (Vitest with happy-dom)
503
- npm run test:watch # Watch mode
504
- npm run mutation:test # Stryker mutation testing (scoped to RDF emitters, ~3-5 min)
505
183
  ```
506
184
 
507
- Test coverage includes:
508
- - 1357+ tests across unit, round-trip, SHACL conformance, property-based fuzz, and build-integration layers
509
- - 7-fixture concept corpus (minimal, multilingual, full-relationships, with-sources, with-non-verbal, with-dates, withdrawn)
510
- - SHACL conformance gate: all fixtures validated against canonical shapes
511
- - Property-based fuzz: 200 iterations × 4 invariants via fast-check
512
- - 10,000-concept scale stress test (< 100ms)
513
- - Stryker mutation testing scoped to concept/dataset/bibliography emitters
185
+ Or use a Glossarist GCR package — set `gcr_package` in your dataset config and the CLI downloads it automatically.
514
186
 
515
- ---
187
+ ## Deployment
188
+
189
+ The build outputs a static site to `dist/`. Deploy it anywhere:
516
190
 
517
- ## License
191
+ - **GitHub Pages**: Push `dist/` to `gh-pages` branch
192
+ - **Netlify/Vercel**: Set build command to `npx concept-browser build`, publish directory to `dist/`
193
+ - **S3/CloudFront**: `aws s3 sync dist/ s3://my-bucket/`
518
194
 
519
- This project is part of the [Glossarist](https://github.com/glossarist) ecosystem.
195
+ No server required. All data is pre-built into static JSON files.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glossarist/concept-browser",
3
- "version": "0.7.74",
3
+ "version": "0.7.76",
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": {