Add search

This commit is contained in:
Illya Marchenko 2024-10-30 14:24:19 +02:00
parent ae88e2e4c9
commit e4c712d5ad
Signed by: stuzer05
GPG Key ID: A6ABAAA9268F9F4F
2 changed files with 78 additions and 19 deletions

@ -2,32 +2,42 @@
<header class="flex justify-between mx-2 mt-1"> <header class="flex justify-between mx-2 mt-1">
<span class="font-bold">Tools</span> <span class="font-bold">Tools</span>
<router-link :to="{ name: 'home' }" class="ml-4" tag="button" <router-link :to="{ name: 'home' }" class="ml-4" tag="button"
>Home</router-link >Home</router-link
> >
</header> </header>
<hr class="mt-2 mb-2" /> <hr class="mt-2 mb-2" />
<div class="mx-2">
<input
type="text"
v-model="searchQuery"
placeholder="Search.."
class="mb-4 border w-full"
/>
</div>
<nav class="flex flex-col ml-2"> <nav class="flex flex-col ml-2">
<div <div
v-for="[title, routes] of Object.entries(menuRoutes).sort((a, b) => v-for="[title, routes] of filteredMenuRoutes"
a[0].localeCompare(b[0]) :key="title"
)"
class="flex flex-col mb-2" class="flex flex-col mb-2"
v-show="Object.keys(routes).length > 0"
> >
<p> <p>
<i>{{ title }}</i> <i>{{ title }}</i>
</p> </p>
<router-link <router-link
v-for="[key, value] of Object.entries(routes)" v-for="[key, value] of Object.entries(routes)"
:key="key"
:to="{ name: key }" :to="{ name: key }"
class="ml-4" class="ml-4"
tag="button" tag="button"
>{{ value }}</router-link >{{ value }}</router-link
> >
</div> </div>
<hr class="mt-3 mb-3" /> <hr class="mt-3 mb-3" v-show="filteredMenuRoutes.length > 0" />
<div class="flex flex-col mb-2"> <div class="flex flex-col mb-2">
<p><i>Other</i></p> <p><i>Other</i></p>
@ -35,10 +45,10 @@
href="https://gist.stuzer.link/stuzer05/liked" href="https://gist.stuzer.link/stuzer05/liked"
class="ml-4" class="ml-4"
tag="button" tag="button"
>Gist</a >Gist</a
> >
<a href="https://pdf.stuzer.link/" class="ml-4" tag="button" <a href="https://pdf.stuzer.link/" class="ml-4" tag="button"
>PDF tools</a >PDF tools</a
> >
</div> </div>
</nav> </nav>
@ -46,17 +56,37 @@
<script> <script>
import { useToolsStore } from "@/stores/toolsStore"; import { useToolsStore } from "@/stores/toolsStore";
import { ref, computed } from 'vue';
export default { export default {
name: "Sidebar", name: "Sidebar",
components: {}, components: {},
data() { setup() {
const toolsStore = useToolsStore();
const searchQuery = ref('');
const filteredMenuRoutes = computed(() => {
const query = searchQuery.value.toLowerCase();
if (query) {
return Object.entries(toolsStore.tools)
.map(([categoryName, routes]) => [
categoryName,
Object.fromEntries(
Object.entries(routes).filter(
([_, routeName]) => routeName.toLowerCase().includes(query)
)
),
])
.filter(([categoryName, routes]) => Object.keys(routes).length > 0);
} else {
return Object.entries(toolsStore.tools);
}
});
return { return {
menuRoutes: {}, searchQuery,
filteredMenuRoutes,
}; };
}, },
mounted() {
this.menuRoutes = useToolsStore().tools;
},
}; };
</script> </script>

@ -1,12 +1,20 @@
<template> <template>
<div class="container mx-auto p-4"> <div class="container mx-auto p-4">
<input
type="text"
v-model="searchQuery"
placeholder="Search.."
class="mb-4 border w-full"
/>
<div <div
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-5" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-5"
> >
<div <div
v-for="(category, categoryName) in tools" v-for="(category, categoryName) in filteredTools"
:key="categoryName" :key="categoryName"
class="bg-white rounded-lg shadow-md p-4" class="bg-white shadow-md p-4"
v-show="Object.keys(category).length > 0"
> >
<h2 class="text-xl font-semibold mb-3">{{ categoryName }}</h2> <h2 class="text-xl font-semibold mb-3">{{ categoryName }}</h2>
<div class="max-h-80 overflow-y-auto"> <div class="max-h-80 overflow-y-auto">
@ -31,7 +39,7 @@
<div class="flex flex-wrap justify-center items-center gap-4 max-w-4xl"> <div class="flex flex-wrap justify-center items-center gap-4 max-w-4xl">
<a <a
href="https://gist.stuzer.link/stuzer05/liked" href="https://gist.stuzer.link/stuzer05/liked"
class="flex items-center w-64 p-4 bg-white rounded-lg shadow-md hover:bg-gray-50 transition-colors duration-300" class="flex items-center w-64 p-4 bg-white shadow-md hover:bg-gray-50 transition-colors duration-300"
> >
<img <img
src="https://gist.stuzer.link/assets/opengist-85b89b9c.svg" src="https://gist.stuzer.link/assets/opengist-85b89b9c.svg"
@ -43,7 +51,7 @@
<a <a
href="https://pdf.stuzer.link/" href="https://pdf.stuzer.link/"
class="flex items-center w-64 p-4 bg-white rounded-lg shadow-md hover:bg-gray-50 transition-colors duration-300" class="flex items-center w-64 p-4 bg-white shadow-md hover:bg-gray-50 transition-colors duration-300"
> >
<img <img
src="https://pdf.stuzer.link/favicon.svg" src="https://pdf.stuzer.link/favicon.svg"
@ -59,11 +67,13 @@
<script> <script>
import { useToolsStore } from "@/stores/toolsStore"; import { useToolsStore } from "@/stores/toolsStore";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { computed, ref } from 'vue';
export default { export default {
data() { data() {
return { return {
tools: {}, tools: {},
searchQuery: ref(''),
}; };
}, },
setup() { setup() {
@ -78,7 +88,26 @@ export default {
mounted() { mounted() {
this.tools = useToolsStore().tools; this.tools = useToolsStore().tools;
}, },
computed: {
filteredTools() {
const query = this.searchQuery.toLowerCase();
if (query) {
return Object.fromEntries(
Object.entries(this.tools).map(([categoryName, tools]) => [
categoryName,
Object.fromEntries(
Object.entries(tools).filter(
([_, toolName]) => toolName.toLowerCase().includes(query)
)
),
])
);
} else {
return this.tools;
}
},
},
}; };
</script> </script>
<style lang="scss"></style> <style lang="scss"></style>