Add distributionhub-style distros page with 211 distributions#51
Add distributionhub-style distros page with 211 distributions#51zen0bit wants to merge 2 commits into
Conversation
📝 WalkthroughWalkthroughThis pull request introduces a new distributions gallery feature with searchable and filterable Linux distribution listings, updates contact information and domain references from Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (1)
docs/distros.md (1)
29-52: Move inline style overrides intodocs/distros.cssto avoid drift.This block duplicates styling already defined in the new stylesheet and can diverge over time. Keep page styles in one place.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/distros.md` around lines 29 - 52, The inline <style> block in docs/distros.md (selectors: body, .search-container .form-control, .search-container .form-control::placeholder, .filter-btn, .filter-btn:hover/.active) duplicates rules already in the new stylesheet; remove this inline style from the MD file and relocate those rules into docs/distros.css (or merge with the existing definitions there), ensuring the selectors and declarations are preserved and any specificity/order is adjusted so visual behavior (dark background, search input, placeholder color, filter button states) remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/distros.css`:
- Line 3: Replace the current `@import`
url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
with the plain `@import`
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap";
and update any font-family declarations that use quoted family names (e.g.,
font-family: 'Roboto', sans-serif;) to unquoted identifiers (e.g., font-family:
Roboto, sans-serif;), so the `@import` notation and the "Roboto" font-family
quotes satisfy the stylelint rules.
In `@docs/distros.js`:
- Line 134: The category values must be normalized to lowercase so UI filters
match; update the distro object for "Accessible-Coconut" (currently category:
"") to the correct lowercase value (e.g., "beginner" if intended) and change any
entries using "Beginner" (capitalized) to "beginner" so filtering works
consistently (search for the object with name "Accessible-Coconut" and the entry
containing category "Beginner" to edit their category fields).
In `@docs/distros.md`:
- Around line 67-70: The fallback logic for distro icons currently only accepts
PNGs and sets iconSrc using the distro.icon check in the expression that defines
iconSrc; update that logic so it also accepts SVG (and other common web image
formats) instead of only '.png' — modify the condition that references
distro.icon.endsWith('.png') (used when computing iconSrc) to allow '.svg' (or a
whitelist like '.png' | '.svg' | '.jpg' | '.jpeg') and keep the fallback
'img/distro/default-distro.png' when the icon is missing or not an accepted
format.
- Around line 76-99: The card rendering currently builds card.innerHTML by
interpolating raw fields (iconSrc, distro.name, distro.websiteLink,
cleanVersion, distro.description, distro.downloadLink), which allows XSS via
unsafe HTML or javascript: URLs; fix by replacing the innerHTML construction
with DOM-safe creation (createElement, setAttribute, textContent) and by
validating/normalizing links for distro.websiteLink and distro.downloadLink to
only allow http and https schemes (reject or replace others with '#' or remove
the anchor) and sanitize/escape any string values (name, cleanVersion,
description) before inserting them into textContent or attribute values; ensure
iconSrc is validated as an http/https URL before setting as img.src.
In `@docs/README.md`:
- Line 298: The heading "parent site [oSoWoSo](https://osowoso.org)" is
currently H4 and causes a heading-level jump (MD001); change that line to an
appropriate level (e.g., H2 or H3) so it increments properly from the preceding
H1—update the markdown at the heading text "parent site
[oSoWoSo](https://osowoso.org)" to use "##" or "###" instead of "####" to
restore correct document structure and navigation.
In `@src/distros.css`:
- Line 3: The `@import` line currently uses single quotes and the project lint
rules flag both the URL quoting and the quoted font-family name; update the
`@import` to use double quotes around the URL (e.g. `@import`
url("https://fonts.googleapis.com/...")) and remove unnecessary quotes around
the Roboto family wherever it's used (change font-family: 'Roboto', ... to
font-family: Roboto, ...); locate the `@import` url(...) line and any font-family
declarations referencing 'Roboto' to apply these changes.
- Around line 101-125: You’re overriding global Bootstrap classes (.row and
.col-md-4) which can break other layouts; scope these rules to the distro
component by prefixing the selectors with the distro container class/id used in
this component (e.g. change selectors to target .distro-container .row and
.distro-container .col-md-4 and update the matching media query selectors the
same way), keeping the same declarations but confined to that container so
Bootstrap global grid behavior elsewhere is unaffected.
In `@src/distros.js`:
- Line 134: The distro entries in the distros array have inconsistent category
values which break the lowercase strict filter: update the objects (e.g., the
one with name "Accessible-Coconut" that currently has category "" and the entry
using "Beginner") to use the normalized, lowercase category tokens your
filtering expects (for example set category: "uncategorized" or the project’s
canonical "other" for empty values and change "Beginner" to "beginner"); make
the values consistent across the distros array in src/distros.js so the filter
matches correctly.
In `@src/distros.md`:
- Line 67: The template uses distro.version directly in the expression that sets
cleanVersion, which throws when version is undefined; update the assignment for
cleanVersion (where distro.version is referenced) to guard against missing
values by checking distro.version or using a safe fallback (e.g., const
cleanVersion = (distro.version || '').replace(/\sx86_64/i, '')) so rendering
continues when version is absent.
- Around line 68-70: The code sets iconSrc using a check that only accepts .png,
causing .svg logos to be treated as missing; update the logic that computes
iconSrc (the distro.icon check and assignment) to accept .svg as well (e.g.,
treat distro.icon as valid if it endsWith('.png') or endsWith('.svg') / matches
/\.(png|svg)$/i) while keeping the default 'img/distro/default-distro.png'
fallback and preserving null/undefined safety for distro.icon.
- Around line 76-98: The code currently sets card.innerHTML using untrusted
distro fields (iconSrc, distro.websiteLink, distro.name, cleanVersion,
distro.description, distro.downloadLink), which risks HTML/JS injection; replace
the innerHTML assignment in the rendering path (the block that builds the card)
with explicit DOM construction: create elements with document.createElement for
the card container, img, h5, a, p, div, and button/link, set attributes via
setAttribute or element.href/src, and assign text nodes via textContent (not
innerHTML) for name, cleanVersion and description; ensure the link elements use
rel="noopener" and target="_blank" and validate or fallback non-http
downloadLink before assigning to href to avoid javascript: URIs.
---
Nitpick comments:
In `@docs/distros.md`:
- Around line 29-52: The inline <style> block in docs/distros.md (selectors:
body, .search-container .form-control, .search-container
.form-control::placeholder, .filter-btn, .filter-btn:hover/.active) duplicates
rules already in the new stylesheet; remove this inline style from the MD file
and relocate those rules into docs/distros.css (or merge with the existing
definitions there), ensuring the selectors and declarations are preserved and
any specificity/order is adjusted so visual behavior (dark background, search
input, placeholder color, filter button states) remains identical.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ef243ce6-28c8-4955-afec-3844ed0a1c1f
⛔ Files ignored due to path filters (291)
docs/img/distro/4mlinux.pngis excluded by!**/*.pngdocs/img/distro/ac.pngis excluded by!**/*.pngdocs/img/distro/adelie.pngis excluded by!**/*.pngdocs/img/distro/agarimos.pngis excluded by!**/*.pngdocs/img/distro/alienos.pngis excluded by!**/*.pngdocs/img/distro/alma.svgis excluded by!**/*.svgdocs/img/distro/alpine.pngis excluded by!**/*.pngdocs/img/distro/alt.pngis excluded by!**/*.pngdocs/img/distro/anduinos.pngis excluded by!**/*.pngdocs/img/distro/antiX.pngis excluded by!**/*.pngdocs/img/distro/arch.svgis excluded by!**/*.svgdocs/img/distro/archbang.pngis excluded by!**/*.pngdocs/img/distro/archcraft.pngis excluded by!**/*.pngdocs/img/distro/archman.pngis excluded by!**/*.pngdocs/img/distro/arcolinux.svgis excluded by!**/*.svgdocs/img/distro/arkane.pngis excluded by!**/*.pngdocs/img/distro/artix.svgis excluded by!**/*.svgdocs/img/distro/athena.pngis excluded by!**/*.pngdocs/img/distro/aurora.svgis excluded by!**/*.svgdocs/img/distro/avlinux.pngis excluded by!**/*.pngdocs/img/distro/axos.pngis excluded by!**/*.pngdocs/img/distro/backbox.pngis excluded by!**/*.pngdocs/img/distro/batocera.pngis excluded by!**/*.pngdocs/img/distro/bazzite.pngis excluded by!**/*.pngdocs/img/distro/besgnulinux.pngis excluded by!**/*.pngdocs/img/distro/biglinux.pngis excluded by!**/*.pngdocs/img/distro/blackarch.pngis excluded by!**/*.pngdocs/img/distro/blendos.svgis excluded by!**/*.svgdocs/img/distro/bliss.pngis excluded by!**/*.pngdocs/img/distro/bluefin.pngis excluded by!**/*.pngdocs/img/distro/bodhi.pngis excluded by!**/*.pngdocs/img/distro/bredos.pngis excluded by!**/*.pngdocs/img/distro/bunsenlabs.pngis excluded by!**/*.pngdocs/img/distro/cachy.svgis excluded by!**/*.svgdocs/img/distro/calculate.pngis excluded by!**/*.pngdocs/img/distro/catos.svgis excluded by!**/*.svgdocs/img/distro/cereus.svgis excluded by!**/*.svgdocs/img/distro/chimera.pngis excluded by!**/*.pngdocs/img/distro/chimeraos.svgis excluded by!**/*.svgdocs/img/distro/clearlinux.svgis excluded by!**/*.svgdocs/img/distro/ctlos.svgis excluded by!**/*.svgdocs/img/distro/cuerdos.pngis excluded by!**/*.pngdocs/img/distro/datlinux.pngis excluded by!**/*.pngdocs/img/distro/debian.svgis excluded by!**/*.svgdocs/img/distro/deblinux.pngis excluded by!**/*.pngdocs/img/distro/deepin.svgis excluded by!**/*.svgdocs/img/distro/delinuxco.pngis excluded by!**/*.pngdocs/img/distro/devuan.pngis excluded by!**/*.pngdocs/img/distro/ditana.pngis excluded by!**/*.pngdocs/img/distro/drauger.pngis excluded by!**/*.pngdocs/img/distro/drparted.pngis excluded by!**/*.pngdocs/img/distro/dsl.pngis excluded by!**/*.pngdocs/img/distro/dynebolic.pngis excluded by!**/*.pngdocs/img/distro/elementary.pngis excluded by!**/*.pngdocs/img/distro/elive.pngis excluded by!**/*.pngdocs/img/distro/emmabuntüs.pngis excluded by!**/*.pngdocs/img/distro/endlessos.pngis excluded by!**/*.pngdocs/img/distro/eos.pngis excluded by!**/*.pngdocs/img/distro/eweos.svgis excluded by!**/*.svgdocs/img/distro/exe.pngis excluded by!**/*.pngdocs/img/distro/exherbo.svgis excluded by!**/*.svgdocs/img/distro/exodia.pngis excluded by!**/*.pngdocs/img/distro/fatdog.pngis excluded by!**/*.pngdocs/img/distro/fedora.svgis excluded by!**/*.svgdocs/img/distro/ferenos.pngis excluded by!**/*.pngdocs/img/distro/finnix.svgis excluded by!**/*.svgdocs/img/distro/freebsd.pngis excluded by!**/*.pngdocs/img/distro/funos.pngis excluded by!**/*.pngdocs/img/distro/garuda.svgis excluded by!**/*.svgdocs/img/distro/gentoo.pngis excluded by!**/*.pngdocs/img/distro/ghostbsd.pngis excluded by!**/*.pngdocs/img/distro/guix.svgis excluded by!**/*.svgdocs/img/distro/gxde.pngis excluded by!**/*.pngdocs/img/distro/heliumos.svgis excluded by!**/*.svgdocs/img/distro/hellosystem.pngis excluded by!**/*.pngdocs/img/distro/hyperbola.pngis excluded by!**/*.pngdocs/img/distro/instantos.svgis excluded by!**/*.svgdocs/img/distro/joborun.pngis excluded by!**/*.pngdocs/img/distro/kaisen.pngis excluded by!**/*.pngdocs/img/distro/kali.svgis excluded by!**/*.svgdocs/img/distro/kamarada.pngis excluded by!**/*.pngdocs/img/distro/kanotix.pngis excluded by!**/*.pngdocs/img/distro/kaos.svgis excluded by!**/*.svgdocs/img/distro/kolibrios.pngis excluded by!**/*.pngdocs/img/distro/kubuntu.svgis excluded by!**/*.svgdocs/img/distro/kumander.pngis excluded by!**/*.pngdocs/img/distro/lastoslinux.pngis excluded by!**/*.pngdocs/img/distro/lazylinux.pngis excluded by!**/*.pngdocs/img/distro/leap.pngis excluded by!**/*.pngdocs/img/distro/libreelec.pngis excluded by!**/*.pngdocs/img/distro/lilidog.svgis excluded by!**/*.svgdocs/img/distro/lingmoos.pngis excluded by!**/*.pngdocs/img/distro/linuxconsole.pngis excluded by!**/*.pngdocs/img/distro/linuxhub.pngis excluded by!**/*.pngdocs/img/distro/linuxlite.pngis excluded by!**/*.pngdocs/img/distro/lionlinux.pngis excluded by!**/*.pngdocs/img/distro/lirix.pngis excluded by!**/*.pngdocs/img/distro/liya.pngis excluded by!**/*.pngdocs/img/distro/loc-os.pngis excluded by!**/*.pngdocs/img/distro/mabox.pngis excluded by!**/*.pngdocs/img/distro/mageia.pngis excluded by!**/*.pngdocs/img/distro/makulu.svgis excluded by!**/*.svgdocs/img/distro/manjaro.svgis excluded by!**/*.svgdocs/img/distro/martineos.pngis excluded by!**/*.pngdocs/img/distro/mauna.pngis excluded by!**/*.pngdocs/img/distro/melawy.svgis excluded by!**/*.svgdocs/img/distro/minios.pngis excluded by!**/*.pngdocs/img/distro/mint.svgis excluded by!**/*.svgdocs/img/distro/miracle.pngis excluded by!**/*.pngdocs/img/distro/mocaccino.pngis excluded by!**/*.pngdocs/img/distro/modicia.pngis excluded by!**/*.pngdocs/img/distro/mofo.pngis excluded by!**/*.pngdocs/img/distro/mxlinux.pngis excluded by!**/*.pngdocs/img/distro/nebios.svgis excluded by!**/*.svgdocs/img/distro/neon.svgis excluded by!**/*.svgdocs/img/distro/neptune.pngis excluded by!**/*.pngdocs/img/distro/netrunner.pngis excluded by!**/*.pngdocs/img/distro/nitrux.pngis excluded by!**/*.pngdocs/img/distro/nix.pngis excluded by!**/*.pngdocs/img/distro/nobara.pngis excluded by!**/*.pngdocs/img/distro/nutyx.pngis excluded by!**/*.pngdocs/img/distro/obarun.pngis excluded by!**/*.pngdocs/img/distro/omegalinux.pngis excluded by!**/*.pngdocs/img/distro/omnios.pngis excluded by!**/*.pngdocs/img/distro/onixos.pngis excluded by!**/*.pngdocs/img/distro/openbsd.pngis excluded by!**/*.pngdocs/img/distro/openindiana.pngis excluded by!**/*.pngdocs/img/distro/openkylin.pngis excluded by!**/*.pngdocs/img/distro/openmamba.svgis excluded by!**/*.svgdocs/img/distro/openmandriva.pngis excluded by!**/*.pngdocs/img/distro/oracle.pngis excluded by!**/*.pngdocs/img/distro/oreon.pngis excluded by!**/*.pngdocs/img/distro/parabola.pngis excluded by!**/*.pngdocs/img/distro/parch.svgis excluded by!**/*.svgdocs/img/distro/pardus.pngis excluded by!**/*.pngdocs/img/distro/parrotos.pngis excluded by!**/*.pngdocs/img/distro/pclinuxos.svgis excluded by!**/*.svgdocs/img/distro/pearl.pngis excluded by!**/*.pngdocs/img/distro/pentoo.pngis excluded by!**/*.pngdocs/img/distro/peppermint.svgis excluded by!**/*.svgdocs/img/distro/pikaos.svgis excluded by!**/*.svgdocs/img/distro/pisi.pngis excluded by!**/*.pngdocs/img/distro/plop.pngis excluded by!**/*.pngdocs/img/distro/pop.pngis excluded by!**/*.pngdocs/img/distro/porteux.pngis excluded by!**/*.pngdocs/img/distro/predator-os.pngis excluded by!**/*.pngdocs/img/distro/primtux.pngis excluded by!**/*.pngdocs/img/distro/puppy.pngis excluded by!**/*.pngdocs/img/distro/q4os.pngis excluded by!**/*.pngdocs/img/distro/quarkos.pngis excluded by!**/*.pngdocs/img/distro/qubes.svgis excluded by!**/*.svgdocs/img/distro/raspberry.svgis excluded by!**/*.svgdocs/img/distro/ravynos.pngis excluded by!**/*.pngdocs/img/distro/reborn.svgis excluded by!**/*.svgdocs/img/distro/redcore.pngis excluded by!**/*.pngdocs/img/distro/redox.pngis excluded by!**/*.pngdocs/img/distro/refracta.pngis excluded by!**/*.pngdocs/img/distro/regata.pngis excluded by!**/*.pngdocs/img/distro/rhino.pngis excluded by!**/*.pngdocs/img/distro/rlxos.pngis excluded by!**/*.pngdocs/img/distro/rocky.svgis excluded by!**/*.svgdocs/img/distro/runtu.pngis excluded by!**/*.pngdocs/img/distro/salix.pngis excluded by!**/*.pngdocs/img/distro/sdesk.pngis excluded by!**/*.pngdocs/img/distro/serpentos.pngis excluded by!**/*.pngdocs/img/distro/shebang.pngis excluded by!**/*.pngdocs/img/distro/siduction.pngis excluded by!**/*.pngdocs/img/distro/sigmalinux.pngis excluded by!**/*.pngdocs/img/distro/slackel.svgis excluded by!**/*.svgdocs/img/distro/slackware.pngis excluded by!**/*.pngdocs/img/distro/slax.pngis excluded by!**/*.pngdocs/img/distro/slitaz.pngis excluded by!**/*.pngdocs/img/distro/smartos.pngis excluded by!**/*.pngdocs/img/distro/solus.pngis excluded by!**/*.pngdocs/img/distro/solydxk.pngis excluded by!**/*.pngdocs/img/distro/sparky.pngis excluded by!**/*.pngdocs/img/distro/starbuntu.pngis excluded by!**/*.pngdocs/img/distro/steamfork.pngis excluded by!**/*.pngdocs/img/distro/stormos.pngis excluded by!**/*.pngdocs/img/distro/stratos.pngis excluded by!**/*.pngdocs/img/distro/suse.pngis excluded by!**/*.pngdocs/img/distro/tails.svgis excluded by!**/*.svgdocs/img/distro/tiger-os.pngis excluded by!**/*.pngdocs/img/distro/tileos.svgis excluded by!**/*.svgdocs/img/distro/tinycore.pngis excluded by!**/*.pngdocs/img/distro/tribblix.svgis excluded by!**/*.svgdocs/img/distro/trisquel.pngis excluded by!**/*.pngdocs/img/distro/tromjaro.pngis excluded by!**/*.pngdocs/img/distro/tsurugi.pngis excluded by!**/*.pngdocs/img/distro/ttos.pngis excluded by!**/*.pngdocs/img/distro/tumbleweed.pngis excluded by!**/*.pngdocs/img/distro/tux.pngis excluded by!**/*.pngdocs/img/distro/tuxedo.pngis excluded by!**/*.pngdocs/img/distro/twister.pngis excluded by!**/*.pngdocs/img/distro/ubuntu.pngis excluded by!**/*.pngdocs/img/distro/ufficiozero.pngis excluded by!**/*.pngdocs/img/distro/ultramarine.svgis excluded by!**/*.svgdocs/img/distro/vanilla.svgis excluded by!**/*.svgdocs/img/distro/vengefoulwolf.pngis excluded by!**/*.pngdocs/img/distro/venom.pngis excluded by!**/*.pngdocs/img/distro/vinarios.pngis excluded by!**/*.pngdocs/img/distro/void.pngis excluded by!**/*.pngdocs/img/distro/voyager.pngis excluded by!**/*.pngdocs/img/distro/wattos.pngis excluded by!**/*.pngdocs/img/distro/wmlive.pngis excluded by!**/*.pngdocs/img/distro/wolfos.pngis excluded by!**/*.pngdocs/img/distro/xebian.pngis excluded by!**/*.pngdocs/img/distro/zenned.pngis excluded by!**/*.pngdocs/img/distro/zenwalk.pngis excluded by!**/*.pngdocs/img/distro/zephix.pngis excluded by!**/*.pngdocs/img/distro/zorin.svgis excluded by!**/*.svgsrc/img/distro/4mlinux.pngis excluded by!**/*.pngsrc/img/distro/ac.pngis excluded by!**/*.pngsrc/img/distro/adelie.pngis excluded by!**/*.pngsrc/img/distro/agarimos.pngis excluded by!**/*.pngsrc/img/distro/alienos.pngis excluded by!**/*.pngsrc/img/distro/alma.svgis excluded by!**/*.svgsrc/img/distro/alpine.pngis excluded by!**/*.pngsrc/img/distro/alt.pngis excluded by!**/*.pngsrc/img/distro/anduinos.pngis excluded by!**/*.pngsrc/img/distro/antiX.pngis excluded by!**/*.pngsrc/img/distro/arch.svgis excluded by!**/*.svgsrc/img/distro/archbang.pngis excluded by!**/*.pngsrc/img/distro/archcraft.pngis excluded by!**/*.pngsrc/img/distro/archman.pngis excluded by!**/*.pngsrc/img/distro/arcolinux.svgis excluded by!**/*.svgsrc/img/distro/arkane.pngis excluded by!**/*.pngsrc/img/distro/artix.svgis excluded by!**/*.svgsrc/img/distro/athena.pngis excluded by!**/*.pngsrc/img/distro/aurora.svgis excluded by!**/*.svgsrc/img/distro/avlinux.pngis excluded by!**/*.pngsrc/img/distro/axos.pngis excluded by!**/*.pngsrc/img/distro/backbox.pngis excluded by!**/*.pngsrc/img/distro/batocera.pngis excluded by!**/*.pngsrc/img/distro/bazzite.pngis excluded by!**/*.pngsrc/img/distro/besgnulinux.pngis excluded by!**/*.pngsrc/img/distro/biglinux.pngis excluded by!**/*.pngsrc/img/distro/blackarch.pngis excluded by!**/*.pngsrc/img/distro/blendos.svgis excluded by!**/*.svgsrc/img/distro/bliss.pngis excluded by!**/*.pngsrc/img/distro/bluefin.pngis excluded by!**/*.pngsrc/img/distro/bodhi.pngis excluded by!**/*.pngsrc/img/distro/bredos.pngis excluded by!**/*.pngsrc/img/distro/bunsenlabs.pngis excluded by!**/*.pngsrc/img/distro/cachy.svgis excluded by!**/*.svgsrc/img/distro/calculate.pngis excluded by!**/*.pngsrc/img/distro/catos.svgis excluded by!**/*.svgsrc/img/distro/cereus.svgis excluded by!**/*.svgsrc/img/distro/chimera.pngis excluded by!**/*.pngsrc/img/distro/chimeraos.svgis excluded by!**/*.svgsrc/img/distro/clearlinux.svgis excluded by!**/*.svgsrc/img/distro/ctlos.svgis excluded by!**/*.svgsrc/img/distro/cuerdos.pngis excluded by!**/*.pngsrc/img/distro/datlinux.pngis excluded by!**/*.pngsrc/img/distro/debian.svgis excluded by!**/*.svgsrc/img/distro/deblinux.pngis excluded by!**/*.pngsrc/img/distro/deepin.svgis excluded by!**/*.svgsrc/img/distro/delinuxco.pngis excluded by!**/*.pngsrc/img/distro/devuan.pngis excluded by!**/*.pngsrc/img/distro/ditana.pngis excluded by!**/*.pngsrc/img/distro/drauger.pngis excluded by!**/*.pngsrc/img/distro/drparted.pngis excluded by!**/*.pngsrc/img/distro/dsl.pngis excluded by!**/*.pngsrc/img/distro/dynebolic.pngis excluded by!**/*.pngsrc/img/distro/elementary.pngis excluded by!**/*.pngsrc/img/distro/elive.pngis excluded by!**/*.pngsrc/img/distro/emmabuntüs.pngis excluded by!**/*.pngsrc/img/distro/endlessos.pngis excluded by!**/*.pngsrc/img/distro/eos.pngis excluded by!**/*.pngsrc/img/distro/eweos.svgis excluded by!**/*.svgsrc/img/distro/exe.pngis excluded by!**/*.pngsrc/img/distro/exherbo.svgis excluded by!**/*.svgsrc/img/distro/exodia.pngis excluded by!**/*.pngsrc/img/distro/fatdog.pngis excluded by!**/*.pngsrc/img/distro/fedora.svgis excluded by!**/*.svgsrc/img/distro/ferenos.pngis excluded by!**/*.pngsrc/img/distro/finnix.svgis excluded by!**/*.svgsrc/img/distro/freebsd.pngis excluded by!**/*.pngsrc/img/distro/funos.pngis excluded by!**/*.pngsrc/img/distro/garuda.svgis excluded by!**/*.svgsrc/img/distro/gentoo.pngis excluded by!**/*.pngsrc/img/distro/ghostbsd.pngis excluded by!**/*.pngsrc/img/distro/guix.svgis excluded by!**/*.svgsrc/img/distro/gxde.pngis excluded by!**/*.pngsrc/img/distro/heliumos.svgis excluded by!**/*.svgsrc/img/distro/hellosystem.pngis excluded by!**/*.pngsrc/img/distro/hyperbola.pngis excluded by!**/*.pngsrc/img/distro/instantos.svgis excluded by!**/*.svgsrc/img/distro/joborun.pngis excluded by!**/*.pngsrc/img/distro/kaisen.pngis excluded by!**/*.pngsrc/img/distro/kali.svgis excluded by!**/*.svg
📒 Files selected for processing (9)
docs/README-web.htmldocs/README.mddocs/SECURITY.htmldocs/distros.cssdocs/distros.jsdocs/distros.mdsrc/distros.csssrc/distros.jssrc/distros.md
| @@ -0,0 +1,234 @@ | |||
| /* DistroHopper Distribution Gallery Styles - Based on distributionhub design */ | |||
|
|
|||
| @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'); | |||
There was a problem hiding this comment.
Fix the two stylelint violations (@import notation and font-family quotes).
Line 3 and Line 10 currently violate the configured lint rules and will keep CI/style checks noisy.
🔧 Suggested patch
-@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
+@import 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap';
body {
- font-family: 'Roboto', sans-serif;
+ font-family: Roboto, sans-serif;
background-color: `#1a1a1a`;
color: `#ffffff`;
}Also applies to: 10-10
🧰 Tools
🪛 Stylelint (17.7.0)
[error] 3-3: Expected "url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap')" to be "'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'" (import-notation)
(import-notation)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/distros.css` at line 3, Replace the current `@import`
url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
with the plain `@import`
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap";
and update any font-family declarations that use quoted family names (e.g.,
font-family: 'Roboto', sans-serif;) to unquoted identifiers (e.g., font-family:
Roboto, sans-serif;), so the `@import` notation and the "Roboto" font-family
quotes satisfy the stylelint rules.
| { name: "AnduinOS", version: "1.1 x86_64", icon: "img/distro/anduinos.png", downloadLink: "https://download.anduinos.com/1.1/1.1.1/AnduinOS-1.1.1-en_US.iso", description: "A custom Debian-based Linux distribution", websiteLink: "https://www.anduinos.com/", category: "beginner"}, | ||
| { name: "openKylin", version: "2.0 SP1 x86_64", icon: "img/distro/openkylin.png", downloadLink: "https://www.openkylin.top/downloads/download-smp.php?id=80", description: "A Linux operating system based on Ubuntu.", websiteLink: "https://www.openkylin.top/index-en.html", category: "beginner"}, | ||
| { name: "NebiOS", version: "3.2 x86_64", icon: "img/distro/nebios.svg", downloadLink: "https://release.nebisoftware.com/NebiOS/Stable/3.2/nebios-3.2-amd64.iso", description: "A quantum leap forward in Linux innovation.", websiteLink: "https://nebisoftware.com/nebios", category: "beginner"}, | ||
| { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: ""}, |
There was a problem hiding this comment.
Normalize category values to keep filtering correct.
Line 146 uses Beginner (capitalized), but UI filter comparisons are lowercase; this entry will not show under the Beginner filter. Line 134 has an empty category, so it also won’t match any category filter.
🔧 Suggested patch
- { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: ""},
+ { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: "beginner"},
...
- { name: "Batocera", version: "41 x86_64", icon: "img/distro/batocera.png", downloadLink: "https://buzzheavier.com/eft5npjtcraz/download", description: "Distribution for turning a computer into a console", websiteLink: "https://batocera.org/", category: "Beginner", torrent: "https://updates.batocera.org/torrents/batocera-x86_64-41-20250106.img.gz.torrent"},
+ { name: "Batocera", version: "41 x86_64", icon: "img/distro/batocera.png", downloadLink: "https://buzzheavier.com/eft5npjtcraz/download", description: "Distribution for turning a computer into a console", websiteLink: "https://batocera.org/", category: "beginner", torrent: "https://updates.batocera.org/torrents/batocera-x86_64-41-20250106.img.gz.torrent"},Also applies to: 146-146
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/distros.js` at line 134, The category values must be normalized to
lowercase so UI filters match; update the distro object for "Accessible-Coconut"
(currently category: "") to the correct lowercase value (e.g., "beginner" if
intended) and change any entries using "Beginner" (capitalized) to "beginner" so
filtering works consistently (search for the object with name
"Accessible-Coconut" and the entry containing category "Beginner" to edit their
category fields).
| const cleanVersion = distro.version.replace(/\sx86_64/i, ''); | ||
| // Use default icon if not found or just use the path as-is from distributionhub | ||
| const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png'; | ||
|
|
There was a problem hiding this comment.
Support SVG icons in fallback logic (current check hides many valid logos).
Line 69 only allows .png, but the dataset includes many .svg icons, so those cards incorrectly fall back to the default image.
🔧 Suggested patch
- const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png';
+ const iconSrc =
+ distro.icon && /\.(png|svg|webp|avif)$/i.test(distro.icon)
+ ? distro.icon
+ : 'img/distro/default-distro.png';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const cleanVersion = distro.version.replace(/\sx86_64/i, ''); | |
| // Use default icon if not found or just use the path as-is from distributionhub | |
| const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png'; | |
| const cleanVersion = distro.version.replace(/\sx86_64/i, ''); | |
| // Use default icon if not found or just use the path as-is from distributionhub | |
| const iconSrc = | |
| distro.icon && /\.(png|svg|webp|avif)$/i.test(distro.icon) | |
| ? distro.icon | |
| : 'img/distro/default-distro.png'; | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/distros.md` around lines 67 - 70, The fallback logic for distro icons
currently only accepts PNGs and sets iconSrc using the distro.icon check in the
expression that defines iconSrc; update that logic so it also accepts SVG (and
other common web image formats) instead of only '.png' — modify the condition
that references distro.icon.endsWith('.png') (used when computing iconSrc) to
allow '.svg' (or a whitelist like '.png' | '.svg' | '.jpg' | '.jpeg') and keep
the fallback 'img/distro/default-distro.png' when the icon is missing or not an
accepted format.
| card.innerHTML = ` | ||
| <div class="card h-100"> | ||
| <div class="card-img-container"> | ||
| <img src="${iconSrc}" class="card-img-top" alt="${distro.name} logo" loading="lazy"> | ||
| </div> | ||
| <div class="card-body d-flex flex-column"> | ||
| <h5 class="card-title"> | ||
| ${distro.websiteLink ? `<a href="${distro.websiteLink}" class="distro-title-link" target="_blank" rel="noopener">` : ''} | ||
| <strong>${distro.name}</strong> | ||
| ${distro.websiteLink ? '</a>' : ''} | ||
| </h5> | ||
| <div class="card-text distro-version"> | ||
| <strong>Version:</strong> ${cleanVersion} | ||
| </div> | ||
| <p class="card-text flex-grow-1">${distro.description || ''}</p> | ||
| <div class="mt-auto"> | ||
| <a href="${distro.downloadLink || '#'}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener"> | ||
| <i class="fas fa-download me-2"></i>Download | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| `; | ||
|
|
There was a problem hiding this comment.
Harden card rendering against HTML/URL injection.
Line 76–99 interpolates raw distribution fields into innerHTML. If upstream data includes unsafe HTML or javascript: URLs, this becomes an XSS vector.
🔧 Suggested hardening (escape text + allow only http/https URLs)
+ const escapeHtml = (value = '') =>
+ String(value)
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+
+ const safeUrl = (value, fallback = '#') => {
+ try {
+ const u = new URL(value, window.location.origin);
+ return (u.protocol === 'http:' || u.protocol === 'https:') ? u.href : fallback;
+ } catch {
+ return fallback;
+ }
+ };
...
- card.innerHTML = `
+ card.innerHTML = `
<div class="card h-100">
<div class="card-img-container">
- <img src="${iconSrc}" class="card-img-top" alt="${distro.name} logo" loading="lazy">
+ <img src="${escapeHtml(iconSrc)}" class="card-img-top" alt="${escapeHtml(distro.name)} logo" loading="lazy">
</div>
<div class="card-body d-flex flex-column">
<h5 class="card-title">
- ${distro.websiteLink ? `<a href="${distro.websiteLink}" class="distro-title-link" target="_blank" rel="noopener">` : ''}
- <strong>${distro.name}</strong>
+ ${distro.websiteLink ? `<a href="${safeUrl(distro.websiteLink)}" class="distro-title-link" target="_blank" rel="noopener">` : ''}
+ <strong>${escapeHtml(distro.name)}</strong>
${distro.websiteLink ? '</a>' : ''}
</h5>
<div class="card-text distro-version">
- <strong>Version:</strong> ${cleanVersion}
+ <strong>Version:</strong> ${escapeHtml(cleanVersion)}
</div>
- <p class="card-text flex-grow-1">${distro.description || ''}</p>
+ <p class="card-text flex-grow-1">${escapeHtml(distro.description || '')}</p>
<div class="mt-auto">
- <a href="${distro.downloadLink || '#'}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener">
+ <a href="${safeUrl(distro.downloadLink || '#')}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener">
<i class="fas fa-download me-2"></i>Download
</a>
</div>
</div>
</div>
`;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| card.innerHTML = ` | |
| <div class="card h-100"> | |
| <div class="card-img-container"> | |
| <img src="${iconSrc}" class="card-img-top" alt="${distro.name} logo" loading="lazy"> | |
| </div> | |
| <div class="card-body d-flex flex-column"> | |
| <h5 class="card-title"> | |
| ${distro.websiteLink ? `<a href="${distro.websiteLink}" class="distro-title-link" target="_blank" rel="noopener">` : ''} | |
| <strong>${distro.name}</strong> | |
| ${distro.websiteLink ? '</a>' : ''} | |
| </h5> | |
| <div class="card-text distro-version"> | |
| <strong>Version:</strong> ${cleanVersion} | |
| </div> | |
| <p class="card-text flex-grow-1">${distro.description || ''}</p> | |
| <div class="mt-auto"> | |
| <a href="${distro.downloadLink || '#'}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener"> | |
| <i class="fas fa-download me-2"></i>Download | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| const escapeHtml = (value = '') => | |
| String(value) | |
| .replace(/&/g, '&') | |
| .replace(/</g, '<') | |
| .replace(/>/g, '>') | |
| .replace(/"/g, '"') | |
| .replace(/'/g, '''); | |
| const safeUrl = (value, fallback = '#') => { | |
| try { | |
| const u = new URL(value, window.location.origin); | |
| return (u.protocol === 'http:' || u.protocol === 'https:') ? u.href : fallback; | |
| } catch { | |
| return fallback; | |
| } | |
| }; | |
| card.innerHTML = ` | |
| <div class="card h-100"> | |
| <div class="card-img-container"> | |
| <img src="${escapeHtml(iconSrc)}" class="card-img-top" alt="${escapeHtml(distro.name)} logo" loading="lazy"> | |
| </div> | |
| <div class="card-body d-flex flex-column"> | |
| <h5 class="card-title"> | |
| ${distro.websiteLink ? `<a href="${safeUrl(distro.websiteLink)}" class="distro-title-link" target="_blank" rel="noopener">` : ''} | |
| <strong>${escapeHtml(distro.name)}</strong> | |
| ${distro.websiteLink ? '</a>' : ''} | |
| </h5> | |
| <div class="card-text distro-version"> | |
| <strong>Version:</strong> ${escapeHtml(cleanVersion)} | |
| </div> | |
| <p class="card-text flex-grow-1">${escapeHtml(distro.description || '')}</p> | |
| <div class="mt-auto"> | |
| <a href="${safeUrl(distro.downloadLink || '#')}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener"> | |
| <i class="fas fa-download me-2"></i>Download | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| `; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/distros.md` around lines 76 - 99, The card rendering currently builds
card.innerHTML by interpolating raw fields (iconSrc, distro.name,
distro.websiteLink, cleanVersion, distro.description, distro.downloadLink),
which allows XSS via unsafe HTML or javascript: URLs; fix by replacing the
innerHTML construction with DOM-safe creation (createElement, setAttribute,
textContent) and by validating/normalizing links for distro.websiteLink and
distro.downloadLink to only allow http and https schemes (reject or replace
others with '#' or remove the anchor) and sanitize/escape any string values
(name, cleanVersion, description) before inserting them into textContent or
attribute values; ensure iconSrc is validated as an http/https URL before
setting as img.src.
| [up](./) | ||
|
|
||
| #### parent site [oSoWoSo](https://osowoso.xyz) | ||
| #### parent site [oSoWoSo](https://osowoso.org) |
There was a problem hiding this comment.
Fix heading level jump at Line 298 (MD001).
Line 298 jumps from an H1 section to H4, which violates heading increment rules and can hurt document structure/navigation.
🛠️ Proposed fix
-#### parent site [oSoWoSo](https://osowoso.org)
+## parent site [oSoWoSo](https://osowoso.org)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### parent site [oSoWoSo](https://osowoso.org) | |
| ## parent site [oSoWoSo](https://osowoso.org) |
🧰 Tools
🪛 markdownlint-cli2 (0.22.0)
[warning] 298-298: Heading levels should only increment by one level at a time
Expected: h2; Actual: h4
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/README.md` at line 298, The heading "parent site
[oSoWoSo](https://osowoso.org)" is currently H4 and causes a heading-level jump
(MD001); change that line to an appropriate level (e.g., H2 or H3) so it
increments properly from the preceding H1—update the markdown at the heading
text "parent site [oSoWoSo](https://osowoso.org)" to use "##" or "###" instead
of "####" to restore correct document structure and navigation.
| .row { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
| margin: -0.75rem; | ||
| } | ||
|
|
||
| .col-md-4 { | ||
| flex: 0 0 calc(33.333% - 1.5rem); | ||
| max-width: calc(33.333% - 1.5rem); | ||
| padding: 0.75rem; | ||
| } | ||
|
|
||
| @media (max-width: 992px) { | ||
| .col-md-4 { | ||
| flex: 0 0 calc(50% - 1.5rem); | ||
| max-width: calc(50% - 1.5rem); | ||
| } | ||
| } | ||
|
|
||
| @media (max-width: 576px) { | ||
| .col-md-4 { | ||
| flex: 0 0 calc(100% - 1.5rem); | ||
| max-width: calc(100% - 1.5rem); | ||
| } | ||
| } |
There was a problem hiding this comment.
Scope grid overrides to the distro container instead of global Bootstrap classes.
Overriding .row and .col-md-4 globally can break unrelated Bootstrap layout blocks on this page.
Suggested fix
-.row {
+#distroList.row {
display: flex;
flex-wrap: wrap;
margin: -0.75rem;
}
-.col-md-4 {
+#distroList > .col-md-4 {
flex: 0 0 calc(33.333% - 1.5rem);
max-width: calc(33.333% - 1.5rem);
padding: 0.75rem;
}
`@media` (max-width: 992px) {
- .col-md-4 {
+ `#distroList` > .col-md-4 {
flex: 0 0 calc(50% - 1.5rem);
max-width: calc(50% - 1.5rem);
}
}
`@media` (max-width: 576px) {
- .col-md-4 {
+ `#distroList` > .col-md-4 {
flex: 0 0 calc(100% - 1.5rem);
max-width: calc(100% - 1.5rem);
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/distros.css` around lines 101 - 125, You’re overriding global Bootstrap
classes (.row and .col-md-4) which can break other layouts; scope these rules to
the distro component by prefixing the selectors with the distro container
class/id used in this component (e.g. change selectors to target
.distro-container .row and .distro-container .col-md-4 and update the matching
media query selectors the same way), keeping the same declarations but confined
to that container so Bootstrap global grid behavior elsewhere is unaffected.
| { name: "AnduinOS", version: "1.1 x86_64", icon: "img/distro/anduinos.png", downloadLink: "https://download.anduinos.com/1.1/1.1.1/AnduinOS-1.1.1-en_US.iso", description: "A custom Debian-based Linux distribution", websiteLink: "https://www.anduinos.com/", category: "beginner"}, | ||
| { name: "openKylin", version: "2.0 SP1 x86_64", icon: "img/distro/openkylin.png", downloadLink: "https://www.openkylin.top/downloads/download-smp.php?id=80", description: "A Linux operating system based on Ubuntu.", websiteLink: "https://www.openkylin.top/index-en.html", category: "beginner"}, | ||
| { name: "NebiOS", version: "3.2 x86_64", icon: "img/distro/nebios.svg", downloadLink: "https://release.nebisoftware.com/NebiOS/Stable/3.2/nebios-3.2-amd64.iso", description: "A quantum leap forward in Linux innovation.", websiteLink: "https://nebisoftware.com/nebios", category: "beginner"}, | ||
| { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: ""}, |
There was a problem hiding this comment.
Normalize category values to keep filter behavior correct.
Line 134 uses an empty category and Line 146 uses Beginner (capitalized). The filter logic does strict lowercase matching, so these cards won’t appear under expected filters.
Suggested fix
- { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: ""},
+ { name: "Accessible-Coconut", version: "22.04.3 x86_64", icon: "img/distro/ac.png", downloadLink: "https://sourceforge.net/projects/accessible-coconut/files/latest/download", description: "A GNU/Linux OS derived from Ubuntu-MATE.", websiteLink: "https://zendalona.com/accessible-coconut/", category: "beginner"},
- { name: "Batocera", version: "41 x86_64", icon: "img/distro/batocera.png", downloadLink: "https://buzzheavier.com/eft5npjtcraz/download", description: "Distribution for turning a computer into a console", websiteLink: "https://batocera.org/", category: "Beginner", torrent: "https://updates.batocera.org/torrents/batocera-x86_64-41-20250106.img.gz.torrent"},
+ { name: "Batocera", version: "41 x86_64", icon: "img/distro/batocera.png", downloadLink: "https://buzzheavier.com/eft5npjtcraz/download", description: "Distribution for turning a computer into a console", websiteLink: "https://batocera.org/", category: "beginner", torrent: "https://updates.batocera.org/torrents/batocera-x86_64-41-20250106.img.gz.torrent"},Also applies to: 146-146
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/distros.js` at line 134, The distro entries in the distros array have
inconsistent category values which break the lowercase strict filter: update the
objects (e.g., the one with name "Accessible-Coconut" that currently has
category "" and the entry using "Beginner") to use the normalized, lowercase
category tokens your filtering expects (for example set category:
"uncategorized" or the project’s canonical "other" for empty values and change
"Beginner" to "beginner"); make the values consistent across the distros array
in src/distros.js so the filter matches correctly.
| const distributions = window.distributions || []; | ||
|
|
||
| function createDistroCard(distro) { | ||
| const cleanVersion = distro.version.replace(/\sx86_64/i, ''); |
There was a problem hiding this comment.
Guard version before calling .replace() to prevent full render failure.
If a distro entry is missing version, this throws and aborts rendering for the whole list.
Suggested fix
- const cleanVersion = distro.version.replace(/\sx86_64/i, '');
+ const cleanVersion = String(distro.version || 'Unknown')
+ .replace(/\sx86_64/i, '')
+ .trim();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const cleanVersion = distro.version.replace(/\sx86_64/i, ''); | |
| const cleanVersion = String(distro.version || 'Unknown') | |
| .replace(/\sx86_64/i, '') | |
| .trim(); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/distros.md` at line 67, The template uses distro.version directly in the
expression that sets cleanVersion, which throws when version is undefined;
update the assignment for cleanVersion (where distro.version is referenced) to
guard against missing values by checking distro.version or using a safe fallback
(e.g., const cleanVersion = (distro.version || '').replace(/\sx86_64/i, '')) so
rendering continues when version is absent.
| // Use default icon if not found or just use the path as-is from distributionhub | ||
| const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png'; | ||
|
|
There was a problem hiding this comment.
SVG icons are currently treated as missing assets.
Line 69 only allows .png, but the dataset includes many .svg icons, so valid logos are replaced by the default image.
Suggested fix
- const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png';
+ const hasIcon = typeof distro.icon === 'string' && distro.icon.trim().length > 0;
+ const iconSrc = hasIcon ? distro.icon : 'img/distro/default-distro.png';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Use default icon if not found or just use the path as-is from distributionhub | |
| const iconSrc = distro.icon && distro.icon.endsWith('.png') ? distro.icon : 'img/distro/default-distro.png'; | |
| // Use default icon if not found or just use the path as-is from distributionhub | |
| const hasIcon = typeof distro.icon === 'string' && distro.icon.trim().length > 0; | |
| const iconSrc = hasIcon ? distro.icon : 'img/distro/default-distro.png'; | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/distros.md` around lines 68 - 70, The code sets iconSrc using a check
that only accepts .png, causing .svg logos to be treated as missing; update the
logic that computes iconSrc (the distro.icon check and assignment) to accept
.svg as well (e.g., treat distro.icon as valid if it endsWith('.png') or
endsWith('.svg') / matches /\.(png|svg)$/i) while keeping the default
'img/distro/default-distro.png' fallback and preserving null/undefined safety
for distro.icon.
| card.innerHTML = ` | ||
| <div class="card h-100"> | ||
| <div class="card-img-container"> | ||
| <img src="${iconSrc}" class="card-img-top" alt="${distro.name} logo" loading="lazy"> | ||
| </div> | ||
| <div class="card-body d-flex flex-column"> | ||
| <h5 class="card-title"> | ||
| ${distro.websiteLink ? `<a href="${distro.websiteLink}" class="distro-title-link" target="_blank" rel="noopener">` : ''} | ||
| <strong>${distro.name}</strong> | ||
| ${distro.websiteLink ? '</a>' : ''} | ||
| </h5> | ||
| <div class="card-text distro-version"> | ||
| <strong>Version:</strong> ${cleanVersion} | ||
| </div> | ||
| <p class="card-text flex-grow-1">${distro.description || ''}</p> | ||
| <div class="mt-auto"> | ||
| <a href="${distro.downloadLink || '#'}" class="btn btn-download flex-grow-1" target="_blank" rel="noopener"> | ||
| <i class="fas fa-download me-2"></i>Download | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| `; |
There was a problem hiding this comment.
Avoid injecting distro fields via innerHTML.
This path trusts external data fields directly in markup/attributes. A malformed entry can inject HTML/JS URLs into the page.
Suggested direction
- card.innerHTML = `
- <div class="card h-100">
- ...
- </div>
- `;
+ const safeUrl = (value) => {
+ try {
+ const u = new URL(value, window.location.origin);
+ return ['http:', 'https:'].includes(u.protocol) ? u.href : '#';
+ } catch {
+ return '#';
+ }
+ };
+ // Build elements with createElement/textContent and assign href via safeUrl(...)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/distros.md` around lines 76 - 98, The code currently sets card.innerHTML
using untrusted distro fields (iconSrc, distro.websiteLink, distro.name,
cleanVersion, distro.description, distro.downloadLink), which risks HTML/JS
injection; replace the innerHTML assignment in the rendering path (the block
that builds the card) with explicit DOM construction: create elements with
document.createElement for the card container, img, h5, a, p, div, and
button/link, set attributes via setAttribute or element.href/src, and assign
text nodes via textContent (not innerHTML) for name, cleanVersion and
description; ensure the link elements use rel="noopener" and target="_blank" and
validate or fallback non-http downloadLink before assigning to href to avoid
javascript: URIs.
Summary
Updated the distros page with distributionhub design:
Files
src/distros.html- Main page (standalone HTML)src/distros.css- DistributionHub-styled CSSsrc/distros.js- 211 distributions from distributionhubsrc/lib/- Bootstrap, FontAwesome, Animate CSSdocs/- Built filesNotes
The distros page is now a standalone HTML file to preserve the distributionhub design with its custom CSS/JS includes. This integrates with the main site navigation while using the black theme from distributionhub.