Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions _includes/appendix-filter.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div id="appendix-filter" class="appendix-filter" aria-label="Filter licenses by rules">
<p><strong>Filter by rules</strong> — show only licenses that match <em>every</em> selected attribute:</p>
<div class="appendix-filter-groups">
{% assign types = "permissions|conditions|limitations" | split: "|" %}
{% assign seen_tags = '' %}
{% for type in types %}
<fieldset class="appendix-filter-group">
<legend>{{ type | capitalize }}</legend>
{% assign rules = site.data.rules[type] | sort: "label" %}
{% for rule_obj in rules %}
{% if seen_tags contains rule_obj.tag or rule_obj.tag contains '--' %}
{% continue %}
{% endif %}
{% capture seen_tags %}{{ seen_tags | append:rule_obj.tag }}{% endcapture %}
<label class="appendix-filter-chip">
<input type="checkbox" value="{{ rule_obj.tag }}" data-rule-type="{{ type }}" />
{{ rule_obj.label }}
</label>
{% endfor %}
</fieldset>
{% endfor %}
</div>
<button type="button" id="appendix-filter-clear" class="appendix-filter-clear">Clear filters</button>
<p id="appendix-filter-status" class="appendix-filter-status" aria-live="polite"></p>
</div>
45 changes: 45 additions & 0 deletions _includes/css/responsive.css
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,51 @@
}
}

.appendix-table-wrapper {
overflow-x: auto;
max-width: 100%;
margin-bottom: 2rem;
}

.appendix-filter {
margin: 1.5rem 0;
padding: 1rem;
border: 1px solid #ddd;
border-radius: 6px;
background: color-mix(in srgb, var(--backgroundColor) 92%, #149ad4 8%);
}

.appendix-filter-groups {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.appendix-filter-group {
border: none;
margin: 0;
padding: 0;
min-width: 12rem;
}

.appendix-filter-chip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
margin: 0.15rem 0.5rem 0.15rem 0;
font-size: 0.85rem;
font-weight: normal;
}

.appendix-filter-clear {
margin-top: 0.75rem;
}

.appendix-filter-status {
margin: 0.5rem 0 0;
font-size: 0.85rem;
}

/* Smartphones (portrait) ----------- */
@media only screen and (max-width : 321px) {
.container {
Expand Down
15 changes: 13 additions & 2 deletions appendix.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ For reference, here is a table of every license described in the [choosealicense

If you're here to choose a license, **[start from the home page](/)** to see a few licenses that will work for most cases.

<table border style="font-size: xx-small; position: relative">
{% include appendix-filter.html %}

<div class="appendix-table-wrapper">
<table class="appendix-table" border style="font-size: xx-small; position: relative">
{% assign types = "permissions|conditions|limitations" | split: "|" %}
<thead>
<tr style="position: sticky; top: 0; z-index: 1000001; background: color-mix(in srgb, var(--backgroundColor) 70%, transparent);">
<th scope="col" style="text-align: center">License</th>
{% assign seen_tags = '' %}
Expand All @@ -25,9 +29,12 @@ If you're here to choose a license, **[start from the home page](/)** to see a f
{% endfor %}
{% endfor %}
</tr>
</thead>
<tbody>
{% assign licenses = site.licenses | sort: "path" %}
{% for license in licenses %}
<tr style="height: 3em"><th scope="row"><a href="{{ license.id }}">{{ license.title }}</a></th>
{% capture rule_tags %}{% for t in types %}{% for r in license[t] %}{{ r }},{% endfor %}{% endfor %}{% endcapture %}
<tr style="height: 3em" data-rules="{{ rule_tags | strip }}"><th scope="row"><a href="{{ license.url }}">{{ license.title }}</a></th>
{% assign seen_tags = '' %}
{% for type in types %}
{% assign rules = site.data.rules[type] | sort: "label" %}
Expand Down Expand Up @@ -62,7 +69,9 @@ If you're here to choose a license, **[start from the home page](/)** to see a f
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>

## Legend

Expand Down Expand Up @@ -93,3 +102,5 @@ If you're here to choose a license, **[start from the home page](/)** to see a f
{% endfor %}
</dl>
{% endfor %}

<script src="{{ '/assets/js/appendix-filter.js' | relative_url }}"></script>
52 changes: 52 additions & 0 deletions assets/js/appendix-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class AppendixFilter {
constructor(root) {
this.root = root;
this.table = document.querySelector('.appendix-table');
this.rows = Array.from(this.table?.querySelectorAll('tbody tr') || []);
this.checkboxes = Array.from(root.querySelectorAll('input[type="checkbox"]'));
this.statusEl = document.querySelector('#appendix-filter-status');
this.clearBtn = document.querySelector('#appendix-filter-clear');

this.checkboxes.forEach((cb) => cb.addEventListener('change', () => this.apply()));
this.clearBtn?.addEventListener('click', () => {
this.checkboxes.forEach((cb) => { cb.checked = false; });
this.apply();
});

this.apply();
}

selectedRules() {
return this.checkboxes.filter((cb) => cb.checked).map((cb) => cb.value);
}

rowMatches(row, rules) {
if (!rules.length) return true;
const rowTags = (row.dataset.rules || '').split(',').filter(Boolean);
return rules.every((rule) => rowTags.includes(rule));
}

apply() {
const rules = this.selectedRules();
let visible = 0;

this.rows.forEach((row) => {
const match = this.rowMatches(row, rules);
row.hidden = !match;
if (match) visible += 1;
});

if (this.statusEl) {
if (!rules.length) {
this.statusEl.textContent = `Showing all ${this.rows.length} licenses.`;
} else {
this.statusEl.textContent = `Showing ${visible} of ${this.rows.length} licenses matching ${rules.length} selected rule(s).`;
}
}
}
}

document.addEventListener('DOMContentLoaded', () => {
const root = document.querySelector('#appendix-filter');
if (root) new AppendixFilter(root);
});