Personal blog finxol.io
blog

feat: add basic post filtering by tags

finxol.io 50917f53 12c00240

verified
+54 -8
+54 -8
app/pages/index.vue
··· 21 21 const posts = data.value ? data.value[0]?.children : []; 22 22 23 23 defineOgImageComponent("Page", { 24 - description: `This is ${config.title}. Read all ${posts?.length || 0} posts published so far, but stay tuned for more!` 24 + description: `This is ${config.title}. Read all ${posts?.length || 0} posts published so far, and stay tuned for more!` 25 + }); 26 + 27 + const tags = 28 + posts?.reduce((acc, post) => { 29 + for (const tag of post.tags as string[]) { 30 + if (!acc.includes(tag)) { 31 + acc.push(tag); 32 + } 33 + } 34 + return acc; 35 + }, [] as string[]) ?? []; 36 + 37 + const filter = ref<string | undefined>(undefined); 38 + 39 + const filteredPosts = computed(() => { 40 + if (!filter.value) return posts; 41 + return posts?.filter( 42 + (post) => 43 + post.tags && (post.tags as string[]).includes(filter.value ?? "") 44 + ); 25 45 }); 26 46 </script> 27 47 ··· 33 53 34 54 Change this content by editing the file <code>content/index.md</code>. 35 55 </p> 56 + </header> 36 57 37 - <h2 class="text-2xl font-bold my-6"> 38 - Posts 39 - </h2> 40 - </header> 58 + <h2 class="text-2xl font-bold my-6"> 59 + Posts 60 + </h2> 61 + 62 + <section class="my-6"> 63 + <p> 64 + Filter posts: 65 + </p> 66 + <div class="w-full overflow-x-scroll flex flex-row items-start"> 67 + <button 68 + v-for="tag in tags" 69 + :key="tag" 70 + :class="[ 71 + 'flex px-2 py-1 mr-2 mb-2 w-max flex-row items-center gap-2', 72 + `${tag === filter ? 'bg-gray-500 dark:bg-gray-500 text-gray-100 dark:text-gray-100' : 'bg-gray-200 dark:bg-gray-800 text-gray-800 dark:text-gray-200'}`, 73 + 'rounded-full text-sm font-medium lowercase' 74 + ]" 75 + @click="filter = filter === tag ? undefined : tag" 76 + > 77 + <Icon 78 + v-if="tag === filter" 79 + name="ri:close-line" 80 + size="1rem" 81 + mode="svg" 82 + /> 83 + {{ tag }} 84 + </button> 85 + </div> 86 + </section> 41 87 42 88 <PostPreviewAccent 43 - v-if="posts" 44 - :post="posts[0]" 89 + v-if="filteredPosts" 90 + :post="filteredPosts[0]" 45 91 /> 46 92 47 93 <div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mt-4 mb-8"> 48 94 <PostPreview 49 - v-for="post in posts?.slice(1)" 95 + v-for="post in filteredPosts?.slice(1)" 50 96 :key="post.path" 51 97 :post="post" 52 98 />