@glossarist/concept-browser 0.1.7 → 0.1.8
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/scripts/generate-data.mjs +25 -0
- package/src/adapters/types.ts +1 -0
- package/src/config/types.ts +17 -0
- package/src/views/DatasetView.vue +38 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glossarist/concept-browser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
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": {
|
|
@@ -373,6 +373,30 @@ function processDataset(dir, register, opts) {
|
|
|
373
373
|
};
|
|
374
374
|
}
|
|
375
375
|
|
|
376
|
+
// Copy bulk format files from compiled/ directory (full GCR)
|
|
377
|
+
const compiledDir = path.join(ROOT, '.datasets', register, 'compiled');
|
|
378
|
+
const bulkFormats = [];
|
|
379
|
+
if (fs.existsSync(compiledDir)) {
|
|
380
|
+
for (const file of fs.readdirSync(compiledDir)) {
|
|
381
|
+
const src = path.join(compiledDir, file);
|
|
382
|
+
const dest = path.join(DATA, register, file);
|
|
383
|
+
fs.copyFileSync(src, dest);
|
|
384
|
+
const ext = path.extname(file);
|
|
385
|
+
const formatMap = {
|
|
386
|
+
'.ttl': 'turtle',
|
|
387
|
+
'.jsonld': 'jsonld',
|
|
388
|
+
'.xml': 'tbx',
|
|
389
|
+
'.jsonl': 'jsonl',
|
|
390
|
+
'.yaml': 'yaml',
|
|
391
|
+
};
|
|
392
|
+
const formatName = formatMap[ext] || ext.slice(1);
|
|
393
|
+
bulkFormats.push({ file, format: formatName, size: fs.statSync(src).size });
|
|
394
|
+
}
|
|
395
|
+
if (bulkFormats.length) {
|
|
396
|
+
console.log(` Copied ${bulkFormats.length} bulk format files`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
376
400
|
const manifest = {
|
|
377
401
|
id: register,
|
|
378
402
|
datasetUri: opts.datasetUri,
|
|
@@ -396,6 +420,7 @@ function processDataset(dir, register, opts) {
|
|
|
396
420
|
color: opts.color,
|
|
397
421
|
languageStats: langStats,
|
|
398
422
|
availableFormats,
|
|
423
|
+
bulkFormats,
|
|
399
424
|
};
|
|
400
425
|
if (opts.languageOrder) manifest.languageOrder = opts.languageOrder;
|
|
401
426
|
writeJson(path.join(DATA, register, 'manifest.json'), manifest);
|
package/src/adapters/types.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface Manifest {
|
|
|
25
25
|
languageOrder?: string[];
|
|
26
26
|
languageStats?: Record<string, { terms: number; definitions: number }>;
|
|
27
27
|
availableFormats?: string[];
|
|
28
|
+
bulkFormats?: { file: string; format: string; size: number }[];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export interface ConceptIndex {
|
package/src/config/types.ts
CHANGED
|
@@ -90,8 +90,25 @@ export interface DatasetConfig {
|
|
|
90
90
|
color?: string;
|
|
91
91
|
tags?: string[];
|
|
92
92
|
languageOrder?: string[];
|
|
93
|
+
downloads?: string[];
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
// === Downloads ===
|
|
97
|
+
|
|
98
|
+
export interface BulkFormatInfo {
|
|
99
|
+
file: string;
|
|
100
|
+
format: string;
|
|
101
|
+
size: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export const FORMAT_LABELS: Record<string, string> = {
|
|
105
|
+
turtle: 'Turtle (RDF)',
|
|
106
|
+
jsonld: 'JSON-LD (SKOS)',
|
|
107
|
+
tbx: 'TBX-XML',
|
|
108
|
+
jsonl: 'JSONL',
|
|
109
|
+
yaml: 'YAML',
|
|
110
|
+
};
|
|
111
|
+
|
|
95
112
|
// === Pages ===
|
|
96
113
|
|
|
97
114
|
export type PageType = 'news' | 'contributors' | 'about' | 'stats' | 'custom';
|
|
@@ -3,6 +3,7 @@ import { computed, ref, watch, onMounted, onUnmounted } from 'vue';
|
|
|
3
3
|
import { useVocabularyStore } from '../stores/vocabulary';
|
|
4
4
|
import { useDsStyle } from '../utils/dataset-style';
|
|
5
5
|
import { useDatasetLoader } from '../composables/use-dataset-loader';
|
|
6
|
+
import { FORMAT_LABELS } from '../config/types';
|
|
6
7
|
import ConceptCard from '../components/ConceptCard.vue';
|
|
7
8
|
|
|
8
9
|
const props = defineProps<{ registerId: string }>();
|
|
@@ -15,6 +16,23 @@ const manifest = computed(() => store.manifests.get(props.registerId));
|
|
|
15
16
|
const adapter = computed(() => store.datasets.get(props.registerId));
|
|
16
17
|
const chunkLoading = ref(false);
|
|
17
18
|
|
|
19
|
+
function formatSize(bytes: number): string {
|
|
20
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
21
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
22
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const bulkDownloads = computed(() => {
|
|
26
|
+
const m = manifest.value;
|
|
27
|
+
if (!m?.bulkFormats?.length) return [];
|
|
28
|
+
return m.bulkFormats.map(f => ({
|
|
29
|
+
...f,
|
|
30
|
+
url: `${m.baseUrl}/${f.file}`,
|
|
31
|
+
label: FORMAT_LABELS[f.format] || f.format.toUpperCase(),
|
|
32
|
+
sizeLabel: formatSize(f.size),
|
|
33
|
+
}));
|
|
34
|
+
});
|
|
35
|
+
|
|
18
36
|
const totalConceptCount = computed(() => adapter.value?.getConceptCount() ?? 0);
|
|
19
37
|
|
|
20
38
|
const filter = ref('');
|
|
@@ -145,6 +163,26 @@ function goToPage(p: number) {
|
|
|
145
163
|
</div>
|
|
146
164
|
</div>
|
|
147
165
|
|
|
166
|
+
<!-- Downloads -->
|
|
167
|
+
<div v-if="bulkDownloads.length" class="card p-4 mb-6">
|
|
168
|
+
<h3 class="text-xs font-semibold text-ink-400 uppercase tracking-wide mb-3">Download</h3>
|
|
169
|
+
<div class="flex flex-wrap gap-2">
|
|
170
|
+
<a
|
|
171
|
+
v-for="dl in bulkDownloads"
|
|
172
|
+
:key="dl.file"
|
|
173
|
+
:href="dl.url"
|
|
174
|
+
download
|
|
175
|
+
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg border border-ink-100 bg-surface-raised text-sm font-medium text-ink-700 hover:bg-ink-50 hover:border-ink-200 transition-colors"
|
|
176
|
+
>
|
|
177
|
+
<svg class="w-3.5 h-3.5 text-ink-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
178
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
179
|
+
</svg>
|
|
180
|
+
{{ dl.label }}
|
|
181
|
+
<span class="text-ink-300 text-xs">{{ dl.sizeLabel }}</span>
|
|
182
|
+
</a>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
148
186
|
<!-- Loading state (initial dataset load) -->
|
|
149
187
|
<div v-if="loading || (!adapter?.index && !localError)" class="space-y-4 py-4">
|
|
150
188
|
<div class="space-y-2">
|