@glossarist/concept-browser 0.7.53 → 0.7.54
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/package.json +1 -1
- package/src/components/AppSidebar.vue +106 -110
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.54",
|
|
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": {
|
|
@@ -283,132 +283,128 @@ const activeSectionId = computed(() => {
|
|
|
283
283
|
|
|
284
284
|
<!-- Group entries -->
|
|
285
285
|
<div v-if="isGroupExpanded(group.id)" class="space-y-1" :class="group.label ? 'ml-1' : ''">
|
|
286
|
-
<!--
|
|
287
|
-
<
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
class="text-[9px] uppercase tracking-wide italic text-ink-400 dark:text-ink-400"
|
|
303
|
-
>{{ ds.status }}</span>
|
|
304
|
-
<span
|
|
305
|
-
v-if="ds.isCurrent"
|
|
306
|
-
class="current-star flex-shrink-0"
|
|
307
|
-
title="Current edition"
|
|
308
|
-
>✦</span>
|
|
309
|
-
</button>
|
|
310
|
-
</div>
|
|
311
|
-
</template>
|
|
312
|
-
|
|
313
|
-
<!-- REGULAR group: original entry style with expansion -->
|
|
314
|
-
<template v-else>
|
|
315
|
-
<div
|
|
316
|
-
v-for="ds in group.entries"
|
|
317
|
-
:key="ds.id"
|
|
318
|
-
class="rounded-lg transition-all duration-150"
|
|
319
|
-
:class="currentDataset === ds.id ? 'bg-surface' : ''"
|
|
286
|
+
<!-- Per-entry rendering: button is kind-specific, expansion is shared (DRY/MECE) -->
|
|
287
|
+
<div
|
|
288
|
+
v-for="ds in group.entries"
|
|
289
|
+
:key="ds.id"
|
|
290
|
+
class="rounded-lg transition-all duration-150"
|
|
291
|
+
:class="currentDataset === ds.id ? 'bg-surface' : ''"
|
|
292
|
+
>
|
|
293
|
+
<!-- LINEAGE: compact timeline button -->
|
|
294
|
+
<button
|
|
295
|
+
v-if="group.kind === 'lineage'"
|
|
296
|
+
@click="goToDataset(ds.id)"
|
|
297
|
+
class="series-entry w-full text-left flex items-center gap-2 pl-6 pr-3 py-1.5 rounded-md text-sm border-l-2 transition-all duration-150"
|
|
298
|
+
:class="currentDataset === ds.id
|
|
299
|
+
? 'bg-amber-50/70 dark:bg-amber-400/10 border-l-[3px] text-ink-900 dark:text-ink-50 font-semibold'
|
|
300
|
+
: 'border-transparent text-ink-600 dark:text-ink-300 hover:bg-ink-50 dark:hover:bg-ink-700/40 hover:text-ink-900 dark:hover:text-ink-50'"
|
|
301
|
+
:style="currentDataset === ds.id ? { borderLeftColor: 'var(--gold-accent, #B8935A)' } : {}"
|
|
320
302
|
>
|
|
321
|
-
<
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
>
|
|
331
|
-
|
|
332
|
-
<div v-if="ds.loaded" class="text-xs mt-0.5" :class="currentDataset === ds.id ? 'text-ink-400 dark:text-ink-300' : 'text-ink-300 dark:text-ink-400'">
|
|
333
|
-
{{ ds.conceptCount.toLocaleString() }} {{ t('home.concepts').toLowerCase() }}
|
|
334
|
-
</div>
|
|
335
|
-
</button>
|
|
303
|
+
<span class="flex-1 truncate text-[13.5px] font-medium leading-snug">{{ ds.ref || ds.title || ds.id }}</span>
|
|
304
|
+
<span
|
|
305
|
+
v-if="ds.status && ds.status !== 'valid'"
|
|
306
|
+
class="text-[9px] uppercase tracking-wide italic text-ink-400 dark:text-ink-400"
|
|
307
|
+
>{{ ds.status }}</span>
|
|
308
|
+
<span
|
|
309
|
+
v-if="ds.isCurrent"
|
|
310
|
+
class="current-star flex-shrink-0"
|
|
311
|
+
title="Current edition"
|
|
312
|
+
>✦</span>
|
|
313
|
+
</button>
|
|
336
314
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
315
|
+
<!-- DEFAULT/OTHER: standard entry button -->
|
|
316
|
+
<button
|
|
317
|
+
v-else
|
|
318
|
+
@click="goToDataset(ds.id)"
|
|
319
|
+
class="w-full text-left px-3 py-2 rounded-lg text-sm border-l-2"
|
|
320
|
+
:class="[
|
|
321
|
+
currentDataset === ds.id
|
|
322
|
+
? 'text-ink-800 dark:text-ink-50'
|
|
323
|
+
: 'border-transparent text-ink-600 dark:text-ink-300 hover:bg-ink-50 dark:hover:bg-ink-700 hover:text-ink-800 dark:hover:text-ink-50'
|
|
324
|
+
]"
|
|
325
|
+
:style="currentDataset === ds.id ? { borderLeftColor: getColor(ds.id), borderLeftWidth: '2px' } : {}"
|
|
326
|
+
>
|
|
327
|
+
<div class="font-medium truncate leading-snug">{{ localizedDatasetField(ds.id, 'title', ds.title) }}</div>
|
|
328
|
+
<div v-if="ds.loaded" class="text-xs mt-0.5" :class="currentDataset === ds.id ? 'text-ink-400 dark:text-ink-300' : 'text-ink-300 dark:text-ink-400'">
|
|
329
|
+
{{ ds.conceptCount.toLocaleString() }} {{ t('home.concepts').toLowerCase() }}
|
|
330
|
+
</div>
|
|
331
|
+
</button>
|
|
332
|
+
|
|
333
|
+
<!-- SHARED expansion content: sub-pages + sections + provenance.
|
|
334
|
+
Appears for the active dataset in ALL group kinds (DRY). -->
|
|
335
|
+
<div v-if="currentDataset === ds.id && (filteredDatasetPages.length || provenance.owner)" class="px-2 pb-2">
|
|
336
|
+
<nav v-if="filteredDatasetPages.length" class="space-y-0.5 mt-1">
|
|
337
|
+
<router-link
|
|
338
|
+
v-for="page in filteredDatasetPages"
|
|
339
|
+
:key="page.route || 'concepts'"
|
|
340
|
+
:to="pageRoute(page)"
|
|
341
|
+
class="btn-ghost w-full text-left flex items-center gap-2 text-sm"
|
|
342
|
+
:class="isActive(page) ? 'active' : ''"
|
|
343
|
+
@click="closeMobile"
|
|
344
|
+
>
|
|
345
|
+
<NavIcon :name="page.icon" />
|
|
346
|
+
{{ navTitle(page) }}
|
|
347
|
+
</router-link>
|
|
348
|
+
</nav>
|
|
349
|
+
|
|
350
|
+
<!-- Sections tree -->
|
|
351
|
+
<div v-if="getDatasetSections(ds.id).length" class="mt-2 pt-2 border-t border-ink-100/60">
|
|
352
|
+
<button @click="toggleSectionNode(ds.id + '-sections')"
|
|
353
|
+
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[10px] uppercase tracking-wide text-ink-400 hover:text-ink-600 hover:bg-ink-50 transition-colors"
|
|
354
|
+
>
|
|
355
|
+
<span class="w-3 text-[10px]">{{ expandedSectionNodes.has(ds.id + '-sections') ? '▾' : '▸' }}</span>
|
|
356
|
+
<span class="flex-1 text-left">{{ t('nav.sections') }}</span>
|
|
357
|
+
<span class="badge text-[9px] bg-amber-50 text-amber-600 px-1 py-0.5">{{ getDatasetSections(ds.id).length }}</span>
|
|
358
|
+
</button>
|
|
359
|
+
<div v-if="expandedSectionNodes.has(ds.id + '-sections')" class="mt-0.5 max-h-64 overflow-y-auto">
|
|
360
|
+
<button
|
|
361
|
+
@click="clearSectionFilter()"
|
|
362
|
+
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[11px] transition-colors"
|
|
363
|
+
:class="!activeSectionId ? 'bg-ink-800/8 text-blue-700 font-medium' : 'text-ink-500 hover:bg-ink-50'"
|
|
357
364
|
>
|
|
358
|
-
<span class="w-3 text-
|
|
359
|
-
<span class="flex-1 text-left">{{ t('
|
|
360
|
-
<span class="badge text-[9px] bg-amber-50 text-amber-600 px-1 py-0.5">{{ getDatasetSections(ds.id).length }}</span>
|
|
365
|
+
<span class="w-3 text-ink-200">·</span>
|
|
366
|
+
<span class="flex-1 text-left">{{ t('dataset.all') }}</span>
|
|
361
367
|
</button>
|
|
362
|
-
<
|
|
363
|
-
<button
|
|
364
|
-
@click="clearSectionFilter()"
|
|
368
|
+
<template v-for="section in getDatasetSections(ds.id)" :key="section.id">
|
|
369
|
+
<button @click="goToSection(ds.id, 'section-' + section.id)"
|
|
365
370
|
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[11px] transition-colors"
|
|
366
|
-
:class="
|
|
371
|
+
:class="activeSectionId === 'section-' + section.id ? 'bg-ink-800/8 text-blue-700 font-medium' : 'text-ink-500 hover:bg-ink-50'"
|
|
367
372
|
>
|
|
368
|
-
<span class="
|
|
369
|
-
<span class="
|
|
373
|
+
<span v-if="section.children?.length" class="text-[10px] text-ink-300 w-3 cursor-pointer" @click.stop="toggleSectionNode(ds.id + '-s-' + section.id)">{{ expandedSectionNodes.has(ds.id + '-s-' + section.id) ? '▾' : '▸' }}</span>
|
|
374
|
+
<span v-else class="w-3 text-ink-200">·</span>
|
|
375
|
+
<span class="flex-1 text-left truncate">{{ sectionDisplay(section) }}</span>
|
|
370
376
|
</button>
|
|
371
|
-
<
|
|
372
|
-
<button
|
|
377
|
+
<div v-if="section.children?.length && expandedSectionNodes.has(ds.id + '-s-' + section.id)" class="ml-3">
|
|
378
|
+
<button v-for="child in section.children" :key="child.id"
|
|
379
|
+
@click="goToSection(ds.id, 'section-' + child.id)"
|
|
373
380
|
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[11px] transition-colors"
|
|
374
|
-
:class="activeSectionId === 'section-' +
|
|
381
|
+
:class="activeSectionId === 'section-' + child.id ? 'bg-ink-800/8 text-blue-700 font-medium' : 'text-ink-400 hover:bg-ink-50'"
|
|
375
382
|
>
|
|
376
|
-
<span
|
|
377
|
-
<span
|
|
378
|
-
<span class="flex-1 text-left truncate">{{ sectionDisplay(section) }}</span>
|
|
383
|
+
<span class="w-3 text-ink-200">·</span>
|
|
384
|
+
<span class="flex-1 text-left truncate">{{ sectionDisplay(child) }}</span>
|
|
379
385
|
</button>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
@click="goToSection(ds.id, 'section-' + child.id)"
|
|
383
|
-
class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[11px] transition-colors"
|
|
384
|
-
:class="activeSectionId === 'section-' + child.id ? 'bg-ink-800/8 text-blue-700 font-medium' : 'text-ink-400 hover:bg-ink-50'"
|
|
385
|
-
>
|
|
386
|
-
<span class="w-3 text-ink-200">·</span>
|
|
387
|
-
<span class="flex-1 text-left truncate">{{ sectionDisplay(child) }}</span>
|
|
388
|
-
</button>
|
|
389
|
-
</div>
|
|
390
|
-
</template>
|
|
391
|
-
</div>
|
|
386
|
+
</div>
|
|
387
|
+
</template>
|
|
392
388
|
</div>
|
|
389
|
+
</div>
|
|
393
390
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
</div>
|
|
391
|
+
<div v-if="provenance.owner" class="mt-3 pt-3 border-t border-ink-100/60">
|
|
392
|
+
<div class="text-[11px] text-ink-300 space-y-1.5 px-1">
|
|
393
|
+
<div v-if="provenance.ref" class="text-xs font-semibold text-ink-700">
|
|
394
|
+
{{ provenance.ref }}
|
|
395
|
+
</div>
|
|
396
|
+
<div class="flex items-center gap-1">
|
|
397
|
+
<span class="text-ink-400">{{ t('sidebar.publishedBy') }}</span>
|
|
398
|
+
<a v-if="provenance.ownerUrl" :href="provenance.ownerUrl" target="_blank" rel="noopener" class="concept-link font-medium">{{ provenance.owner }}</a>
|
|
399
|
+
<span v-else class="text-ink-600 font-medium">{{ provenance.owner }}</span>
|
|
400
|
+
</div>
|
|
401
|
+
<div v-if="provenance.sourceRepo">
|
|
402
|
+
<a :href="provenance.sourceRepo" target="_blank" rel="noopener" class="concept-link">{{ t('sidebar.viewSource') }}</a>
|
|
407
403
|
</div>
|
|
408
404
|
</div>
|
|
409
405
|
</div>
|
|
410
406
|
</div>
|
|
411
|
-
</
|
|
407
|
+
</div>
|
|
412
408
|
</div>
|
|
413
409
|
</div>
|
|
414
410
|
</template>
|