@glossarist/concept-browser 0.4.9 → 0.4.12

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.4.9",
3
+ "version": "0.4.12",
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": {
@@ -22,7 +22,6 @@ const {
22
22
  taxonomyKeys,
23
23
  taxonomyLabels,
24
24
  treeRoots,
25
- supportingClasses,
26
25
  toggleExpand,
27
26
  childClasses,
28
27
  hasChildren,
@@ -167,19 +166,6 @@ function selectTaxonomy(key: string) {
167
166
  </div>
168
167
  </template>
169
168
 
170
- <!-- Supporting classes -->
171
- <div v-if="supportingClasses.length" class="mt-2 pt-2 border-t border-ink-100/40">
172
- <div class="text-[10px] uppercase tracking-wide text-ink-300 mb-1 px-2">Supporting</div>
173
- <button v-for="cls in supportingClasses" :key="cls.compact"
174
- @click="selectClass(cls.compact)"
175
- class="w-full flex items-center gap-1.5 px-2 py-1 rounded-lg text-[11px] transition-colors"
176
- :class="activeClassId === cls.compact && !activeTaxonomy ? 'bg-ink-800/8 text-blue-700 font-medium' : 'text-ink-400 hover:bg-ink-50'"
177
- >
178
- <span class="w-3 text-ink-200">·</span>
179
- <span class="flex-1 text-left">{{ cls.label }}</span>
180
- </button>
181
- </div>
182
-
183
169
  <!-- SKOS Taxonomies -->
184
170
  <div class="mt-2 pt-2 border-t border-ink-100/40">
185
171
  <div class="text-[10px] uppercase tracking-wide text-ink-300 mb-1 px-2">Taxonomies</div>
@@ -15,6 +15,7 @@ import { useDsStyle } from '../utils/dataset-style';
15
15
  import { getFactory } from '../adapters/factory';
16
16
  import { useRenderOptions } from '../composables/use-render-options';
17
17
  import { categorizeRelationship, relationshipLabel, relationshipDefinition } from '../utils/relationship-categories';
18
+ import { useSiteConfig } from '../config/use-site-config';
18
19
  import ConceptTimeline from './ConceptTimeline.vue';
19
20
  import ConceptRdfView from './ConceptRdfView.vue';
20
21
  import FormatDownloads from './FormatDownloads.vue';
@@ -32,6 +33,7 @@ const props = defineProps<{
32
33
  const router = useRouter();
33
34
  const store = useVocabularyStore();
34
35
  const { getColor } = useDsStyle();
36
+ const { config: siteConfig } = useSiteConfig();
35
37
  const factory = getFactory();
36
38
 
37
39
  const activeTab = ref<'rdf' | 'definition' | 'history'>('definition');
@@ -75,17 +77,9 @@ const languages = computed(() => {
75
77
  });
76
78
  });
77
79
 
78
- // Collapsible language sections — auto-collapse non-eng when 6+ languages
80
+ // Collapsible language sections — expand all with content, collapse those without
79
81
  const collapsedLangs = ref(new Set<string>());
80
82
 
81
- function initCollapsed(langs: string[]) {
82
- if (langs.length >= 6) {
83
- collapsedLangs.value = new Set(langs.filter(l => l !== 'eng'));
84
- }
85
- }
86
-
87
- watch(languages, (langs) => { initCollapsed(langs); }, { immediate: true });
88
-
89
83
  const engConcept = computed((): LocalizedConcept | null => {
90
84
  return props.concept.localization('eng') ?? null;
91
85
  });
@@ -192,6 +186,20 @@ function hasContent(lc: LangContent): boolean {
192
186
  return !!(lc.definition || lc.notes.length || lc.examples.length || lc.sources.length);
193
187
  }
194
188
 
189
+ function initCollapsed() {
190
+ const mainLangs = siteConfig.value?.defaults?.mainLanguages || [];
191
+ const mainSet = new Set(mainLangs.length ? mainLangs : ['eng']);
192
+ const collapsed = new Set<string>();
193
+ for (const lc of allLangContent.value) {
194
+ if (!hasContent(lc) && !mainSet.has(lc.lang)) {
195
+ collapsed.add(lc.lang);
196
+ }
197
+ }
198
+ collapsedLangs.value = collapsed;
199
+ }
200
+
201
+ watch(languages, () => { initCollapsed(); }, { immediate: true });
202
+
195
203
  const allCollapsed = computed(() => collapsedLangs.value.size === allLangContent.value.length);
196
204
 
197
205
  function toggleLang(lang: string) {
@@ -115,6 +115,7 @@ interface SimNode extends SimulationNodeDatum {
115
115
  register: string;
116
116
  conceptId: string;
117
117
  designation: string;
118
+ altDesignations: string[];
118
119
  hasDesignation: boolean;
119
120
  loaded: boolean;
120
121
  nodeType?: 'concept' | 'domain';
@@ -178,11 +179,15 @@ function buildSimulation(width: number, height: number) {
178
179
  const simNodes: SimNode[] = renderNodes.map(n => {
179
180
  const lang = uiStore.selectedLang;
180
181
  const desig = n.designations[lang] || Object.values(n.designations)[0] || '';
182
+ const alts = Object.entries(n.designations)
183
+ .filter(([l, t]) => l !== lang && t && t !== desig)
184
+ .map(([, t]) => t);
181
185
  return {
182
186
  uri: n.uri,
183
187
  register: n.register,
184
188
  conceptId: n.conceptId,
185
189
  designation: desig,
190
+ altDesignations: alts,
186
191
  hasDesignation: !!n.designations[lang],
187
192
  loaded: n.loaded,
188
193
  nodeType: n.nodeType,
@@ -272,6 +277,20 @@ function buildSimulation(width: number, height: number) {
272
277
  return '#636588';
273
278
  });
274
279
 
280
+ conceptNodes.append('text')
281
+ .attr('dy', -9)
282
+ .attr('y', 7)
283
+ .attr('text-anchor', 'middle')
284
+ .attr('font-size', '6px')
285
+ .attr('font-family', '"DM Sans", system-ui, sans-serif')
286
+ .attr('fill', '#a0a1b5')
287
+ .attr('pointer-events', 'none')
288
+ .text(d => {
289
+ if (labelMode.value !== 'designation') return '';
290
+ const alts = d.altDesignations.slice(0, 2);
291
+ return alts.join(' · ');
292
+ });
293
+
275
294
  const dragBehavior = drag<SVGGElement, SimNode>()
276
295
  .on('start', (event: D3DragEvent<SVGGElement, SimNode, SimNode>, d) => {
277
296
  if (!event.active) simulation?.alphaTarget(0.3).restart();
@@ -2,7 +2,6 @@ import { ref, computed } from 'vue';
2
2
  import {
3
3
  getClass,
4
4
  getClassTree,
5
- getAllClasses,
6
5
  type OwlClass,
7
6
  } from '../adapters/ontology-schema';
8
7
 
@@ -53,15 +52,6 @@ function hasChildren(cls: OwlClass): boolean {
53
52
 
54
53
  const treeRoots = getClassTree();
55
54
 
56
- const supportingClasses = computed(() =>
57
- getAllClasses().filter(
58
- c => c.children.length === 0
59
- && !c.subClassOf?.startsWith('gloss:')
60
- && c.compact !== 'gloss:Concept'
61
- && c.compact !== 'gloss:ConceptCollection'
62
- )
63
- );
64
-
65
55
  const allNavItems = computed(() => {
66
56
  const items: { id: string; label: string; depth: number }[] = [];
67
57
  function walk(classes: OwlClass[], depth: number) {
@@ -82,7 +72,6 @@ export function useOntologyNav() {
82
72
  taxonomyKeys,
83
73
  taxonomyLabels,
84
74
  treeRoots,
85
- supportingClasses,
86
75
  allNavItems,
87
76
  toggleExpand,
88
77
  childClasses,
@@ -152,6 +152,7 @@ export interface SiteConfig {
152
152
  defaults: {
153
153
  language?: string;
154
154
  languageOrder?: string[];
155
+ mainLanguages?: string[];
155
156
  };
156
157
  email?: string;
157
158
  pages?: PageConfig[];
@@ -27,7 +27,7 @@ export interface RuntimeSiteConfig {
27
27
  social?: Record<string, string>;
28
28
  nav?: { label: string; route: string }[];
29
29
  footerNav?: { label: string; route: string }[];
30
- defaults?: { language?: string; languageOrder?: string[] };
30
+ defaults?: { language?: string; languageOrder?: string[]; mainLanguages?: string[] };
31
31
  email?: string;
32
32
  pages?: PageConfig[];
33
33
  contributors?: { name: string; role?: string; organization?: string; url?: string; email?: string }[];
@@ -15,7 +15,7 @@ const manifest = computed(() => store.manifests.get(resolvedId.value));
15
15
  </script>
16
16
 
17
17
  <template>
18
- <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
18
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
19
19
  <!-- Breadcrumb -->
20
20
  <nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-ink-400 mb-6">
21
21
  <router-link :to="{ name: 'home' }" class="hover:text-ink-700 transition-colors">Home</router-link>
@@ -14,7 +14,7 @@ const contributors = config.value?.contributors as Contributor[] | undefined;
14
14
  </script>
15
15
 
16
16
  <template>
17
- <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
17
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
18
18
  <nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-ink-400 mb-6">
19
19
  <router-link :to="{ name: 'home' }" class="hover:text-ink-700 transition-colors">Home</router-link>
20
20
  <span class="text-ink-200">/</span>
@@ -78,7 +78,7 @@ function formatDate(dateStr: string) {
78
78
  </script>
79
79
 
80
80
  <template>
81
- <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
81
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
82
82
  <nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-ink-400 mb-6">
83
83
  <router-link :to="{ name: 'home' }" class="hover:text-ink-700 transition-colors">Home</router-link>
84
84
  <span class="text-ink-200">/</span>
@@ -43,7 +43,7 @@ onMounted(async () => {
43
43
  </script>
44
44
 
45
45
  <template>
46
- <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
46
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
47
47
  <nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-ink-400 mb-6">
48
48
  <router-link :to="{ name: 'home' }" class="hover:text-ink-700 transition-colors">Home</router-link>
49
49
  <template v-if="registerId">
@@ -47,7 +47,7 @@ onMounted(async () => {
47
47
  </script>
48
48
 
49
49
  <template>
50
- <div class="max-w-3xl mx-auto px-4 py-16 text-center">
50
+ <div class="max-w-5xl mx-auto px-4 py-16 text-center">
51
51
  <template v-if="error">
52
52
  <h1 class="text-2xl font-serif text-ink-800 mb-4">Concept not found</h1>
53
53
  <p class="text-ink-500 mb-2">The following concept URI could not be resolved:</p>
@@ -68,7 +68,7 @@ function coverageColor(ratio: number): string {
68
68
  </script>
69
69
 
70
70
  <template>
71
- <div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
71
+ <div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
72
72
  <!-- Breadcrumb -->
73
73
  <nav aria-label="Breadcrumb" class="flex items-center gap-1.5 text-sm text-ink-400 mb-6">
74
74
  <router-link :to="{ name: 'home' }" class="hover:text-ink-700 transition-colors">Home</router-link>