mirror of https://github.com/jdx/mise
147 lines
3.2 KiB
Vue
147 lines
3.2 KiB
Vue
<template>
|
|
<input
|
|
class="filter"
|
|
type="text"
|
|
placeholder="Filter by Short or Full"
|
|
v-model="filter"
|
|
autofocus="autofocus"
|
|
/>
|
|
<table class="full-width">
|
|
<thead>
|
|
<tr>
|
|
<th>Short</th>
|
|
<th>Full</th>
|
|
<th>OS</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-if="filteredData.length === 0">
|
|
<td colspan="3" class="no-matches">No matches found</td>
|
|
</tr>
|
|
<tr
|
|
v-else
|
|
v-for="(entry, index) in filteredData"
|
|
:key="`backend-${index}`"
|
|
>
|
|
<td v-html="highlightMatches(entry.short)"></td>
|
|
<td>
|
|
<span v-for="(backend, index) in entry.backends">
|
|
<a
|
|
:href="`${backend.url}`"
|
|
v-html="highlightMatches(backend.name)"
|
|
></a>
|
|
<span v-if="index < entry.backends.length - 1"><br /></span>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span v-for="(os, index) in entry.os"
|
|
>{{ os }}<span v-if="index < entry.os.length - 1">, </span>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</template>
|
|
|
|
<script>
|
|
import { data } from "/registry.data.ts";
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
filter:
|
|
new URLSearchParams(globalThis?.location?.search).get("filter") || "",
|
|
data: data,
|
|
};
|
|
},
|
|
computed: {
|
|
filteredData() {
|
|
if (this.filter.trim() === "") return this.data;
|
|
return this.data.filter((entry) => {
|
|
const searchTerm = this.filter.toLowerCase();
|
|
const short = entry.short.toString().toLowerCase();
|
|
|
|
return (
|
|
short.includes(searchTerm) ||
|
|
entry.backends.some((b) => b.name.toLowerCase().includes(searchTerm))
|
|
);
|
|
});
|
|
},
|
|
},
|
|
watch: {
|
|
filter(newFilter = "") {
|
|
const url = new URL(window.location);
|
|
url.hash = "tools";
|
|
if (newFilter.trim() === "") {
|
|
url.searchParams.delete("filter");
|
|
} else {
|
|
url.searchParams.set("filter", newFilter);
|
|
}
|
|
window.history.pushState({}, "", url);
|
|
},
|
|
},
|
|
methods: {
|
|
highlightMatches(text) {
|
|
if (this.filter.trim() === "") return text;
|
|
const matchExists = text
|
|
.toLowerCase()
|
|
.includes(this.filter.toLowerCase());
|
|
if (!matchExists) return text;
|
|
|
|
const re = new RegExp(this.filter, "ig");
|
|
return text.replace(
|
|
re,
|
|
(matchedText) =>
|
|
`<span style="background-color: rgba(173, 216, 230, 0.2)">${matchedText}</span>`,
|
|
);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.filter {
|
|
width: 100%;
|
|
padding: 10px;
|
|
margin-bottom: 10px;
|
|
border-radius: 10px;
|
|
background: var(--vp-c-bg-soft);
|
|
font-size: 15px;
|
|
color: var(--vp-c-text-2);
|
|
}
|
|
|
|
.full-width {
|
|
width: 100%;
|
|
table-layout: fixed;
|
|
min-height: 500px;
|
|
}
|
|
|
|
.full-width th:nth-child(1),
|
|
.full-width td:nth-child(1) {
|
|
min-width: 40%;
|
|
width: 50%;
|
|
}
|
|
|
|
.full-width th:nth-child(2),
|
|
.full-width td:nth-child(2) {
|
|
min-width: 40%;
|
|
width: 50%;
|
|
}
|
|
|
|
.full-width th:nth-child(3),
|
|
.full-width td:nth-child(3) {
|
|
min-width: 20%;
|
|
}
|
|
|
|
.full-width th,
|
|
.full-width td {
|
|
word-wrap: break-word; /* Allows text to wrap within cells */
|
|
}
|
|
|
|
.no-matches {
|
|
text-align: center;
|
|
font-style: italic;
|
|
color: var(--vp-c-text-2);
|
|
}
|
|
</style>
|