opnform-host-nginx/client/components/pages/templates/TemplatesList.vue

275 lines
7.2 KiB
Vue
Raw Normal View History

2023-12-09 15:47:03 +01:00
<template>
<div>
<section class="bg-white py-12">
<div class="px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
<div
class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 sm:gap-6 relative z-20"
>
2023-12-09 15:47:03 +01:00
<div class="flex items-center gap-4">
<div class="flex-1 sm:flex-none">
<select-input
v-if="filterTypes"
v-model="selectedType"
name="type"
:options="typesOptions"
class="w-full sm:w-auto md:w-56"
2023-12-09 15:47:03 +01:00
/>
</div>
<div class="flex-1 sm:flex-none">
<select-input
v-if="filterIndustries"
v-model="selectedIndustry"
name="industry"
:options="industriesOptions"
class="w-full sm:w-auto md:w-56"
2023-12-09 15:47:03 +01:00
/>
</div>
</div>
<div class="flex-1 w-full md:max-w-xs">
<text-input
v-model="search"
autocomplete="off"
name="search"
placeholder="Search..."
/>
2023-12-09 15:47:03 +01:00
</div>
</div>
<div
v-if="loading"
class="text-center mt-4"
>
<Loader class="h-6 w-6 text-nt-blue mx-auto" />
2023-12-09 15:47:03 +01:00
</div>
<p
v-else-if="enrichedTemplates.length === 0"
class="text-center mt-4"
>
2023-12-09 15:47:03 +01:00
No templates found.
</p>
<div
v-else
class="relative z-10"
>
<div
class="grid grid-cols-1 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8 sm:gap-y-12"
>
<single-template
v-for="template in enrichedTemplates"
:key="template.id"
:template="template"
/>
2023-12-09 15:47:03 +01:00
</div>
</div>
</div>
</section>
<slot name="before-lists" />
2023-12-09 15:47:03 +01:00
<section
v-if="showTypes"
class="py-12 bg-white border-t border-gray-200 sm:py-16"
>
2023-12-18 10:35:00 +01:00
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="flex items-center justify-between">
<h4
class="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl"
>
2023-12-18 10:35:00 +01:00
All Types
</h4>
<v-button
v-if="$route.name !== 'templates'"
:to="{ name: 'templates' }"
color="white"
size="small"
:arrow="true"
>
2023-12-19 17:10:07 +01:00
View All Templates
</v-button>
2023-12-09 15:47:03 +01:00
</div>
<div
class="grid grid-cols-1 gap-x-8 gap-y-4 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<NuxtLink
v-for="row in types"
:key="row.slug"
:to="{ params: { slug: row.slug }, name: 'templates-types-slug' }"
:title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
2023-12-18 10:35:00 +01:00
>
{{ row.name }}
</NuxtLink>
2023-12-09 15:47:03 +01:00
</div>
2023-12-18 10:35:00 +01:00
</div>
</section>
<section
v-if="showIndustries"
class="py-12 bg-white border-t border-gray-200 sm:py-16"
>
2023-12-18 10:35:00 +01:00
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<div class="flex items-center justify-between">
<h4
class="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl"
>
2023-12-18 10:35:00 +01:00
All Industries
</h4>
<v-button
v-if="$route.name !== 'templates'"
:to="{ name: 'templates' }"
color="white"
size="small"
:arrow="true"
>
2023-12-19 17:10:07 +01:00
View All Templates
</v-button>
2023-12-18 10:35:00 +01:00
</div>
<div
class="grid grid-cols-1 gap-x-8 gap-y-4 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<NuxtLink
v-for="row in industries"
:key="row.slug"
:to="{
params: { slug: row.slug },
name: 'templates-industries-slug',
}"
:title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
2023-12-18 10:35:00 +01:00
>
{{ row.name }}
</NuxtLink>
2023-12-18 10:35:00 +01:00
</div>
</div>
</section>
2023-12-09 15:47:03 +01:00
</div>
</template>
<script>
import { computed } from "vue"
import Fuse from "fuse.js"
import SingleTemplate from "./SingleTemplate.vue"
import { refDebounced } from "@vueuse/core"
2023-12-09 15:47:03 +01:00
export default {
name: "TemplatesList",
components: { SingleTemplate },
2023-12-09 15:47:03 +01:00
props: {
2023-12-18 10:35:00 +01:00
templates: {
type: Array,
required: true,
2023-12-18 10:35:00 +01:00
},
loading: {
2023-12-09 15:47:03 +01:00
type: Boolean,
default: false,
2023-12-19 17:10:07 +01:00
},
showTypes: {
type: Boolean,
default: true,
2023-12-19 17:10:07 +01:00
},
filterTypes: {
type: Boolean,
default: true,
2023-12-19 17:10:07 +01:00
},
showIndustries: {
type: Boolean,
default: true,
2023-12-19 17:10:07 +01:00
},
filterIndustries: {
type: Boolean,
default: true,
},
2023-12-09 15:47:03 +01:00
},
2023-12-18 10:35:00 +01:00
setup() {
2023-12-09 15:47:03 +01:00
const authStore = useAuthStore()
const templatesStore = useTemplatesStore()
const search = ref("")
2023-12-19 16:45:23 +01:00
const debouncedSearch = refDebounced(search, 500)
2023-12-09 15:47:03 +01:00
return {
2023-12-19 15:24:54 +01:00
search,
2023-12-19 16:45:23 +01:00
debouncedSearch,
2023-12-18 10:35:00 +01:00
user: computed(() => authStore.user),
2023-12-19 15:24:54 +01:00
industries: computed(() => [...templatesStore.industries.values()]),
types: computed(() => [...templatesStore.types.values()]),
2023-12-09 15:47:03 +01:00
}
},
data: () => ({
selectedType: "all",
selectedIndustry: "all",
2023-12-09 15:47:03 +01:00
}),
computed: {
2023-12-18 10:35:00 +01:00
industriesOptions() {
return [{ name: "All Industries", value: "all" }].concat(
Object.values(this.industries).map((industry) => {
return {
name: industry.name,
value: industry.slug,
}
}),
)
2023-12-09 15:47:03 +01:00
},
2023-12-18 10:35:00 +01:00
typesOptions() {
return [{ name: "All Types", value: "all" }].concat(
Object.values(this.types).map((type) => {
return {
name: type.name,
value: type.slug,
}
}),
)
2023-12-09 15:47:03 +01:00
},
2023-12-18 10:35:00 +01:00
enrichedTemplates() {
let enrichedTemplates = this.templates
2023-12-09 15:47:03 +01:00
// Filter by Selected Type
if (
this.filterTypes &&
this.selectedType &&
this.selectedType !== "all"
) {
2023-12-09 15:47:03 +01:00
enrichedTemplates = enrichedTemplates.filter((item) => {
return item.types && item.types.length > 0
? item.types.includes(this.selectedType)
: false
2023-12-09 15:47:03 +01:00
})
}
// Filter by Selected Industry
if (
this.filterIndustries &&
this.selectedIndustry &&
this.selectedIndustry !== "all"
) {
2023-12-09 15:47:03 +01:00
enrichedTemplates = enrichedTemplates.filter((item) => {
return item.industries && item.industries.length > 0
? item.industries.includes(this.selectedIndustry)
: false
2023-12-09 15:47:03 +01:00
})
}
if (
!this.debouncedSearch ||
this.debouncedSearch === "" ||
this.debouncedSearch === null
) {
2023-12-09 15:47:03 +01:00
return enrichedTemplates
}
// Fuze search
const fuzeOptions = {
keys: ["name", "slug", "description", "short_description"],
2023-12-09 15:47:03 +01:00
}
const fuse = new Fuse(enrichedTemplates, fuzeOptions)
2023-12-19 16:45:23 +01:00
return fuse.search(this.debouncedSearch).map((res) => {
2023-12-09 15:47:03 +01:00
return res.item
})
},
2023-12-09 15:47:03 +01:00
},
}
</script>