@glossarist/concept-browser 0.7.37 → 0.7.41

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glossarist/concept-browser",
3
- "version": "0.7.37",
3
+ "version": "0.7.41",
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": {
@@ -74,6 +74,8 @@ const {
74
74
  navigateRelated,
75
75
  } = useConceptEdges(conceptComputed, registerIdComputed, manifestComputed, edgesComputed, router);
76
76
 
77
+ const hoveredEdgeDisplay = ref<{ designation: string; conceptId: string; tooltip: string } | null>(null);
78
+
77
79
  const uriCopied = ref(false);
78
80
  function copyUri() {
79
81
  const uri = conceptUri(props.concept, props.registerId, props.manifest.uriBase);
@@ -473,42 +475,63 @@ const nonVerbalReps = computed(() => {
473
475
  <!-- Relations -->
474
476
  <div v-if="outgoingEdges.length || incomingEdges.length" class="card p-5">
475
477
  <div class="section-label">{{ t('concept.relations') }}</div>
478
+
479
+ <!-- Outgoing -->
476
480
  <div v-if="outgoingEdges.length" class="mt-3">
477
- <div class="text-xs text-ink-300 mb-2">{{ t('concept.outgoing') }} ({{ outgoingEdges.length }})</div>
478
- <div class="space-y-1 max-h-64 overflow-y-auto">
481
+ <div class="text-xs text-ink-300 mb-1.5">{{ t('concept.outgoing') }} ({{ outgoingEdges.length }})</div>
482
+ <div class="space-y-0.5 max-h-56 overflow-y-auto pr-1 -mr-1">
479
483
  <button
480
484
  v-for="edge in outgoingEdges"
481
485
  :key="edge.target + edge.type"
482
486
  @click="navigateEdge(edge)"
483
- :title="getEdgeDisplay(edge.target).tooltip"
484
- class="text-sm concept-link block truncate w-full text-left flex items-center gap-1.5"
487
+ @mouseenter="hoveredEdgeDisplay = getEdgeDisplay(edge.target)"
488
+ @mouseleave="hoveredEdgeDisplay = null"
489
+ @focus="hoveredEdgeDisplay = getEdgeDisplay(edge.target)"
490
+ class="concept-link block w-full text-left rounded-md px-1.5 py-1 hover:bg-ink-50 transition-colors"
485
491
  :class="getEdgeDisplay(edge.target).isLocal ? '' : 'xref-external'"
486
492
  >
487
- <span class="badge text-[9px] flex-shrink-0" :class="edgeBadgeColor(edge.type, 'out')">{{ relationshipLabel(edge.type) }} →</span>
488
- <span class="truncate">{{ getEdgeDisplay(edge.target).designation || edge.label || getEdgeDisplay(edge.target).conceptId }}</span>
489
- <span class="text-[9px] text-ink-300 flex-shrink-0 font-mono">{{ getEdgeDisplay(edge.target).conceptId }}</span>
490
- <span v-if="getEdgeDisplay(edge.target).badge" class="badge badge-gray text-[9px] flex-shrink-0 truncate max-w-[100px]">{{ getEdgeDisplay(edge.target).badge!.title }}</span>
493
+ <div class="flex items-center gap-1 mb-0.5">
494
+ <span class="badge text-[9px] flex-shrink-0" :class="edgeBadgeColor(edge.type, 'out')">{{ relationshipLabel(edge.type) }} →</span>
495
+ <span v-if="getEdgeDisplay(edge.target).badge" class="badge badge-gray text-[9px] flex-shrink-0 truncate">{{ getEdgeDisplay(edge.target).badge!.title }}</span>
496
+ </div>
497
+ <div class="text-sm text-ink-700 leading-snug line-clamp-2">{{ getEdgeDisplay(edge.target).designation || edge.label || getEdgeDisplay(edge.target).conceptId }}</div>
491
498
  </button>
492
499
  </div>
493
500
  </div>
501
+
502
+ <!-- Incoming -->
494
503
  <div v-if="incomingEdges.length" class="mt-3 pt-3 border-t border-ink-100/60">
495
- <div class="text-xs text-ink-300 mb-2">{{ t('concept.incoming') }} ({{ incomingEdges.length }})</div>
496
- <div class="space-y-1 max-h-48 overflow-y-auto">
504
+ <div class="text-xs text-ink-300 mb-1.5">{{ t('concept.incoming') }} ({{ incomingEdges.length }})</div>
505
+ <div class="space-y-0.5 max-h-40 overflow-y-auto pr-1 -mr-1">
497
506
  <button
498
507
  v-for="edge in incomingEdges"
499
508
  :key="edge.source + edge.type"
500
509
  @click="navigateEdge(edge)"
501
- :title="getEdgeDisplay(edge.source).tooltip"
502
- class="text-sm concept-link block truncate w-full text-left flex items-center gap-1.5"
510
+ @mouseenter="hoveredEdgeDisplay = getEdgeDisplay(edge.source)"
511
+ @mouseleave="hoveredEdgeDisplay = null"
512
+ @focus="hoveredEdgeDisplay = getEdgeDisplay(edge.source)"
513
+ class="concept-link block w-full text-left rounded-md px-1.5 py-1 hover:bg-ink-50 transition-colors"
503
514
  :class="getEdgeDisplay(edge.source).isLocal ? '' : 'xref-external'"
504
515
  >
505
- <span class="badge text-[9px] flex-shrink-0" :class="edgeBadgeColor(edge.type, 'in')">← {{ relationshipLabel(inverseEdgeType(edge.type)) }}</span>
506
- <span class="truncate">{{ getEdgeDisplay(edge.source).designation || edge.label || getEdgeDisplay(edge.source).conceptId }}</span>
507
- <span class="text-[9px] text-ink-300 flex-shrink-0 font-mono">{{ getEdgeDisplay(edge.source).conceptId }}</span>
508
- <span v-if="getEdgeDisplay(edge.source).badge" class="badge badge-gray text-[9px] flex-shrink-0 truncate max-w-[100px]">{{ getEdgeDisplay(edge.source).badge!.title }}</span>
516
+ <div class="flex items-center gap-1 mb-0.5">
517
+ <span class="badge text-[9px] flex-shrink-0" :class="edgeBadgeColor(edge.type, 'in')">← {{ relationshipLabel(inverseEdgeType(edge.type)) }}</span>
518
+ <span v-if="getEdgeDisplay(edge.source).badge" class="badge badge-gray text-[9px] flex-shrink-0 truncate">{{ getEdgeDisplay(edge.source).badge!.title }}</span>
519
+ </div>
520
+ <div class="text-sm text-ink-700 leading-snug line-clamp-2">{{ getEdgeDisplay(edge.source).designation || edge.label || getEdgeDisplay(edge.source).conceptId }}</div>
509
521
  </button>
510
522
  </div>
511
523
  </div>
524
+
525
+ <!-- Hover detail strip (fixed area at bottom of card) -->
526
+ <Transition name="fade">
527
+ <div
528
+ v-if="hoveredEdgeDisplay"
529
+ class="mt-3 pt-3 border-t border-ink-100/60"
530
+ >
531
+ <div class="text-xs text-ink-300 mb-0.5">{{ t('concept.identifier') || 'Identifier' }}</div>
532
+ <div class="font-mono text-[10px] text-ink-500 break-all leading-tight">{{ hoveredEdgeDisplay.conceptId }}</div>
533
+ </div>
534
+ </Transition>
512
535
  </div>
513
536
 
514
537
  <!-- Domains -->
@@ -659,3 +682,14 @@ const nonVerbalReps = computed(() => {
659
682
  </div>
660
683
  </div>
661
684
  </template>
685
+
686
+ <style scoped>
687
+ .fade-enter-active,
688
+ .fade-leave-active {
689
+ transition: opacity 0.15s ease;
690
+ }
691
+ .fade-enter-from,
692
+ .fade-leave-to {
693
+ opacity: 0;
694
+ }
695
+ </style>
@@ -58,12 +58,13 @@ export function useConceptEdges(
58
58
  const designation = node
59
59
  ? (node.designations[locale.value] || node.designations.eng || Object.values(node.designations)[0] || '')
60
60
  : '';
61
- const tooltipLines: string[] = [uri];
61
+ const tooltipLines: string[] = [conceptId];
62
62
  if (node) {
63
63
  for (const [lang, des] of Object.entries(node.designations)) {
64
64
  tooltipLines.push(`${langLabel(lang)}: ${des}`);
65
65
  }
66
66
  }
67
+ tooltipLines.push(uri);
67
68
  let badge: { id: string; title: string } | null = null;
68
69
  if (resolution.type === 'internal' && resolution.registerId !== registerId.value) {
69
70
  const m = store.manifests.get(resolution.registerId);
package/src/style.css CHANGED
@@ -334,6 +334,35 @@
334
334
  color: #dddde6;
335
335
  }
336
336
 
337
+ /* ── Brand colors: lighten for dark backgrounds ── */
338
+ /* ISO red (#e3000f) is too harsh on dark — use a softer coral */
339
+ .dark {
340
+ --brand-primary: #ff5d5d;
341
+ --brand-primary-rgb: 255, 93, 93;
342
+ --brand-dark: #1a1b2e;
343
+ }
344
+
345
+ /* Concept/xref links: lighten in dark mode (override pure red) */
346
+ .dark .concept-link,
347
+ .dark .xref-link {
348
+ color: #ff6b6b;
349
+ }
350
+ .dark .concept-link:hover,
351
+ .dark .xref-link:hover {
352
+ filter: brightness(1.15);
353
+ }
354
+
355
+ /* Brand badges: readable background in dark mode */
356
+ .dark .badge-brand {
357
+ background-color: rgba(255, 93, 93, 0.15);
358
+ color: #ff8a8a;
359
+ }
360
+
361
+ /* Primary buttons: avoid harsh red hover in dark mode */
362
+ .dark .btn-primary:hover {
363
+ background-color: #c41818;
364
+ }
365
+
337
366
  /* ── Surfaces ── */
338
367
  .dark .bg-surface { background-color: #0f1020 !important; }
339
368
  .dark .bg-surface-alt { background-color: #161728 !important; }