diff --git a/index.html b/index.html index c28ce1f..8a6b077 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,9 @@

World Tech Tree (MVP)

+
diff --git a/sorted.html b/sorted.html new file mode 100644 index 0000000..6d29f84 --- /dev/null +++ b/sorted.html @@ -0,0 +1,34 @@ + + + + + + Sorted Technologies + + + + +
+

Sorted Technologies

+ +
+
+
+ + + + + + + + + + +
EraLevelNamePrerequisites
+
+
+ + + diff --git a/sorted.js b/sorted.js new file mode 100644 index 0000000..c9a116d --- /dev/null +++ b/sorted.js @@ -0,0 +1,94 @@ +// Render a table of technologies sorted by era and dependency level + +document.addEventListener('DOMContentLoaded', async () => { + let data = []; + try { + const resp = await fetch('/api/tech-tree'); + if (resp.ok) { + data = await resp.json(); + } else { + throw new Error('Failed to load tech tree'); + } + } catch (err) { + console.error('Error loading tech tree:', err); + return; + } + + // Build adjacency map and compute dependency levels + const dependentsMap = {}; + const levelMap = {}; + + data.forEach(t => { + (t.prerequisites || []).forEach(pr => { + if (!dependentsMap[pr]) dependentsMap[pr] = []; + dependentsMap[pr].push(t.id); + }); + }); + + const queue = []; + data.forEach(t => { + if (!t.prerequisites || t.prerequisites.length === 0) { + levelMap[t.id] = 0; + queue.push(t.id); + } + }); + + while (queue.length) { + const current = queue.shift(); + const currentLevel = levelMap[current]; + (dependentsMap[current] || []).forEach(dep => { + const nextLevel = currentLevel + 1; + if (levelMap[dep] === undefined || nextLevel < levelMap[dep]) { + levelMap[dep] = nextLevel; + queue.push(dep); + } + }); + } + + data.forEach(t => { + if (levelMap[t.id] === undefined) levelMap[t.id] = 0; + t.level = levelMap[t.id]; + }); + + const eraOrder = { + Ancient: 0, + Classical: 1, + Medieval: 2, + Renaissance: 3, + Industrial: 4, + Modern: 5, + Future: 6 + }; + + // Sort technologies by era then dependency level + data.sort((a, b) => { + const eraCmp = (eraOrder[a.era] ?? 99) - (eraOrder[b.era] ?? 99); + if (eraCmp !== 0) return eraCmp; + const lvlCmp = a.level - b.level; + if (lvlCmp !== 0) return lvlCmp; + return a.name.localeCompare(b.name); + }); + + const tbody = document.querySelector('#sorted-table tbody'); + data.forEach(t => { + const tr = document.createElement('tr'); + const eraTd = document.createElement('td'); + eraTd.textContent = t.era || ''; + tr.appendChild(eraTd); + + const lvlTd = document.createElement('td'); + lvlTd.textContent = t.level; + tr.appendChild(lvlTd); + + const nameTd = document.createElement('td'); + nameTd.textContent = t.name; + tr.appendChild(nameTd); + + const prereqTd = document.createElement('td'); + prereqTd.textContent = (t.prerequisites || []).join(', '); + tr.appendChild(prereqTd); + + tbody.appendChild(tr); + }); +}); + diff --git a/style.css b/style.css index cb6c3b4..27198a0 100644 --- a/style.css +++ b/style.css @@ -17,6 +17,20 @@ header { box-shadow: 0 2px 4px rgba(0,0,0,0.1); } +header nav { + margin-top: 10px; +} + +header nav a { + color: #fff; + margin: 0 10px; + text-decoration: none; +} + +header nav a:hover { + text-decoration: underline; +} + main { display: flex; flex-grow: 1; @@ -44,6 +58,34 @@ main { height: 80vh; /* Ensure the canvas has some initial height */ } +#sorted-tech-container { + flex: 1; + border: 1px solid #ddd; + border-radius: 8px; + background-color: #fff; + box-shadow: 0 2px 6px rgba(0,0,0,0.05); + overflow: auto; + position: relative; +} + +#sorted-table { + width: 100%; + border-collapse: collapse; +} + +#sorted-table th, +#sorted-table td { + border: 1px solid #ddd; + padding: 8px; + text-align: left; +} + +#sorted-table th { + background-color: #f9f9f9; + position: sticky; + top: 0; +} + #tech-info-panel { border: 1px solid #ddd; border-radius: 8px;