mirror of
https://github.com/oSoWoSo/DistroHopper.git
synced 2026-06-14 17:36:40 +00:00
- 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>
526 lines
No EOL
20 KiB
HTML
526 lines
No EOL
20 KiB
HTML
<!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()">×</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> |