DistroHopper/docs/all.html
oSoWoSo 00823a53fe Add distro icons and based-on info to cards
- Generate colored placeholder icons with distro initial letter
- Show based-on information from releases data
- Add basedof-badge styling
- Add category badge styling

Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-16 14:25:05 +00:00

526 lines
No EOL
20 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>All Distributions - DistroHopper</title>
<meta name="description" content="All Linux distributions for DistroHopper">
<link rel="stylesheet" href="../style.css">
<style>
/* Distros page styling */
.distros-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
padding: 1rem 0;
}
.distro-card {
border: 1px solid var(--border-color, #444);
border-radius: 8px;
padding: 1rem;
background: var(--bg-secondary, #2d2d2d);
transition: all 0.3s ease;
display: flex;
flex-direction: column;
}
.distro-card:hover {
border-color: var(--green, #8BC53F);
box-shadow: 0 0 10px rgba(139, 197, 63, 0.2);
}
.distro-card h3 {
margin: 0 0 0.5rem 0;
font-size: 1.2rem;
}
.distro-card h3 a {
color: var(--green, #8BC53F);
text-decoration: none;
}
.distro-card h3 a:hover {
text-decoration: underline;
}
.distro-description {
color: var(--text-secondary, #aaa);
font-size: 0.9rem;
margin-bottom: 1rem;
flex-grow: 1;
}
.distro-meta {
font-size: 0.8rem;
color: var(--text-muted, #666);
margin-bottom: 0.75rem;
}
.distro-meta span {
margin-right: 1rem;
}
.download-btn {
display: inline-block;
padding: 0.5rem 1rem;
background: var(--green, #8BC53F);
color: var(--bg-primary, #1a1a1a);
text-decoration: none;
border-radius: 4px;
font-weight: bold;
text-align: center;
cursor: pointer;
border: none;
}
.download-btn:hover {
background: var(--yellow, #FFD700);
}
.category-badge {
display: inline-block;
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: bold;
margin-right: 0.5rem;
}
.category-beginner { background: #4CAF50; color: white; }
.category-advanced { background: #FF9800; color: white; }
.category-lightweight { background: #2196F3; color: white; }
.category-other { background: #9E9E9E; color: white; }
.basedof-badge {
display: inline-block;
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-size: 0.7rem;
background: var(--bg-primary, #333);
color: var(--text-secondary, #aaa);
border: 1px solid var(--border-color, #555);
margin-right: 0.5rem;
}
/* Search and filters */
.distros-filters {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1.5rem;
align-items: center;
}
.distros-search {
flex: 1;
min-width: 200px;
padding: 0.5rem;
border: 1px solid var(--border-color, #444);
border-radius: 4px;
background: var(--bg-secondary, #2d2d2d);
color: var(--text-primary, #fff);
}
.filter-buttons {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.filter-btn {
padding: 0.4rem 0.8rem;
border: 1px solid var(--border-color, #444);
border-radius: 4px;
background: transparent;
color: var(--text-primary, #fff);
cursor: pointer;
}
.filter-btn:hover, .filter-btn.active {
border-color: var(--green, #8BC53F);
color: var(--green, #8BC53F);
}
/* Modal for release/edition selection */
.modal-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal-overlay.active {
display: flex;
}
.modal-content {
background: var(--bg-secondary, #2d2d2d);
border: 1px solid var(--border-color, #444);
border-radius: 8px;
padding: 1.5rem;
max-width: 90vw;
max-height: 80vh;
overflow: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color, #444);
}
.modal-close {
background: none;
border: none;
color: var(--text-primary, #fff);
font-size: 1.5rem;
cursor: pointer;
}
.release-table {
width: 100%;
border-collapse: collapse;
}
.release-table th, .release-table td {
padding: 0.5rem;
border: 1px solid var(--border-color, #444);
text-align: center;
}
.release-table th {
background: var(--bg-primary, #1a1a1a);
}
.release-table td a.download-link {
color: var(--green, #8BC53F);
text-decoration: none;
font-size: 1.2rem;
}
.release-table td a.download-link:hover {
color: var(--yellow, #FFD700);
}
.release-table td.disabled {
color: var(--text-muted, #666);
}
.page-header {
margin-bottom: 1.5rem;
}
.page-header h1 {
margin: 0;
}
.page-header p {
color: var(--text-secondary, #aaa);
margin: 0.5rem 0 0 0;
}
</style>
</head>
<body>
<button class="theme-toggle" onclick="toggleTheme()">🌓</button>
<script>
function toggleTheme(){
const html=document.documentElement;
const current=html.getAttribute("data-theme")||"dark";
const next=current==="dark"?"light":"dark";
html.setAttribute("data-theme",next);
localStorage.setItem("theme",next)
}
(function(){
const saved=localStorage.getItem("theme")||"dark";
document.documentElement.setAttribute("data-theme",saved)
})();
</script>
<nav>
<ul>
<li><a href="https://osowoso.org">oSoWoSo</a></li>
<li>⏮️</a></li>
<li><a href="index.html" class="active">Home</a></li>
<li><a href="CODE_OF_CONDUCT.html">CODE OF CONDUCT</a></li>
<li><a href="CONTRIBUTING.html">CONTRIBUTING</a></li>
<li><a href="README-web.html">README-web</a></li>
<li><a href="SECURITY.html">SECURITY</a></li>
<li><a href="../distros.html">Distros</a></li>
<li><a href="all.html">All</a></li>
<li><a href="stars.html">stars</a></li>
<li>⏭️</a></li>
</ul>
<ul>
<li><a href="https://github.com/oSoWoSo/DistroHopper/releases/latest">⏬ release</a></li>
<li><a href="https://github.com/oSoWoSo/DistroHopper/archive/refs/heads/main.zip">📦repo zip</a></li>
<li><a href="https://github.com/oSoWoSo/DistroHopper">🔗git</a></li>
</ul>
</nav>
<div id="TOC"></div>
<main class="container">
<div class="page-header">
<h1>Supported Distributions</h1>
<p>Linux distributions supported by DistroHopper. Click on a distribution to visit its homepage.</p>
</div>
<div class="distros-filters">
<input type="text" id="distroSearch" class="distros-search" placeholder="Search distributions...">
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="beginner">Beginner</button>
<button class="filter-btn" data-filter="advanced">Advanced</button>
<button class="filter-btn" data-filter="lightweight">Lightweight</button>
</div>
</div>
<div class="distros-grid" id="distroGrid">
<!-- Distros will be rendered here -->
</div>
</main>
<!-- Modal for release/edition selection -->
<div class="modal-overlay" id="modalOverlay">
<div class="modal-content">
<div class="modal-header">
<h2 id="modalTitle">Download Options</h2>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
<div id="modalBody">
<!-- Release/edition table will be rendered here -->
</div>
</div>
</div>
<script src="../distros.js"></script>
<script src="../distros-releases.js"></script>
<script>
// Distros data from distributionhub (211 distros)
const distros = window.distributions || [];
// Current filter state
let currentFilter = 'all';
let searchTerm = '';
// Category labels
const categoryLabels = {
'beginner': 'Beginner',
'advanced': 'Advanced',
'lightweight': 'Lightweight'
};
// Render distro cards
function renderDistros() {
const grid = document.getElementById('distroGrid');
const filtered = distros.filter(distro => {
const matchesFilter = currentFilter === 'all' || distro.category === currentFilter;
const matchesSearch = (!distro.name || distro.name.toLowerCase().includes(searchTerm.toLowerCase())) ||
(distro.description && distro.description.toLowerCase().includes(searchTerm.toLowerCase()));
return matchesFilter && matchesSearch;
});
if (filtered.length === 0) {
grid.innerHTML = '<p style="color: var(--text-secondary);">No distributions found.</p>';
return;
}
grid.innerHTML = filtered.map(distro => {
const category = distro.category || 'other';
const distroId = distro.name || 'Unknown';
// Generate a colored placeholder for icon
const colors = ['#E95420', '#3C3B37', '#A80030', '#41B549', '#87CF3E', '#2F2F2F', '#178CDA', '#000000'];
const colorIndex = distro.name.charCodeAt(0) % colors.length;
const bgColor = colors[colorIndex];
const initial = distro.name ? distro.name.charAt(0).toUpperCase() : '?';
const iconHtml = `<div style="width: 32px; height: 32px; background: ${bgColor}; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 14px; margin-right: 0.5rem;">${initial}</div>`;
// Get based-on info from releases data
const releaseInfo = Object.values(window.distrosReleases || {}).find(d => d.name?.toLowerCase() === distro.name?.toLowerCase());
const basedof = releaseInfo?.basedof || '';
const basedofHtml = basedof ? `<span class="basedof-badge">${basedof}</span>` : '';
return `
<div class="distro-card" data-category="${category}">
<div class="distro-header">
<a href="${distro.websiteLink || '#'}" target="_blank" rel="noopener" style="display: flex; align-items: center; text-decoration: none; color: inherit;">
${iconHtml}<h3>${distro.name || 'Unknown'}</h3>
</a>
</div>
<p class="distro-description">${distro.description || ''}</p>
<div class="distro-meta">
<span class="category-badge category-${category}">${categoryLabels[category] || category}</span>
${basedofHtml}
${distro.version ? `<span>${distro.version}</span>` : ''}
</div>
<button class="download-btn" onclick="showDownloads('${distroId.replace(/'/g, "\\'")}')">Download</button>
</div>
`;
}).join('');
}
// Show download modal with release × edition table
function showDownloads(distroId) {
const distro = distros.find(d => d.name?.toLowerCase() === distroId.toLowerCase() || d.id?.toLowerCase() === distroId.toLowerCase());
const releasesData = window.distrosReleases || {};
// Find matching release data (case-insensitive)
const releaseInfo = Object.values(releasesData).find(d => d.name?.toLowerCase() === distroId.toLowerCase());
if (!distro) {
window.open('https://github.com/oSoWoSo/DistroHopper', '_blank');
return;
}
const modal = document.getElementById('modalOverlay');
const modalTitle = document.getElementById('modalTitle');
const modalBody = document.getElementById('modalBody');
// Generate a colored placeholder for icon
const colors = ['#E95420', '#3C3B37', '#A80030', '#41B549', '#87CF3E', '#2F2F2F', '#178CDA', '#000000'];
const colorIndex = distro.name.charCodeAt(0) % colors.length;
const bgColor = colors[colorIndex];
const initial = distro.name ? distro.name.charAt(0).toUpperCase() : '?';
const iconHtml = `<div style="width: 48px; height: 48px; background: ${bgColor}; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 20px; margin-right: 1rem; vertical-align: middle;">${initial}</div>`;
modalTitle.innerHTML = `${iconHtml}${distro.name}`;
// Get based-on info from release data
const releaseInfo = Object.values(window.distrosReleases || {}).find(d => d.name?.toLowerCase() === distroId.toLowerCase());
const basedof = releaseInfo?.basedof || '';
// Add based-on info if available
let basedofHtml = '';
if (basedof) {
basedofHtml = `<p style="color: var(--text-muted); margin: 0.5rem 0;">
<strong>Based on:</strong> ${basedof}
</p>`;
}
const downloadLink = distro.downloadLink;
const releases = releaseInfo?.releases || [];
const editions = releaseInfo?.editions || [];
let html = '';
// Based-on info
html += basedofHtml;
// If we have releases and editions, show table
if (releases.length > 0 && editions.length > 0) {
html += `<h3 style="margin-top: 0;">Select Version & Edition</h3>`;
html += `<table class="release-table">`;
// Header row with editions
html += `<tr><th>Version</th>`;
editions.forEach(edition => {
html += `<th>${edition}</th>`;
});
html += `</tr>`;
// Data rows for each release
releases.forEach((release, idx) => {
html += `<tr><td><strong>${release}</strong></td>`;
editions.forEach((edition, edIdx) => {
// For now, show link to homepage as placeholder (actual URLs require get_() function)
html += `<td><a href="${distro.websiteLink || '#'}" target="_blank" class="download-link">⬇</a></td>`;
});
html += `</tr>`;
});
html += `</table>`;
html += `<p style="font-size: 0.85rem; color: var(--text-muted); margin-top: 0.5rem;">Click ⬇ to download. For direct ISO links, use DistroHopper.</p>`;
} else if (releases.length > 0) {
// Just releases, no editions
html += `<h3 style="margin-top: 0;">Available Versions</h3>`;
html += `<table class="release-table">`;
html += `<tr><th>Version</th><th>Download</th></tr>`;
releases.slice(0, 10).forEach(release => {
html += `<tr><td><strong>${release}</strong></td><td><a href="${distro.websiteLink || '#'}" target="_blank" class="download-link">⬇</a></td></tr>`;
});
html += `</table>`;
}
// Always show direct download buttons
if (downloadLink) {
html += `<div style="text-align: center; margin: 1rem 0;">
<a href="${downloadLink}" target="_blank" rel="noopener" class="download-btn" style="font-size: 1.2rem; padding: 1rem 2rem;">
⬇ Download Latest Version
</a>
</div>`;
}
if (distro.torrent) {
html += `<div style="text-align: center; margin-bottom: 1rem;">
<a href="${distro.torrent}" target="_blank" rel="noopener" class="download-btn" style="background: #9b59b6; font-size: 1.2rem; padding: 1rem 2rem;">
🧲 Download Torrent
</a>
</div>`;
}
html += `<div style="text-align: center; margin-top: 1rem; padding: 1rem; background: var(--bg-secondary); border-radius: 8px;">
<p style="margin-bottom: 0.5rem;">For other versions and editions, use DistroHopper:</p>
<code style="background: var(--bg-primary); padding: 0.25rem 0.5rem; border-radius: 4px;">./distrohopper</code>
</div>`;
if (distro.websiteLink) {
html += `<div style="text-align: center; margin-top: 1rem;">
<a href="${distro.websiteLink}" target="_blank" rel="noopener" style="color: var(--link-color);">
Visit official website →
</a>
</div>`;
}
modalBody.innerHTML = html;
modal.classList.add('active');
}
// Close modal
function closeModal() {
document.getElementById('modalOverlay').classList.remove('active');
}
// Close modal on overlay click
document.getElementById('modalOverlay').addEventListener('click', function(e) {
if (e.target === this) closeModal();
});
// Search functionality
document.getElementById('distroSearch').addEventListener('input', function(e) {
searchTerm = e.target.value;
renderDistros();
});
// Filter buttons
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', function() {
const filter = this.getAttribute('data-filter');
currentFilter = filter;
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
renderDistros();
});
});
// Initial render
renderDistros();
</script>
</body>
</html>