Skip to content

Commit 081d930

Browse files
committed
feat: add error handling and i18n support for model descriptions
Add error handling for AOS and ParticlesJS initialization to prevent failures when libraries are not loaded. Implement internationalization support for model descriptions, allowing them to be displayed in multiple languages based on user preference. Add fallback rendering for organization logos with generated avatars when images fail to load. Changes: - Wrap AOS and ParticlesJS initialization in typeof checks - Add i18n support for model descriptions with language fallback - Update filter logic to handle multilingual descriptions - Implement logo fallback UI with organization initial avatars - Improve error resilience for optional UI libraries
1 parent d3ac8e1 commit 081d930

2 files changed

Lines changed: 200 additions & 47 deletions

File tree

docs/js/app.js

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
// Initialize AOS (Animate On Scroll)
2-
AOS.init({
3-
duration: 800,
4-
easing: 'ease-in-out',
5-
once: true,
6-
offset: 100
7-
});
1+
// Initialize AOS (Animate On Scroll) - with error handling
2+
if (typeof AOS !== 'undefined') {
3+
AOS.init({
4+
duration: 800,
5+
easing: 'ease-in-out',
6+
once: true,
7+
offset: 100
8+
});
9+
}
810

9-
// Initialize Particles.js
10-
particlesJS('particles-js', {
11-
particles: {
11+
// Initialize Particles.js - with error handling
12+
if (typeof particlesJS !== 'undefined') {
13+
particlesJS('particles-js', {
14+
particles: {
1215
number: {
1316
value: 80,
1417
density: {
@@ -85,7 +88,8 @@ particlesJS('particles-js', {
8588
}
8689
},
8790
retina_detect: true
88-
});
91+
});
92+
}
8993

9094
// Scroll Progress Bar
9195
window.addEventListener('scroll', () => {
@@ -231,10 +235,16 @@ function applyFilters() {
231235
filteredModels = allModels.filter(model => {
232236
const matchesOrg = selectedOrg === 'all' || model.org === selectedOrg;
233237
const matchesType = selectedType === 'all' || model.tags.includes(selectedType);
238+
239+
// Get description text based on current language
240+
const description = typeof model.description === 'object'
241+
? (model.description[i18n.getCurrentLanguage()] || model.description['zh-CN'] || '')
242+
: (model.description || '');
243+
234244
const matchesSearch = !searchTerm ||
235245
model.name.toLowerCase().includes(searchTerm) ||
236246
model.org.toLowerCase().includes(searchTerm) ||
237-
model.description.toLowerCase().includes(searchTerm);
247+
description.toLowerCase().includes(searchTerm);
238248

239249
return matchesOrg && matchesType && matchesSearch;
240250
});
@@ -284,7 +294,9 @@ function renderModels() {
284294
}).join('');
285295

286296
// Reinitialize AOS for new elements
287-
AOS.refresh();
297+
if (typeof AOS !== 'undefined') {
298+
AOS.refresh();
299+
}
288300
}
289301

290302
// Create Timeline Card
@@ -297,6 +309,17 @@ function createTimelineCard(model, isLeft, index) {
297309
day: 'numeric'
298310
});
299311

312+
// Get description based on current language
313+
const description = typeof model.description === 'object'
314+
? (model.description[i18n.getCurrentLanguage()] || model.description['zh-CN'] || '')
315+
: (model.description || '');
316+
317+
// Create logo HTML with fallback
318+
const logoHtml = model.logoUrl
319+
? `<img src="${model.logoUrl}" alt="${model.org}" class="w-6 h-6 rounded-full border-2 border-gray-200 dark:border-gray-600 object-cover" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';" />
320+
<div class="w-6 h-6 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center text-white text-xs font-bold" style="display:none;">${model.org.charAt(0)}</div>`
321+
: `<div class="w-6 h-6 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center text-white text-xs font-bold">${model.org.charAt(0)}</div>`;
322+
300323
const tags = model.tags.map(tag => {
301324
const colors = {
302325
'LLM': 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
@@ -319,19 +342,22 @@ function createTimelineCard(model, isLeft, index) {
319342
<div class="flex-1 max-w-xl">
320343
<div class="timeline-card bg-white dark:bg-gray-800 rounded-xl p-6 shadow-lg border border-gray-200 dark:border-gray-700 hover:shadow-2xl hover:shadow-primary/20 transition-all duration-300 hover:scale-105 group">
321344
<div class="flex items-start justify-between mb-3">
322-
<div>
345+
<div class="flex-1">
323346
<h3 class="text-xl font-bold text-gray-900 dark:text-white mb-1 group-hover:text-primary transition-colors">
324347
${model.name}
325348
</h3>
326-
<p class="text-sm text-gray-500 dark:text-gray-400">${model.org}</p>
349+
<div class="flex items-center gap-2">
350+
${logoHtml}
351+
<p class="text-sm text-gray-500 dark:text-gray-400">${model.org}</p>
352+
</div>
327353
</div>
328-
<span class="text-xs px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-gray-600 dark:text-gray-400 font-mono">
354+
<span class="text-xs px-3 py-1 bg-gray-100 dark:bg-gray-700 rounded-full text-gray-600 dark:text-gray-400 font-mono whitespace-nowrap ml-2">
329355
${formattedDate}
330356
</span>
331357
</div>
332358
333359
<p class="text-gray-600 dark:text-gray-300 mb-4 text-sm">
334-
${model.description}
360+
${description}
335361
</p>
336362
337363
<div class="flex items-center justify-between">
@@ -362,6 +388,17 @@ function createGridCard(model, index) {
362388
day: 'numeric'
363389
});
364390

391+
// Get description based on current language
392+
const description = typeof model.description === 'object'
393+
? (model.description[i18n.getCurrentLanguage()] || model.description['zh-CN'] || '')
394+
: (model.description || '');
395+
396+
// Create logo HTML with fallback
397+
const logoHtml = model.logoUrl
398+
? `<img src="${model.logoUrl}" alt="${model.org}" class="w-8 h-8 rounded-full border-2 border-gray-200 dark:border-gray-600 object-cover" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';" />
399+
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center text-white text-sm font-bold" style="display:none;">${model.org.charAt(0)}</div>`
400+
: `<div class="w-8 h-8 rounded-full bg-gradient-to-br from-primary to-secondary flex items-center justify-center text-white text-sm font-bold">${model.org.charAt(0)}</div>`;
401+
365402
const tags = model.tags.map(tag => {
366403
const colors = {
367404
'LLM': 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
@@ -385,9 +422,13 @@ function createGridCard(model, index) {
385422
</span>
386423
</div>
387424
388-
<p class="text-sm text-gray-500 dark:text-gray-400 mb-2">${model.org}</p>
425+
<div class="flex items-center gap-2 mb-3">
426+
${logoHtml}
427+
<p class="text-sm text-gray-500 dark:text-gray-400">${model.org}</p>
428+
</div>
429+
389430
<p class="text-gray-600 dark:text-gray-300 mb-4 text-sm line-clamp-2">
390-
${model.description}
431+
${description}
391432
</p>
392433
393434
<div class="flex gap-2 flex-wrap mb-4">

0 commit comments

Comments
 (0)