Skip to content

Commit 6aef141

Browse files
author
Victorio Nascimento
committed
Added sync
1 parent 494a7c6 commit 6aef141

1 file changed

Lines changed: 127 additions & 59 deletions

File tree

script.js

Lines changed: 127 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const state = {
66
folderCache: {},
77
currentView: 'loading',
88
currentPath: [],
9-
currentItem: null
9+
currentItem: null,
10+
isLoading: true,
11+
isInitialized: false
1012
};
1113

1214
// Utility
@@ -15,18 +17,27 @@ function getRepoPath() {
1517
return parts[1] && parts[2] ? `${parts[1]}/${parts[2]}` : 'Vic-Nas/PythonSolutions';
1618
}
1719

18-
// Fetch folder contents
20+
// Fetch folder contents with cache busting and validation
1921
async function fetchFolderContents(path) {
20-
if (state.folderCache[path]) {
21-
return state.folderCache[path];
22+
const cacheKey = path;
23+
const cached = state.folderCache[cacheKey];
24+
25+
// Cache for 5 minutes
26+
if (cached && Date.now() - cached.timestamp < 300000) {
27+
return cached.data;
2228
}
2329

2430
try {
25-
const res = await fetch(`https://api.github.com/repos/${getRepoPath()}/contents/${path}`);
31+
const res = await fetch(`https://api.github.com/repos/${getRepoPath()}/contents/${path}`, {
32+
cache: 'no-cache' // Force fresh data from GitHub
33+
});
2634
if (!res.ok) return null;
2735

2836
const items = await res.json();
29-
state.folderCache[path] = items;
37+
state.folderCache[cacheKey] = {
38+
data: items,
39+
timestamp: Date.now()
40+
};
3041
return items;
3142
} catch (err) {
3243
console.error(`Error fetching ${path}:`, err);
@@ -44,61 +55,79 @@ function hasFiles(items) {
4455
);
4556
}
4657

47-
// Load all platforms
58+
// Load all platforms with proper error handling
4859
async function loadPlatforms() {
4960
console.log('Loading platforms...');
50-
const rootItems = await fetchFolderContents('');
51-
if (!rootItems) return;
52-
53-
const platformFolders = rootItems.filter(item =>
54-
item.type === 'dir' &&
55-
!['utils', '.git'].includes(item.name) &&
56-
!item.name.startsWith('.')
57-
);
5861

59-
for (const folder of platformFolders) {
60-
const platformData = {
61-
name: folder.name,
62-
path: folder.name,
63-
image: null,
64-
count: 0
65-
};
62+
try {
63+
const rootItems = await fetchFolderContents('');
64+
if (!rootItems) {
65+
console.error('Failed to load root items');
66+
return;
67+
}
68+
69+
const platformFolders = rootItems.filter(item =>
70+
item.type === 'dir' &&
71+
!['utils', '.git'].includes(item.name) &&
72+
!item.name.startsWith('.')
73+
);
74+
75+
// Load platforms sequentially to avoid race conditions
76+
const platforms = [];
6677

67-
// Check for platform.png
68-
const contents = await fetchFolderContents(folder.name);
69-
if (contents) {
70-
const platformImg = contents.find(f => f.name === 'platform.png');
71-
if (platformImg) {
72-
// Use the download_url from GitHub API
73-
platformData.image = platformImg.download_url || `${folder.name}/platform.png`;
78+
for (const folder of platformFolders) {
79+
const platformData = {
80+
name: folder.name,
81+
path: folder.name,
82+
image: null,
83+
count: 0
84+
};
85+
86+
// Check for platform.png
87+
const contents = await fetchFolderContents(folder.name);
88+
if (contents) {
89+
const platformImg = contents.find(f => f.name === 'platform.png');
90+
if (platformImg) {
91+
platformData.image = platformImg.download_url || `${folder.name}/platform.png`;
92+
}
93+
94+
// Count items recursively
95+
platformData.count = await countItems(folder.name);
7496
}
7597

76-
// Count items recursively
77-
platformData.count = await countItems(folder.name);
98+
platforms.push(platformData);
7899
}
79100

80-
state.platforms.push(platformData);
101+
// Sort and assign only after all data is loaded
102+
platforms.sort((a, b) => a.name.localeCompare(b.name));
103+
state.platforms = platforms;
104+
105+
console.log('Loaded platforms:', state.platforms);
106+
} catch (err) {
107+
console.error('Error loading platforms:', err);
81108
}
82-
83-
state.platforms.sort((a, b) => a.name.localeCompare(b.name));
84-
console.log('Loaded platforms:', state.platforms);
85109
}
86110

87111
// Recursively count problem items
88112
async function countItems(path) {
89-
const items = await fetchFolderContents(path);
90-
if (!items) return 0;
91-
92-
if (hasFiles(items)) return 1;
93-
94-
const subdirs = items.filter(i => i.type === 'dir');
95-
let count = 0;
96-
97-
for (const dir of subdirs) {
98-
count += await countItems(`${path}/${dir.name}`);
113+
try {
114+
const items = await fetchFolderContents(path);
115+
if (!items) return 0;
116+
117+
if (hasFiles(items)) return 1;
118+
119+
const subdirs = items.filter(i => i.type === 'dir');
120+
let count = 0;
121+
122+
for (const dir of subdirs) {
123+
count += await countItems(`${path}/${dir.name}`);
124+
}
125+
126+
return count;
127+
} catch (err) {
128+
console.error(`Error counting items in ${path}:`, err);
129+
return 0;
99130
}
100-
101-
return count;
102131
}
103132

104133
// Parse hash to navigate
@@ -129,10 +158,14 @@ function render() {
129158
console.log('Rendering view:', state.currentView, 'path:', state.currentPath);
130159

131160
const views = ['loading-screen', 'platform-selector', 'folder-view', 'problem-view'];
132-
views.forEach(v => document.getElementById(v).style.display = 'none');
161+
views.forEach(v => {
162+
const el = document.getElementById(v);
163+
if (el) el.style.display = 'none';
164+
});
133165

134166
if (state.currentView === 'loading') {
135-
document.getElementById('loading-screen').style.display = 'flex';
167+
const el = document.getElementById('loading-screen');
168+
if (el) el.style.display = 'flex';
136169
} else if (state.currentView === 'platforms') {
137170
renderPlatforms();
138171
} else if (state.currentView === 'folder') {
@@ -143,10 +176,19 @@ function render() {
143176
}
144177

145178
function renderPlatforms() {
146-
document.getElementById('platform-selector').style.display = 'block';
179+
const selector = document.getElementById('platform-selector');
147180
const grid = document.getElementById('platform-grid');
181+
182+
if (!selector || !grid) return;
183+
184+
selector.style.display = 'block';
148185
grid.innerHTML = '';
149186

187+
if (state.platforms.length === 0) {
188+
grid.innerHTML = '<p style="grid-column: 1/-1; text-align: center;">No platforms found</p>';
189+
return;
190+
}
191+
150192
state.platforms.forEach(platform => {
151193
const card = document.createElement('button');
152194
card.className = 'platform-box';
@@ -171,6 +213,8 @@ function renderPlatforms() {
171213

172214
async function renderFolder() {
173215
const view = document.getElementById('folder-view');
216+
if (!view) return;
217+
174218
view.style.display = 'block';
175219

176220
const pathStr = state.currentPath.join('/');
@@ -186,14 +230,17 @@ async function renderFolder() {
186230

187231
// Set title
188232
const titleParts = state.currentPath.map(capitalize);
189-
document.getElementById('folder-title').textContent = titleParts.join(' / ');
233+
const titleEl = document.getElementById('folder-title');
234+
if (titleEl) titleEl.textContent = titleParts.join(' / ');
190235

191236
// Setup back button
192237
const backBtn = document.getElementById('back-button');
193-
backBtn.onclick = goBack;
238+
if (backBtn) backBtn.onclick = goBack;
194239

195240
// Render cards
196241
const container = document.getElementById('folder-cards');
242+
if (!container) return;
243+
197244
container.innerHTML = '';
198245

199246
for (const dir of subdirs) {
@@ -216,6 +263,8 @@ async function renderFolder() {
216263

217264
async function renderProblem() {
218265
const view = document.getElementById('problem-view');
266+
if (!view) return;
267+
219268
view.style.display = 'block';
220269
view.innerHTML = '<div style="text-align: center; padding: 3rem;">Loading...</div>';
221270

@@ -255,7 +304,9 @@ async function renderProblem() {
255304

256305
if (pyFiles.length > 0) {
257306
try {
258-
const res = await fetch(`https://api.github.com/repos/${getRepoPath()}/contents/${pathStr}/${pyFiles[0].name}`);
307+
const res = await fetch(`https://api.github.com/repos/${getRepoPath()}/contents/${pathStr}/${pyFiles[0].name}`, {
308+
cache: 'no-cache'
309+
});
259310
if (res.ok) {
260311
const data = await res.json();
261312
pythonCode = atob(data.content);
@@ -352,7 +403,11 @@ async function renderProblem() {
352403
}
353404

354405
view.innerHTML = html;
355-
hljs.highlightAll();
406+
407+
// Highlight code if hljs is available
408+
if (typeof hljs !== 'undefined') {
409+
hljs.highlightAll();
410+
}
356411
}
357412

358413
// Navigation
@@ -367,7 +422,7 @@ async function navigateTo(path) {
367422
return;
368423
}
369424

370-
// Check if this folder has files (is a problem)
425+
// Check if this folder has files (is a "problem")
371426
if (hasFiles(items)) {
372427
window.location.hash = `view/${path.map(encodeURIComponent).join('/')}`;
373428
} else {
@@ -381,22 +436,18 @@ function goBack() {
381436
// If we're viewing a problem, go back to its parent folder
382437
if (state.currentView === 'problem') {
383438
if (state.currentPath.length > 1) {
384-
// Go to parent folder
385439
const parentPath = state.currentPath.slice(0, -1);
386440
window.location.hash = parentPath.map(encodeURIComponent).join('/');
387441
} else {
388-
// Go to home
389442
window.location.hash = '';
390443
}
391444
}
392445
// If we're in a folder view, go back one level
393446
else if (state.currentView === 'folder') {
394447
if (state.currentPath.length > 1) {
395-
// Go to parent folder
396448
const parentPath = state.currentPath.slice(0, -1);
397449
window.location.hash = parentPath.map(encodeURIComponent).join('/');
398450
} else {
399-
// Go to home
400451
window.location.hash = '';
401452
}
402453
}
@@ -429,6 +480,12 @@ function getDefaultEmoji(platformName) {
429480

430481
// Event listeners
431482
window.addEventListener('hashchange', async () => {
483+
// Ignore hash changes during initial load
484+
if (state.isLoading) {
485+
console.log('Ignoring hash change during initial load');
486+
return;
487+
}
488+
432489
console.log('Hash changed');
433490
const parsed = parseHash();
434491
state.currentView = parsed.view;
@@ -449,8 +506,19 @@ window.addEventListener('hashchange', async () => {
449506
return;
450507
}
451508

509+
// Set loading state
510+
state.isLoading = true;
511+
state.currentView = 'loading';
512+
render();
513+
514+
// Load platforms completely before proceeding
452515
await loadPlatforms();
453516

517+
// Mark as initialized
518+
state.isLoading = false;
519+
state.isInitialized = true;
520+
521+
// Now parse hash and render
454522
const parsed = parseHash();
455523
state.currentView = parsed.view;
456524
state.currentPath = parsed.path;

0 commit comments

Comments
 (0)