Skip to content

Commit

Permalink
feat: add global search and blogs/resource search
Browse files Browse the repository at this point in the history
  • Loading branch information
ktx-kirtan committed Nov 11, 2024
1 parent e0d8048 commit 5dec25a
Show file tree
Hide file tree
Showing 11 changed files with 739 additions and 283 deletions.
4 changes: 2 additions & 2 deletions blog/components/blog/blog-list.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<div>
<div v-for="(article, index) in articles" :key="index" class="mb-10">
<div class="px-2 py-2 bg-white rounded-lg transition-all duration-200">
<div class="py-2 bg-white rounded-lg transition-all duration-200">
<div class="flex flex-col md:flex-row items-stretch">
<div style="flex: 2" class="px-4 py-2">
<div style="flex: 2" class="">
<div class="">
<nuxt-link
:to="`/${type}/${article?.slug}`"
Expand Down
130 changes: 41 additions & 89 deletions blog/components/blog/blog-sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
<template>
<div class="-mx-8 w-3/12 hidden lg:block">
<div class="w-3/12 hidden lg:block">
<div class="mt-10 px-8">
<h4 class="mb-4 text-xl font-medium text-gray-700">Recent Posts</h4>
<div class="max-w-sm mx-auto">
<div
v-for="(article, index) in recentArticles"
:key="index"
class="flex flex-col py-2 mb-5"
>
<div class="">
<nuxt-link
:to="`/${type}/${article.slug}`"
class="
text-base text-gray-700
font-normal
hover:text-theme-primary
transition-all
duration-150
"
>
{{ article.title }}
</nuxt-link>
</div>
<div class="flex justify-between items-center mt-4">
<div class="flex items-center">
<nuxt-link
:to="`/${type}/author/${article.authors?.[0]}`"
class="text-gray-700 text-sm font-light mr-3 hover:underline"
>
{{ authors?.find((a) => a.slug == article?.authors?.[0])?.name }}
{{ article.authors?.length > 1 ? (" (+" + (article.authors.length - 1 )+ ")") : "" }}
</nuxt-link>
</div>
<span class="font-light text-sm text-gray-600">
{{ formatDate(article.publishDate) }}
</span>
</div>
</div>
</div>
</div>
<div class="">
<div v-if="false" class="mt-1 px-8">
<h4 class="mb-4 text-xl font-medium text-gray-700">Categories</h4>
Expand Down Expand Up @@ -99,94 +138,7 @@
</ul>
</div>
</div>
<!-- <div class="mt-10 px-8">
<h4 class="mb-4 text-xl font-medium text-gray-700">Archives</h4>
<div
class="
flex flex-col
bg-white
max-w-sm
mx-auto
rounded-lg
"
>
<select
v-model="dataVariables.selectedMonth"
name="archiveMonths"
id="archiveMonths"
class="py-2 mb-2 border rounded px-2"
>
<option disabled value="">Select</option>
<option
v-for="(month, index) in archiveMonths"
:key="index"
:value="month"
>
{{ formatMonth(month) }}
</option>
</select>
<ul>
<li
v-for="(article, index) in currentSelectedMonthArticles"
:key="index"
class="mb-2"
>
<nuxt-link
:to="'/blog/' + article.slug"
class="text-gray-700 font-normal"
>
<div class="flex flex-row">
<div>&gt;&nbsp;&nbsp;</div>
<div
class="hover:text-theme-primary transition-all duration-200"
>
{{ article.title }}
</div>
</div>
</nuxt-link>
</li>
</ul>
</div>
</div> -->
<div class="mt-10 px-8">
<h4 class="mb-4 text-xl font-medium text-gray-700">Recent Posts</h4>
<div class="max-w-sm mx-auto">
<div
v-for="(article, index) in recentArticles"
:key="index"
class="flex flex-col py-2 mb-5"
>
<div class="">
<nuxt-link
:to="`/${type}/${article.slug}`"
class="
text-base text-gray-700
font-normal
hover:text-theme-primary
transition-all
duration-150
"
>
{{ article.title }}
</nuxt-link>
</div>
<div class="flex justify-between items-center mt-4">
<div class="flex items-center">
<nuxt-link
:to="`/${type}/author/${article.authors?.[0]}`"
class="text-gray-700 text-sm font-light mr-3 hover:underline"
>
{{ authors?.find((a) => a.slug == article?.authors?.[0])?.name }}
{{ article.authors?.length > 1 ? (" (+" + (article.authors.length - 1 )+ ")") : "" }}
</nuxt-link>
</div>
<span class="font-light text-sm text-gray-600">
{{ formatDate(article.publishDate) }}
</span>
</div>
</div>
</div>
</div>

</div>
</div>
</template>
Expand Down
138 changes: 118 additions & 20 deletions blog/pages/[type]/page/[page].vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,69 @@
<template>
<div class="overflow-x-hidden">
<BreadCrumbs class="md:pt-0 pt-3" :title="getLabelFromType(type)" :paths="[{ name: 'Home', to: '/' }, { name: getLabelFromType(type) }]"/>

<div class="md:px-14 px-5 py-8">
<div class="flex justify-between container mx-auto">
<BreadCrumbs
class="md:pt-0 pt-3"
:title="getLabelFromType(type)"
:paths="[{ name: 'Home', to: '/' }, { name: getLabelFromType(type) }]"
/>

<div class="md:px-14 px-4 py-8">
<div class="flex container mx-auto">
<div class="w-full lg:w-9/12">
<div class="flex items-center justify-between"></div>
<!-- Search input field -->
<div
class="search-container flex items-start w-full max-w-md"
>
<div class="relative w-full">
<!-- Search Icon -->
<svg
class="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 pointer-events-none"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M9.539 15.23q-2.398 0-4.065-1.666Q3.808 11.899 3.808 9.5t1.666-4.065T9.539 3.77t4.064 1.666T15.269 9.5q0 1.042-.369 2.017t-.97 1.668l5.909 5.907q.14.14.15.345q.009.203-.15.363q-.16.16-.354.16t-.354-.16l-5.908-5.908q-.75.639-1.725.989t-1.96.35m0-1q1.99 0 3.361-1.37q1.37-1.37 1.37-3.361T12.9 6.14T9.54 4.77q-1.991 0-3.361 1.37T4.808 9.5t1.37 3.36t3.36 1.37"
/>
</svg>
<input
id="search"
v-model="searchQuery"
type="text"
:placeholder="placeholderText"
class="w-full pl-10 pr-12 py-3 rounded-lg bg-gray-50 border border-gray-300 focus:ring-2 focus:ring-blue-400 focus:outline-none text-gray-700 transition-all duration-200"
/>
</div>
</div>

<div
v-if="searchQuery && filteredResults.length === 0"
class="no-data-found text-gray-600 mt-4"
>
No articles found matching
<span class="font-semibold">{{ searchQuery }}</span>
</div>
<div
v-if="searchQuery && filteredResults.length > 0"
class="no-data-found text-gray-600 mt-4"
>
Search results for
<span class="font-semibold">{{ searchQuery }}</span>
</div>
<!-- Blog list with filtered articles -->
<blog-list
:articles="articles"
class="mt-2"
:articles="searchQuery ? filteredResults : articles"
:authors="authors"
:categories="categories"
:searchQuery="searchQuery"
:tags="tags"
:type="type"
/>
<div class="mt-8">

<!-- Conditionally render pagination if searchQuery is not active -->
<div v-if="!searchQuery && totalArticles > 0" class="mt-8">
<blog-pagination
:currentPage="currentPage"
:total="totalArticles"
Expand All @@ -22,52 +72,81 @@
/>
</div>
</div>
<blog-sidebar :type="type"/>
<blog-sidebar :type="type" />
</div>
</div>
</div>
</template>

<script setup>
import { getLabelFromType } from '~/blog/utils/typeUtils';
import { ref, computed, watch } from "vue";
import { getLabelFromType } from "~/blog/utils/typeUtils";
import { debounce } from "lodash-es";
const route = useRoute();
const router = useRouter();
const type = route.params.type;
// Define page metadata
definePageMeta({
middleware: (to, from) => {
if (to.params.page == 1) {
return navigateTo(`/${to.params.type}`, { redirectCode: 301 })
return navigateTo(`/${to.params.type}`, { redirectCode: 301 });
}
},
});
const nuxtApp = useNuxtApp();
// Fetch articles
const { data: articlesTemp } = await useAsyncData(
"get-articles-" + JSON.stringify(route.params),
() => getArticles(route.params, {}, nuxtApp)
);
const { articles, totalArticles, lastPage, currentPage } = articlesTemp.value;
// Fetch authors
const { data: authorsTemp } = await useAsyncData(() =>
queryContent(`/${getContentFolder(type)}/authors`).findOne()
);
const authors = authorsTemp?.value.authors;
// get categories
let { data: categories } = await useAsyncData(`${type}-categories`,() => getCategories(type));
// Fetch categories and tags
let { data: categories } = await useAsyncData(`${type}-categories`, () =>
getCategories(type)
);
let { data: tags } = await useAsyncData(`${type}-tags`, () => getTags(type));
// Search query for filtering
const searchQuery = ref("");
const loading = ref(false);
const filteredResults = ref([]);
// get tags
let { data: tags } = await useAsyncData(`${type}-tags`,() => getTags(type));
const { data: allArticles } = await useAsyncData(() =>
queryContent(`/${getContentFolder(type)}/posts`).find()
);
// Filtered articles based on search query
const debouncedSearch = async () => {
loading.value = true;
let { data: recentArticles } = await useAsyncData(`${type}-recent-articles`,() => getRecentArticles(type));
// Apply filter directly to the articles array
if (searchQuery.value) {
filteredResults.value = articles.filter((article) =>
article.title.toLowerCase().includes(searchQuery.value.toLowerCase())
);
} else {
filteredResults.value = []; // Reset when the search is cleared
}
loading.value = false;
}
watch(searchQuery, debouncedSearch);
// Fetch recent articles
let { data: recentArticles } = await useAsyncData(
`${type}-recent-articles`,
() => getRecentArticles(type)
);
useHead({
title: getLabelFromType(type),
Expand All @@ -78,6 +157,25 @@ useHead({
},
],
});
let placeholderText = "Search for a " + getLabelFromType(type) + "...";
</script>
<style></style>
<style>
/* Add custom styles for the loader if needed */
.loader {
border: 2px solid transparent;
border-top: 2px solid #3498db;
border-radius: 50%;
width: 16px;
height: 16px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
Loading

0 comments on commit 5dec25a

Please sign in to comment.