mirror of https://github.com/docker/docs.git
271 lines
9.6 KiB
HTML
271 lines
9.6 KiB
HTML
{{ define "left" }}
|
|
{{- partial "sidebar/mainnav.html" . }}
|
|
<div class="navbar-font flex flex-col gap-2 p-4 text-sm">
|
|
<p>Filter guides by tag or programming language.</p>
|
|
<p></p>
|
|
<div
|
|
class="space-y-4"
|
|
x-data="{
|
|
filters: { tags: [], languages: [] },
|
|
toggleFilter(grp, tag) {
|
|
this.filters[grp].includes(tag)
|
|
? this.filters[grp] = this.filters[grp].filter(el => el != tag)
|
|
: this.filters[grp].push(tag);
|
|
|
|
// Update URL
|
|
const url = new URL(window.location.href);
|
|
if (this.filters[grp].length > 0) {
|
|
url.searchParams.set(grp, this.filters[grp].join('~'));
|
|
} else {
|
|
url.searchParams.delete(grp);
|
|
}
|
|
window.history.replaceState({}, '', url);
|
|
|
|
this.$dispatch('guide-filter', { filters: this.filters });
|
|
},
|
|
|
|
init() {
|
|
const url = new URL(window.location.href);
|
|
const tags = url.searchParams.get('tags')
|
|
const langs = url.searchParams.get('languages')
|
|
if (tags != null) {
|
|
this.filters['tags'] = tags.split('~');
|
|
}
|
|
if (langs != null) {
|
|
this.filters['languages'] = langs.split('~');
|
|
}
|
|
}
|
|
}"
|
|
@guide-filter.window="filters = $event.detail.filters;"
|
|
>
|
|
<div class="pl-2"><strong>Tags</strong></div>
|
|
<fieldset class="flex flex-col gap-2">
|
|
{{- range $name, $taxonomy := where site.Taxonomies.tags ".Page.Type" "guides" }}
|
|
{{- $id := anchorize (fmt.Printf "tag-%s" $name) }}
|
|
<div class="flex gap-2 pl-2">
|
|
<input
|
|
value="{{ $name }}"
|
|
type="checkbox"
|
|
id="{{ $id }}"
|
|
@change="toggleFilter('tags', '{{ $name }}')"
|
|
:checked="filters['tags'].includes('{{ $name }}')"
|
|
/>
|
|
<label class="select-none" for="{{ $id }}"
|
|
>{{ .Page.LinkTitle }}</label
|
|
>
|
|
</div>
|
|
{{ end }}
|
|
</fieldset>
|
|
<div class="pl-2"><strong>Languages</strong></div>
|
|
<fieldset class="flex flex-wrap gap-2 pl-2">
|
|
{{- range $name, $taxonomy := where site.Taxonomies.languages ".Page.Type" "guides" }}
|
|
{{- $id := anchorize (fmt.Printf "lang-%s" $name) }}
|
|
<button
|
|
class="border-divider-light dark:border-divider-dark flex gap-1 rounded-full border bg-white px-2 py-1 dark:bg-gray-800"
|
|
:class="{ 'ring-3-2 ring-3-blue-light-400 dark:ring-3-blue-dark-400': filters['languages'].includes('{{ $name }}') }"
|
|
@click="toggleFilter('languages', '{{ $name }}')"
|
|
>
|
|
<img
|
|
height="18"
|
|
width="18"
|
|
title="{{ .Page.LinkTitle }}"
|
|
src="{{ .Page.Params.icon }}"
|
|
/>
|
|
<span>{{ .Page.LinkTitle }}</span>
|
|
</button>
|
|
{{ end }}
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
|
|
{{ define "main" }}
|
|
<div class="flex w-full gap-8">
|
|
<article class="prose dark:prose-invert max-w-none min-w-0">
|
|
{{- partial "breadcrumbs.html" . }}
|
|
<h1 data-pagefind-weight="10" class="scroll-mt-36">{{ .Title }}</h1>
|
|
{{ .Content }}
|
|
<div
|
|
class="not-prose min-h-screen"
|
|
x-data="{
|
|
filters: { tags: [], languages: [] },
|
|
hidden: [],
|
|
total: {{ len .Pages }},
|
|
|
|
noFilters() {
|
|
return Object.values(this.filters).every(arr=> Array.isArray(arr) && arr.length === 0);
|
|
},
|
|
|
|
isVisible(el) {
|
|
return !this.hidden.includes(el.id);
|
|
},
|
|
|
|
updateVisible() {
|
|
const hiddenSet = new Set();
|
|
// show if no filters have been selected
|
|
if (this.noFilters()) {
|
|
this.hidden = [];
|
|
return;
|
|
};
|
|
const guideContainer = this.$refs['guide-container'];
|
|
const guides = guideContainer.children
|
|
|
|
// Loop over the filters object
|
|
for (const [key, value] of Object.entries(this.filters)) {
|
|
if (!value || value.length === 0) continue;
|
|
|
|
for (const g of guides) {
|
|
// Get the dataset for the current guide (e.g., languages or tags)
|
|
const terms = JSON.parse(g.dataset[key]);
|
|
|
|
// Check if any of the filter values exist in the terms
|
|
const containsSome = terms.some(term => this.filters[key].includes(term));
|
|
|
|
// If none of the terms match the filter, mark the guide as hidden
|
|
if (!containsSome) {
|
|
hiddenSet.add(g.id)
|
|
}
|
|
}
|
|
}
|
|
|
|
this.hidden = Array.from(hiddenSet)
|
|
},
|
|
|
|
init() {
|
|
const url = new URL(window.location.href);
|
|
const tags = url.searchParams.get('tags')
|
|
const langs = url.searchParams.get('languages')
|
|
if (tags != null) {
|
|
this.filters['tags'] = tags.split('~');
|
|
}
|
|
if (langs != null) {
|
|
this.filters['languages'] = langs.split('~');
|
|
}
|
|
this.updateVisible();
|
|
}
|
|
}"
|
|
x-cloak
|
|
@guide-filter.window="filters = $event.detail.filters; updateVisible(); $nextTick(() => { window.scrollTo({ top: 0 }) })"
|
|
>
|
|
<div x-show="noFilters()">
|
|
<h2>Featured guides</h2>
|
|
<div
|
|
class="not-prose grid grid-cols-1 gap-8 py-4 lg:grid-cols-2 xl:grid-cols-3"
|
|
>
|
|
{{- $featured := where .Pages "Params.featured" true }}
|
|
{{- with $featured }}
|
|
{{- range . }}
|
|
<div class="flex h-full flex-col">
|
|
<a class="hover:underline" href="{{ .Permalink }}">
|
|
{{- $img := resources.Get (.Params.image | default "/images/thumbnail.webp") }}
|
|
{{- $img = $img.Process "resize 600x" }}
|
|
<img
|
|
class="h-48 w-full rounded-sm object-cover shadow"
|
|
src="{{ $img.Permalink }}"
|
|
/>
|
|
<p class="my-4 text-xl leading-snug">{{ .Title }}</p>
|
|
</a>
|
|
<p class="flex-grow text-sm">{{ .Summary }}</p>
|
|
<div class="mt-4">
|
|
{{ template "guide-metadata" . }}
|
|
</div>
|
|
</div>
|
|
{{- end }}
|
|
{{- end }}
|
|
</div>
|
|
<hr class="text-divider-light dark:text-divider-dark" />
|
|
</div>
|
|
<h2 x-show="noFilters()" id="all-guides" class="scroll-mt-36">
|
|
All guides
|
|
</h2>
|
|
<div x-show="!noFilters()" class="flex flex-col gap-2 pb-8">
|
|
<div class="flex items-center gap-2">
|
|
<span class="icon-svg icon-sm mb-1"
|
|
>{{ partialCached "icon" "filter_alt" "filter_alt" }}</span
|
|
>
|
|
<p>
|
|
Filtered results: showing
|
|
<span x-text="total - hidden.length"></span> out of
|
|
<span x-text="total"></span> guides.
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center gap-2 pl-4">
|
|
{{- range $name, $taxonomy := site.Taxonomies.tags }}
|
|
<div x-show="filters.tags.includes('{{ $name }}')">
|
|
{{ template "termchip" $taxonomy.Page.LinkTitle }}
|
|
</div>
|
|
{{- end }}
|
|
{{- range $name, $taxonomy := site.Taxonomies.languages }}
|
|
<div
|
|
x-show="filters.languages.includes('{{ $name }}')"
|
|
class="border-divider-light dark:border-divider-dark inline-flex items-center gap-1 rounded-full border bg-gray-100 px-2 text-sm text-gray-200 select-none dark:bg-gray-800 dark:text-gray-300"
|
|
>
|
|
<img
|
|
class="py-1"
|
|
height="18"
|
|
width="18"
|
|
title="{{ .Page.LinkTitle }}"
|
|
src="{{ .Page.Params.icon }}"
|
|
/>
|
|
<span>{{ .Page.LinkTitle }}</span>
|
|
</div>
|
|
{{- end }}
|
|
</div>
|
|
</div>
|
|
<div x-ref="guide-container">
|
|
{{- range .Pages }}
|
|
<div
|
|
id="guide-{{ math.Counter }}"
|
|
data-languages="{{ jsonify (.Params.languages | default slice) }}"
|
|
data-tags="{{ jsonify (.Params.tags | default slice) }}"
|
|
x-show="isVisible($el);"
|
|
class="border-divider-light dark:border-divider-dark flex flex-col justify-between border-b p-4 hover:bg-gray-100 hover:dark:bg-gray-800"
|
|
>
|
|
<div class="flex flex-col justify-between xl:flex-row">
|
|
<a
|
|
href="{{ .Permalink }}"
|
|
class="mb-2 truncate text-lg hover:underline xl:mb-0"
|
|
>{{ .Title }}</a
|
|
>
|
|
{{ template "guide-metadata" . }}
|
|
</div>
|
|
</div>
|
|
{{- end }}
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
{{ end }}
|
|
|
|
{{- define "guide-metadata" }}
|
|
<div
|
|
class="flex items-center justify-between gap-8 text-sm text-gray-400 dark:text-gray-300"
|
|
>
|
|
<div class="flex flex-wrap gap-2 md:flex-nowrap">
|
|
{{- $langs := .GetTerms "languages" }}
|
|
{{ partial "languages" $langs }}
|
|
{{- $tags := .GetTerms "tags" }}
|
|
{{- range $tags }}
|
|
{{ template "termchip" .Page.LinkTitle }}
|
|
{{- end }}
|
|
</div>
|
|
{{- with .Params.time }}
|
|
<div class="flex flex-shrink gap-2 whitespace-nowrap">
|
|
<span class="icon-svg"
|
|
>{{ partialCached "icon" "schedule" "schedule" }}</span
|
|
>
|
|
<span>{{ . }}</span>
|
|
</div>
|
|
{{- end }}
|
|
</div>
|
|
{{- end }}
|
|
|
|
{{- define "termchip" }}
|
|
<span class="chip">
|
|
<span class="icon-svg icon-sm pb-0.5">
|
|
{{ partialCached "icon" "tag" "tag" }}
|
|
</span>
|
|
{{ . }}
|
|
</span>
|
|
{{- end }}
|