DistroHopper/docs/README-web.html
2026-02-21 11:52:53 +01:00

616 lines
24 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>README-web</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="style.css" />
</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>
<script>
document.addEventListener("DOMContentLoaded", function () {
const toc = document.getElementById("TOC");
if (!toc) return;
// Add toc-title with toggle button
const titleEl = document.createElement("div");
titleEl.id = "toc-title";
titleEl.innerHTML = '<span>Contents</span><span id="toc-toggle-icon">◀</span>';
toc.insertBefore(titleEl, toc.firstChild);
// Wrap TOC + the rest of the content in .page-wrapper
const body = document.body;
const wrapper = document.createElement("div");
wrapper.className = "page-wrapper";
// Find all elements after <nav> (main nav menu)
const topNav = document.querySelector("body > nav");
const siblings = [];
let el = topNav ? topNav.nextElementSibling : body.firstElementChild;
while (el) {
siblings.push(el);
el = el.nextElementSibling;
}
siblings.forEach((s) => wrapper.appendChild(s));
body.appendChild(wrapper);
// Wrap main content (everything except TOC) in .main-content
const mainContent = document.createElement("div");
mainContent.className = "main-content";
Array.from(wrapper.children).forEach((child) => {
if (child.id !== "TOC") mainContent.appendChild(child);
});
wrapper.appendChild(mainContent);
// Collapsible toggle
const icon = document.getElementById("toc-toggle-icon");
const saved = localStorage.getItem("toc-collapsed");
if (saved === "true") {
toc.classList.add("collapsed");
icon.textContent = "▶";
}
titleEl.addEventListener("click", function () {
toc.classList.toggle("collapsed");
const isCollapsed = toc.classList.contains("collapsed");
icon.textContent = isCollapsed ? "▶" : "◀";
localStorage.setItem("toc-collapsed", isCollapsed);
});
});
</script>
<nav><ul>
<li><a href="https://osowoso.org">oSoWoSo</a></li>
<li>⏮️</a></li>
<li><a href="index.html">Home</a></li>
<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>
<li>⏭️</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" class="active">README-web</a></li>
<li><a href="SECURITY.html">SECURITY</a></li>
<li><a href="stars.html">stars</a></li>
</ul></nav>
<header id="title-block-header">
<h1 class="title">README-web</h1>
</header>
<nav id="TOC" role="doc-toc">
<ul>
<li><a href="#looking-to-try-out-a-new-operating-system"
id="toc-looking-to-try-out-a-new-operating-system">Looking to try out a
new operating system?</a></li>
<li><a href="#distrohopper"
id="toc-distrohopper"><strong>DistroHopper</strong></a></li>
<li><a href="#still-beta-version" id="toc-still-beta-version">Still Beta
version!</a></li>
<li><a href="#features" id="toc-features">Features</a>
<ul>
<li><a href="#welcome-translations"
id="toc-welcome-translations">Welcome translations!</a></li>
</ul></li>
<li><a href="#why-am-i-doing-it" id="toc-why-am-i-doing-it">Why am I
doing it?</a>
<ul>
<li><a href="#how-to-run-distrohopper"
id="toc-how-to-run-distrohopper">How to run DistroHopper?</a></li>
<li><a href="#requirements-for-running-vms"
id="toc-requirements-for-running-vms">Requirements (For running VMs)</a>
<ul>
<li><a href="#installing-requirements"
id="toc-installing-requirements">Installing Requirements</a></li>
<li><a href="#for-distrohopper-to-work-you-need"
id="toc-for-distrohopper-to-work-you-need">For DistroHopper to work you
need</a></li>
</ul></li>
</ul></li>
<li><a href="#how-to-install-distrohopper"
id="toc-how-to-install-distrohopper">How to install
DistroHopper?</a></li>
<li><a href="#how-to-run-distrohopper-1"
id="toc-how-to-run-distrohopper-1">How to run DistroHopper</a>
<ul>
<li><a href="#desktop-files" id="toc-desktop-files">Desktop files</a>
<ul>
<li><a href="#currently-supported-operating-systems-and-tools"
id="toc-currently-supported-operating-systems-and-tools">Currently
supported Operating Systems and tools:</a></li>
</ul></li>
</ul></li>
<li><a href="#join-distrohopper-chat-group"
id="toc-join-distrohopper-chat-group">Join DistroHopper chat
group:</a></li>
<li><a href="#without-these-amazing-projects-it-wouldnt-be-posible"
id="toc-without-these-amazing-projects-it-wouldnt-be-posible">Without
these amazing projects it wouldn't be posible:</a></li>
<li><a href="#mirrored-on" id="toc-mirrored-on">Mirrored on</a></li>
<li><a href="#donate" id="toc-donate">donate</a></li>
</ul>
</nav>
<p><img
src="https://img.shields.io/github/stars/oSoWoSo/DistroHopper?style=for-the-badge&amp;color=8BC53F&amp;logo=instatus&amp;logoColor=000000" />
<img
src="https://img.shields.io/github/forks/oSoWoSo/DistroHopper?style=for-the-badge&amp;color=8BC53F&amp;logo=git&amp;logoColor=000000" />
<img
src="https://img.shields.io/github/license/oSoWoSo/DistroHopper?style=for-the-badge&amp;color=8BC53F&amp;logo=apache&amp;logoColor=000000" />
<img
src="https://img.shields.io/github/repo-size/oSoWoSo/DistroHopper?style=for-the-badge&amp;color=8BC53F&amp;logo=files&amp;logoColor=000000" /></p>
<p><img
src="https://img.shields.io/github/last-commit/oSoWoSo/DistroHopper?style=for-the-badge&amp;color=8BC53F&amp;logo=codeigniter&amp;logoColor=000000" />
<img
src="https://img.shields.io/badge/language-shell-green?style=for-the-badge&amp;color=8BC53F&amp;logo=sharp&amp;logoColor=000000" />
<img
src="https://img.shields.io/badge/gitmoji-%20😜%20😍-FFDD67.svg?style=for-the-badge&amp;color=8BC53F&amp;logo=sharp&amp;logoColor=000000&amp;alt=&quot;Gitmoji&quot;" /></p>
<hr />
<h1 id="looking-to-try-out-a-new-operating-system">Looking to try out a
new operating system?</h1>
<p>try</p>
<h1 id="distrohopper"><strong>DistroHopper</strong></h1>
<p>Quickly download, create and run VM of any#TODO operating system.</p>
<p>Linux<img src="tux23.png" alt="Tux" /> required...</p>
<hr />
<p>Click on Hop for latest download</p>
<p><a
href="https://sourceforge.net/projects/distrohopper/files/latest/download"><img
src="hop120.png" alt="Hop" /></a></p>
<p><a href="https://liberapay.com/zenobit/donate"><img
src="https://liberapay.com/assets/widgets/donate.svg"
alt="Donate" /></a></p>
<p>Licensed under AGPL3</p>
<h1 id="still-beta-version">Still Beta version!</h1>
<details>
<summary>Click for screenshot</summary>
![supported Operating systems](distrohopper.png)
</details>
<p>As a base excellent <a
href="https://github.com/quickemu-project/quickemu">quickemu</a> (Link
to project page)</p>
<details>
<summary>Click for Quickemu old video</summary>
<iframe width="960" height="540" src="https://www.youtube-nocookie.com/embed/AOTYWEgw0hI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</details>
<p>You can download new distro with <strong>few clicks</strong> of a
mouse</p>
<h1 id="features">Features</h1>
<ul>
<li>GUI using yad</li>
</ul>
<details>
<summary>Click for old video</summary>
<iframe width="960" height="540" src="https://www.youtube-nocookie.com/embed/RrFQECcwLRA" title="DistroHopper" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</details>
- TUI using fzf
<details>
<summary>Click for old video</summary>
<iframe width="960" height="540" src="https://www.youtube-nocookie.com/embed/gJ5hqYEskOw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</details>
- Desktop(shortcuts) entries generator
<ul>
<li><p>Set dir where VMs will be stored</p></li>
<li><p>Install DistroHopper systemwide</p></li>
<li><p>Portable mode (dependecies still must be installed)</p></li>
<li><p>Add new operating system to quickget (bit easier)</p></li>
<li><p>Copy all downloaded ISOs to destination directory</p></li>
<li><p>Translate DistroHopper (Currently supported English and Czech
language)</p></li>
</ul>
<p>Developed in English and translated into Czech language.</p>
<h2 id="welcome-translations">Welcome translations!</h2>
<hr />
<h1 id="why-am-i-doing-it">Why am I doing it?</h1>
<p>Because I wanna learn</p>
<ul>
<li><p>Linux</p></li>
<li><p>Bash</p></li>
<li><p>yad</p></li>
<li><p>project management</p></li>
</ul>
<p>And contribute to open source</p>
<p>play with Quickemu</p>
<p>And easily add new distros to it</p>
<hr />
<h2 id="how-to-run-distrohopper">How to run DistroHopper?</h2>
<p>You need fullfill the requirement first...</p>
<h2 id="requirements-for-running-vms">Requirements (For running
VMs)</h2>
<ul>
<li><a href="https://www.qemu.org/">QEMU</a> (<em>6.0.0 or newer</em>)
<strong>with GTK, SDL, SPICE &amp; VirtFS support</strong></li>
<li><a href="https://www.gnu.org/software/bash/">bash</a> (<em>4.0 or
newer</em>)</li>
<li><a href="https://www.gnu.org/software/coreutils/">Coreutils</a></li>
<li><a href="https://github.com/tianocore/edk2">EDK II</a></li>
<li><a href="https://www.gnu.org/software/grep/">grep</a></li>
<li><a href="https://stedolan.github.io/jq/">jq</a></li>
<li><a href="https://wiki.linuxfoundation.org/lsb/start">LSB</a></li>
<li><a href="https://gitlab.com/procps-ng/procps">procps</a></li>
<li><a href="https://www.python.org/">python3</a></li>
<li><a
href="https://github.com/acidanthera/OpenCorePkg/tree/master/Utilities/macrecovery">macrecovery</a></li>
<li><a
href="http://cdrtools.sourceforge.net/private/cdrecord.html">mkisofs</a></li>
<li><a href="https://github.com/gregkh/usbutils">usbutils</a></li>
<li><a href="https://github.com/karelzak/util-linux">util-linux</a></li>
<li><a href="https://www.gnu.org/software/sed/">sed</a></li>
<li><a href="http://www.dest-unreach.org/socat/">socat</a></li>
<li><a
href="https://gitlab.freedesktop.org/spice/spice-gtk">spicy</a></li>
<li><a href="https://github.com/stefanberger/swtpm">swtpm</a></li>
<li><a href="https://www.gnu.org/software/wget/">Wget</a></li>
<li><a
href="https://www.freedesktop.org/wiki/Software/xdg-user-dirs/">xdg-user-dirs</a></li>
<li><a
href="https://gitlab.freedesktop.org/xorg/app/xrandr">xrandr</a></li>
<li><a href="http://zsync.moria.org.uk/">zsync</a></li>
<li><a href="http://www.info-zip.org/UnZip.html">unzip</a></li>
</ul>
<h3 id="installing-requirements">Installing Requirements</h3>
<p>For Ubuntu, Arch and nixos systems the <a
href="https://launchpad.net/~flexiondotorg/+archive/ubuntu/quickemu">ppa</a>,
<a href="https://aur.archlinux.org/packages/quickemu">AUR</a> or <a
href="https://github.com/NixOS/nixpkgs/tree/master/pkgs/development/quickemu">nix</a>
packaging will take care of the dependencies. For other host
distributions or operating systems it will be necessary to install the
above requirements or their equivalents.</p>
<pre><code>If you install DistroHopper, it should take care of dependencies on Arch, Debian, Ubuntu, openSuse and Fedora</code></pre>
<h3 id="for-distrohopper-to-work-you-need">For DistroHopper to work you
need</h3>
<p><code>wget yad fzf</code></p>
<p>quickemu is included</p>
<p>For adding new distros, or adding/improving translations you will
need also meld.</p>
<h1 id="how-to-install-distrohopper">How to install DistroHopper?</h1>
<p>You need get copy of distrohopper</p>
<p>If you want more stable experience, download latest release from</p>
<h4 id="github-or-sourceforge-sourceforge"><a
href="https://github.com/oSoWoSo/DistroHopper/releases">GitHub</a> or
SourceForge <a
href="https://sourceforge.net/projects/distrohopper/files/latest/download"><img
src="https://img.shields.io/sourceforge/dt/distrohopper.svg"
alt="SourceForge" /></a></h4>
<hr />
<p>If you want latest developer version... (could have bugs and break
anytime)</p>
<p>Or you want translate DistroHopper</p>
<p><code>git clone https://github.com/oSoWoSo/DistroHopper</code></p>
<p>Enter created/unpacked distrohopper directory</p>
<p>Now you should be good to go...</p>
<hr />
<h1 id="how-to-run-distrohopper-1">How to run DistroHopper</h1>
<p>Just run from terminal</p>
<p><code>./dh</code></p>
<p>And you will see what next...</p>
<p>I am usually run DistroHopper as:</p>
<p><code>./dh m r s l &amp;&amp; ./dh i &amp;&amp; dh g</code></p>
<p>(But...)</p>
<h2 id="desktop-files">Desktop files</h2>
<p>All desktop files will be storred in your .config/distrohopper in
directories <em>ready</em> and <em>supported</em></p>
<p>Fell free to copy them anywhere you want...</p>
<h3 id="currently-supported-operating-systems-and-tools">Currently
supported Operating Systems and tools:</h3>
<ul>
<li>agarimos - alma - alpine - android - archlinux - archcraft -
arcolinux</li>
<li>batocera - blendos - cachyos - centos-stream - cereus - debian -
deepin</li>
<li>devuan - dietpi - dragonflybsd - elementary - endeavouros -
endless</li>
<li>fedora - freebsd - freedos - fvoid - gabeeos - garuda - gentoo</li>
<li>ghostbsd - haiku - kali - kdeneon - kolibrios - kubuntu -
linuxmint</li>
<li>lmde - mageia - manjaro - miyo - mxlinux - netboot - netbsd -
nixos</li>
<li>lubuntu - macos - openbsd - opensuse - oraclelinux - popos -
reactos</li>
<li>rebornos - rockylinux - siduction - slackware - slitaz - solus</li>
<li>steamos - tails - truenas-core - truenas-scale - ubuntu -
ubuntu-budgie</li>
<li>ubuntukylin - ubuntu-mate - ubuntustudio - ubuntu-unity - ventoy -
void</li>
<li>voidpup - vxlinux - windows - xerolinux - xubuntu - zorin</li>
</ul>
<p>Also with posible planned: <a
href="https://github.com/oSoWoSo/DistroHopper/discussions/9">in
discusion</a></p>
<hr />
<h4 id="discuss-on-github"><a
href="https://github.com/oSoWoSo/DistroHopper/discussions">discuss</a>
on github</h4>
<h1 id="join-distrohopper-chat-group">Join DistroHopper chat group:</h1>
<p><a
href="https://simplex.chat/contact#/?v=1-2&amp;smp=smp%3A%2F%2FSkIkI6EPd2D63F4xFKfHk7I1UGZVNn6k1QWZ5rcyr6w%3D%40smp9.simplex.im%2FzmtsZwfTjwyynibt0bF6bb_xLWS9ce5A%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAkMtz66wGfWb6VDn-_t_mVm3RFiFfOC3Hxye8Hm5tmVo%253D%26srv%3Djssqzccmrcws6bhmn77vgmhfjmhwlyr3u7puw4erkyoosywgl67slqqd.onion&amp;data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22o8KR0TOM0f2j33nO9goMRQ%3D%3D%22%7D"><img
src="simplex.svg" alt="SimpleX" /></a> (click SimpleX logo)</p>
<p>(check the software! even if you don't want chat about DistroHopper)
<a href="https://simplex.chat">Simplex website</a></p>
<h1 id="without-these-amazing-projects-it-wouldnt-be-posible">Without
these amazing projects it wouldn't be posible:</h1>
<h4 id="bash"><a href="https://www.gnu.org/software/bash/">bash</a></h4>
<h4 id="qemu"><a href="https://www.qemu.org/">QEMU</a></h4>
<h4 id="quickemu"><a
href="https://github.com/quickemu-project/quickemu">quickemu</a></h4>
<p>GUI depends on</p>
<h4 id="yad"><a href="https://github.com/v1cont/yad">yad</a></h4>
<p>TUI depends on</p>
<h4 id="fzf"><a href="https://github.com/junegunn/fzf">fzf</a></h4>
<hr />
<p>For</p>
<ul>
<li>easy of use</li>
</ul>
<h4 id="fish"><a href="https://fishshell.com">fish</a></h4>
<ul>
<li>commiting and working with github</li>
</ul>
<h4 id="lazygit"><a
href="https://github.com/jesseduffield/lazygit">lazygit</a></h4>
<h4 id="opencommit"><a
href="https://github.com/di-sukharev/opencommit">opencommit</a></h4>
<ul>
<li>Editing</li>
</ul>
<h4 id="geany"><a href="https://geany.org/">geany</a></h4>
<h4 id="kate"><a href="https://apps.kde.org/kate">Kate</a></h4>
<ul>
<li>diff</li>
</ul>
<h4 id="meld"><a href="https://meld.app/">Meld</a></h4>
<ul>
<li>Logo and icons</li>
</ul>
<h4 id="gimp"><a href="https://www.gimp.org">GIMP</a></h4>
<p>and</p>
<h4 id="inkscape"><a href="https://inkscape.org">Inkscape</a></h4>
<h4 id="logo-by-bit-repaired-by-me"><a
href="https://freesvg.org/by/OpenClipart">logo by</a> bit repaired by
me..</h4>
<ul>
<li>Updating translation</li>
</ul>
<h4 id="poedit"><a href="https://poeditor.com/">Poedit</a></h4>
<p>Everything done on</p>
<h4 id="void-linux"><a href="https://voidlinux.org">Void Linux</a></h4>
<hr />
<h1 id="mirrored-on">Mirrored on</h1>
<h4 id="github"><a
href="https://github.com/oSoWoSo/DistroHopper">GitHub</a></h4>
<h4 id="sourceforge"><a
href="https://sourceforge.net/projects/distrohopper">SourceForge</a></h4>
<h4 id="disroot"><a
href="https://git.disroot.org/oSoWoSo/DistroHopper">Disroot</a></h4>
<h4 id="codeberg"><a
href="https://codeberg.org/oSoWoSo/DistroHopper">Codeberg</a></h4>
<h4 id="gitlab"><a
href="https://gitlab.com/osowoso/distrohopper">GitLab</a></h4>
<h4 id="sourcehut"><a
href="https://git.sr.ht/~osowoso/DistroHopper">SourceHut</a></h4>
<hr />
<p>For Homepage click on Hop</p>
<p><a href="https://dh.osowoso.xyz/"><img src="hop120.png"
alt="Hop" /></a></p>
<h1 id="donate">donate</h1>
<p><a href="https://liberapay.com/zenobit/donate"><img
src="https://liberapay.com/assets/widgets/donate.svg"
alt="Donate" /></a></p>
<p>@zen0bit at github</p>
<p>mailto: <a
href="mailto:zenobit@osowoso.xyz">zenobit@osowoso.xyz</a></p>
<p><a href="./">up</a></p>
<h4 id="parent-site-osowoso">parent site <a
href="https://osowoso.xyz">oSoWoSo</a></h4>
<script>
(function () {
function hexToRgb(hex) {
hex = hex.trim().replace(/^#/, '');
if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
const n = parseInt(hex, 16);
return [n >> 16 & 255, n >> 8 & 255, n & 255];
}
function clamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
function Color(r, g, b) {
this.r = r / 255;
this.g = g / 255;
this.b = b / 255;
}
Color.prototype.applyFilter = function (funcs) {
let [r, g, b] = [this.r * 255, this.g * 255, this.b * 255];
function multiply(matrix) {
const nr = clamp(r * matrix[0] + g * matrix[1] + b * matrix[2], 0, 255);
const ng = clamp(r * matrix[3] + g * matrix[4] + b * matrix[5], 0, 255);
const nb = clamp(r * matrix[6] + g * matrix[7] + b * matrix[8], 0, 255);
r = nr; g = ng; b = nb;
}
function hueRotate(angle) {
const a = angle / 180 * Math.PI;
const sin = Math.sin(a), cos = Math.cos(a);
multiply([
0.213 + cos*0.787 - sin*0.213, 0.715 - cos*0.715 - sin*0.715, 0.072 - cos*0.072 + sin*0.928,
0.213 - cos*0.213 + sin*0.143, 0.715 + cos*0.285 + sin*0.140, 0.072 - cos*0.072 - sin*0.283,
0.213 - cos*0.213 - sin*0.787, 0.715 - cos*0.715 + sin*0.715, 0.072 + cos*0.928 + sin*0.072,
]);
}
function sepia(v) {
multiply([
0.393 + 0.607*(1-v), 0.769 - 0.769*(1-v), 0.189 - 0.189*(1-v),
0.349 - 0.349*(1-v), 0.686 + 0.314*(1-v), 0.168 - 0.168*(1-v),
0.272 - 0.272*(1-v), 0.534 - 0.534*(1-v), 0.131 + 0.869*(1-v),
]);
}
function saturate(v) {
multiply([
0.213 + 0.787*v, 0.715 - 0.715*v, 0.072 - 0.072*v,
0.213 - 0.213*v, 0.715 + 0.285*v, 0.072 - 0.072*v,
0.213 - 0.213*v, 0.715 - 0.715*v, 0.072 + 0.928*v,
]);
}
for (const [fn, val] of funcs) {
if (fn === 'invert') { r = clamp((1-r/255)*255*val + r/255*255*(1-val),0,255); g = clamp((1-g/255)*255*val + g/255*255*(1-val),0,255); b = clamp((1-b/255)*255*val + b/255*255*(1-val),0,255); }
if (fn === 'sepia') sepia(val);
if (fn === 'saturate') saturate(val);
if (fn === 'hueRotate') hueRotate(val);
if (fn === 'brightness'){ r = clamp(r*val,0,255); g = clamp(g*val,0,255); b = clamp(b*val,0,255); }
}
return new Color(r, g, b);
};
function loss(result, target) {
return (
Math.pow(result.r*255 - target.r*255, 2) +
Math.pow(result.g*255 - target.g*255, 2) +
Math.pow(result.b*255 - target.b*255, 2)
);
}
function solve(target) {
function css(v) {
return [
['invert', clamp(v[0], 0, 1)],
['sepia', clamp(v[1], 0, 1)],
['saturate', clamp(v[2], 0, 20)],
['hueRotate', clamp(v[3], 0, 360)],
['brightness',clamp(v[4], 0, 10)],
['brightness',clamp(v[5], 0, 10)],
];
}
function score(v) {
return loss(new Color(0,0,0).applyFilter(css(v)), target);
}
let best = null, bestScore = Infinity;
for (let i = 0; i < 30; i++) {
let v = [Math.random(), Math.random(), Math.random()*10, Math.random()*360, Math.random()*2, Math.random()*2];
for (let step = 1; step > 0.0001; step *= 0.9) {
for (let j = 0; j < v.length; j++) {
const orig = v[j];
v[j] += step * (Math.random() > 0.5 ? 1 : -1);
const s = score(v);
if (s < bestScore) { bestScore = s; best = [...v]; }
else v[j] = orig;
}
}
}
const f = css(best);
return [
`invert(${(clamp(f[0][1],0,1)*100).toFixed(0)}%)`,
`sepia(${(clamp(f[1][1],0,1)*100).toFixed(0)}%)`,
`saturate(${(clamp(f[2][1],0,20)*100).toFixed(0)}%)`,
`hue-rotate(${clamp(f[3][1],0,360).toFixed(0)}deg)`,
`brightness(${(clamp(f[4][1],0,10)*100).toFixed(0)}%)`,
`brightness(${(clamp(f[5][1],0,10)*100).toFixed(0)}%)`,
].join(' ');
}
// Cache solved filters per color so theme switching is instant
const cache = {};
function applyIconColor() {
const raw = getComputedStyle(document.documentElement)
.getPropertyValue('--color-icon').trim();
if (!raw) return false;
let rgb;
if (raw.startsWith('#')) {
rgb = hexToRgb(raw);
} else if (raw.startsWith('rgb')) {
rgb = raw.match(/\d+/g).map(Number).slice(0, 3);
} else {
return false;
}
const key = rgb.join(',');
if (!cache[key]) {
cache[key] = solve(new Color(...rgb));
}
document.documentElement.style.setProperty('--filter-icon', cache[key]);
return true;
}
function init() {
if (!applyIconColor()) return;
// Watch for data-theme attribute changes on <html> — re-apply immediately
new MutationObserver(function(mutations) {
for (const m of mutations) {
if (m.attributeName === 'data-theme') {
applyIconColor();
break;
}
}
}).observe(document.documentElement, { attributes: true });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>
<script data-goatcounter="https://osowoso.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>
<script src="https://giscus.app/client.js"
data-repo="osowoso/Distrohopper"
data-repo-id="R_kgDOJHu9MQ"
data-category="General"
data-category-id="DIC_kwDOJHu9Mc4CVBGm"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="preferred_color_scheme"
data-lang="cs"
crossorigin="anonymous"
async></script>
</body>
</html>