Finishing the templates pages

This commit is contained in:
Julien Nahum 2023-12-19 15:24:54 +01:00
parent bb519907f6
commit 8e70d6be98
10 changed files with 295 additions and 352 deletions

View File

@ -1,51 +1,48 @@
<template> <template>
<div v-if="template"> <div>
<!-- <template v-if="displayAll">--> <template v-if="displayAll">
<!-- <span v-if="template.is_new"--> <span v-if="template.is_new"
<!-- class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-blue-500 rounded-full"--> class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-blue-500 rounded-full"
<!-- >--> >
<!-- <svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"--> <svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
<!-- fill="currentColor"--> fill="currentColor"
<!-- >--> >
<!-- <path fill-rule="evenodd"--> <path fill-rule="evenodd"
<!-- d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"--> d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"
<!-- clip-rule="evenodd"--> clip-rule="evenodd"
<!-- />--> />
<!-- </svg>--> </svg>
<!-- New--> New
<!-- </span>--> </span>
<!-- <span v-for="item in types"--> <span v-for="item in types" :key="item.slug"
<!-- class="inline-flex items-center rounded-full bg-gray-50 dark:bg-gray-800 dark:text-gray-400 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"--> class="inline-flex items-center rounded-full bg-gray-50 dark:bg-gray-800 dark:text-gray-400 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
<!-- >--> >
<!-- {{ item }}--> {{ item.name }}
<!-- </span>--> </span>
<!-- <span v-for="item in industries"--> <span v-for="item in industries" :key="item.slug"
<!-- class="inline-flex items-center rounded-full bg-blue-50 dark:bg-blue-900 dark:text-gray-400 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"--> class="inline-flex items-center rounded-full bg-blue-50 dark:bg-blue-900 dark:text-gray-400 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
<!-- >--> >
<!-- {{ item }}--> {{ item.name }}
<!-- </span>--> </span>
<!-- </template>--> </template>
<!-- <template v-else>--> <template v-else>
<!-- <span v-if="types.length > 0"--> <span v-if="types.length > 0"
<!-- class="inline-flex items-center rounded-full bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"--> class="inline-flex items-center rounded-full bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
<!-- >--> >
<!-- {{ types[0] }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>--> {{ types[0].name }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>
<!-- </span>--> </span>
<!-- <span v-if="industries.length > 0"--> <span v-if="industries.length > 0"
<!-- class="inline-flex items-center rounded-full bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"--> class="inline-flex items-center rounded-full bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
<!-- >--> >
<!-- {{ industries[0] }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>--> {{ industries[0].name }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>
<!-- </span>--> </span>
<!-- </template>--> </template>
</div> </div>
</template> </template>
<script> <script setup>
import { computed } from 'vue'
import { useTemplatesStore } from '../../../stores/templates'
export default { const props = defineProps({
props: {
template: { template: {
type: Object, type: Object,
required: true required: true
@ -54,31 +51,9 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
} }
}, })
setup () {
const templatesStore = useTemplatesStore() const templatesStore = useTemplatesStore()
return { const types = computed(() => templatesStore.getTemplateTypes(props.template.types))
templatesStore const industries = computed(() => templatesStore.getTemplateIndustries(props.template.industries))
}
},
data: () => ({}),
computed: {
// template () {
// return this.templatesStore.getByKey(this.slug)
// },
// types () {
// if (!this.template) return null
// return this.templatesStore.getTemplateTypes(this.template.types)
// },
// industries () {
// if (!this.template) return null
// return this.templatesStore.getTemplateIndustries(this.template.industries)
// }
},
methods: {}
}
</script> </script>

View File

@ -16,7 +16,7 @@
</div> </div>
</div> </div>
<div class="flex-1 w-full md:max-w-xs"> <div class="flex-1 w-full md:max-w-xs">
<text-input autocomplete="off" name="search" :form="searchTemplate" placeholder="Search..."/> <text-input autocomplete="off" name="search" v-model="search" placeholder="Search..."/>
</div> </div>
</div> </div>
@ -45,7 +45,7 @@
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<router-link v-for="row in types" :key="row.slug" <router-link v-for="row in types" :key="row.slug"
:to="{params:{slug:row.slug}, name:'templates-types'}" :to="{params: {slug:row.slug}, name:'templates-types-slug'}"
:title="row.name" :title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue" class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
> >
@ -65,7 +65,7 @@
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<router-link v-for="row in industries" :key="row.slug" <router-link v-for="row in industries" :key="row.slug"
:to="{params:{slug:row.slug}, name:'templates-industries'}" :to="{params:{slug:row.slug}, name:'templates-industries-slug'}"
:title="row.name" :title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue" class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
> >
@ -79,9 +79,9 @@
<script> <script>
import {computed} from 'vue' import {computed} from 'vue'
import Form from 'vform'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import SingleTemplate from './SingleTemplate.vue' import SingleTemplate from './SingleTemplate.vue'
import {refThrottled} from "@vueuse/core";
export default { export default {
name: 'TemplatesList', name: 'TemplatesList',
@ -100,23 +100,22 @@ export default {
setup() { setup() {
const authStore = useAuthStore() const authStore = useAuthStore()
const templatesStore = useTemplatesStore() const templatesStore = useTemplatesStore()
const search = ref('')
const throttledSearch = refThrottled(search, 1000)
return { return {
search,
throttledSearch,
user: computed(() => authStore.user), user: computed(() => authStore.user),
industries: computed(() => templatesStore.industries), industries: computed(() => [...templatesStore.industries.values()]),
types: computed(() => templatesStore.types) types: computed(() => [...templatesStore.types.values()])
} }
}, },
data: () => ({ data: () => ({
selectedType: 'all', selectedType: 'all',
selectedIndustry: 'all', selectedIndustry: 'all',
searchTemplate: new Form({
search: ''
})
}), }),
watch: {},
computed: { computed: {
industriesOptions() { industriesOptions() {
return [{name: 'All Industries', value: 'all'}].concat(Object.values(this.industries).map((industry) => { return [{name: 'All Industries', value: 'all'}].concat(Object.values(this.industries).map((industry) => {
@ -151,7 +150,8 @@ export default {
}) })
} }
if (this.searchTemplate.search === '' || this.searchTemplate.search === null) { console.log(this.throttledSearch, '---inode')
if (!this.throttledSearch || this.throttledSearch === '' || this.throttledSearch === null) {
return enrichedTemplates return enrichedTemplates
} }
@ -165,7 +165,7 @@ export default {
] ]
} }
const fuse = new Fuse(enrichedTemplates, fuzeOptions) const fuse = new Fuse(enrichedTemplates, fuzeOptions)
return fuse.search(this.searchTemplate.search).map((res) => { return fuse.search(this.throttledSearch).map((res) => {
return res.item return res.item
}) })
} }

View File

@ -45,9 +45,9 @@
<p class="mt-2 text-lg font-normal text-gray-600"> <p class="mt-2 text-lg font-normal text-gray-600">
{{ cleanQuotes(template.short_description) }} {{ cleanQuotes(template.short_description) }}
</p> </p>
<!-- <template-tags :slug="template.slug" :display-all="true"--> <template-tags :template="template" :display-all="true"
<!-- class="flex flex-wrap items-center justify-center gap-3 mt-4 md:justify-start"--> class="flex flex-wrap items-center justify-center gap-3 mt-4 md:justify-start"
<!-- />--> />
</div> </div>
</div> </div>
</div> </div>
@ -226,6 +226,7 @@ const {data: relatedTemplatesData} = await useAsyncData('related-templates', ()
})) }))
}) })
templatesStore.save(relatedTemplatesData.value) templatesStore.save(relatedTemplatesData.value)
templatesStore.initTypesAndIndustries()
// State // State
const showFormTemplateModal = ref(false) const showFormTemplateModal = ref(false)
@ -235,7 +236,7 @@ const breadcrumbs = computed(() => {
if (!template.value) { if (!template.value) {
return [{route: {name: 'templates'}, label: 'Templates'}] return [{route: {name: 'templates'}, label: 'Templates'}]
} }
return [{route: {name: 'templates'}, label: 'Templates'}, {label: template.name}] return [{route: {name: 'templates'}, label: 'Templates'}, {label: template.value.name}]
}) })
const relatedTemplates = computed(() => templatesStore.getByKey(template?.value?.related_templates)) const relatedTemplates = computed(() => templatesStore.getByKey(template?.value?.related_templates))
const canEditTemplate = computed(() => authStore.authenticated && template.value && (authStore.user.admin || authStore.user.template_editor || template.creator_id === authStore.user.id)) const canEditTemplate = computed(() => authStore.authenticated && template.value && (authStore.user.admin || authStore.user.template_editor || template.creator_id === authStore.user.id))

View File

@ -31,6 +31,7 @@ const templatesStore = useTemplatesStore()
if (!templatesStore.allLoaded) { if (!templatesStore.allLoaded) {
templatesStore.startLoading() templatesStore.startLoading()
templatesStore.initTypesAndIndustries()
const {data} = await fetchAllTemplates() const {data} = await fetchAllTemplates()
templatesStore.set(data.value) templatesStore.set(data.value)
templatesStore.allLoaded = true templatesStore.allLoaded = true

View File

@ -76,7 +76,7 @@
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<router-link v-for="row in otherIndustries" :key="row.slug" <router-link v-for="row in otherIndustries" :key="row.slug"
:to="{params:{slug:row.slug}, name:'templates-industries'}" :to="{params:{slug:row.slug}, name:'templates-industries-slug'}"
:title="row.name" :title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue" class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
> >
@ -96,12 +96,12 @@
import Form from 'vform' import Form from 'vform'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import { computed } from 'vue' import { computed } from 'vue'
import { useAuthStore } from '../../stores/auth' import { useAuthStore } from '../../../stores/auth.js'
import { useTemplatesStore } from '../../stores/templates' import { useTemplatesStore } from '../../../stores/templates.js'
import SeoMeta from '../../mixins/seo-meta.js' import SeoMeta from '../../../mixins/seo-meta.js'
import OpenFormFooter from '../../components/pages/OpenFormFooter.vue' import OpenFormFooter from '../../../components/pages/OpenFormFooter.vue'
import Breadcrumb from '~/components/global/Breadcrumb.vue' import Breadcrumb from '~/components/global/Breadcrumb.vue'
import SingleTemplate from '../../components/pages/templates/SingleTemplate.vue' import SingleTemplate from '../../../components/pages/templates/SingleTemplate.vue'
const loadTemplates = function () { const loadTemplates = function () {
const templatesStore = useTemplatesStore() const templatesStore = useTemplatesStore()

View File

@ -1,238 +0,0 @@
<template>
<div class="flex flex-col min-h-full">
<breadcrumb :path="breadcrumbs" />
<div v-if="templatesLoading" class="text-center my-4">
<Loader class="h-6 w-6 text-nt-blue mx-auto" />
</div>
<p v-else-if="type === null || !type" class="text-center my-4">
We could not find this type.
</p>
<template v-else>
<section class="py-12 sm:py-16 bg-gray-50 border-b border-gray-200">
<div class="px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
<div class="text-center mx-auto">
<div class="font-semibold sm:w-full text-blue-500 mb-3">
{{ type.name }}
</div>
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold tracking-tight text-gray-900">
{{ type.meta_title }}
</h1>
<p class="max-w-xl mx-auto text-gray-600 mt-4 text-lg font-normal">
{{ type.meta_description }}
</p>
</div>
</div>
</section>
<section class="bg-white py-12 sm:py-16">
<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">
<div class="flex items-center gap-4">
<div class="flex-1 sm:flex-none">
<select-input v-model="selectedIndustry" name="industry"
:options="industriesOptions" class="w-full sm:w-auto md:w-56"
/>
</div>
</div>
<div class="flex-1 w-full md:max-w-xs">
<text-input name="search" :form="searchTemplate" placeholder="Search..." />
</div>
</div>
<div v-if="templatesLoading" class="text-center mt-4">
<Loader class="h-6 w-6 text-nt-blue mx-auto" />
</div>
<p v-else-if="enrichedTemplates.length === 0" class="text-center mt-4">
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" :slug="template.slug" />
</div>
</div>
</div>
</section>
<section class="py-12 bg-white border-t border-gray-200 sm:py-16">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<p class="text-gray-600 font-normal">
{{ type.description }}
</p>
</div>
</section>
<section class="py-12 bg-white border-t border-gray-200 sm:py-16">
<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">
Other Types
</h4>
<v-button :to="{name:'templates'}" color="white" size="small" :arrow="true">
View All Templates
</v-button>
</div>
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<router-link v-for="row in otherTypes" :key="row.slug"
:to="{params:{slug:row.slug}, name:'templates-types'}"
:title="row.name"
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
>
{{ row.name }}
</router-link>
</div>
</div>
</section>
</template>
<open-form-footer class="mt-8 border-t"/>
</div>
</template>
<script>
import Form from 'vform'
import Fuse from 'fuse.js'
import { computed } from 'vue'
import { useAuthStore } from '../../stores/auth'
import { useTemplatesStore } from '../../stores/templates'
import SeoMeta from '../../mixins/seo-meta.js'
import OpenFormFooter from '../../components/pages/OpenFormFooter.vue'
import Breadcrumb from '~/components/global/Breadcrumb.vue'
import SingleTemplate from '../../components/pages/templates/SingleTemplate.vue'
const loadTemplates = function () {
const templatesStore = useTemplatesStore()
templatesStore.startLoading()
templatesStore.loadIfEmpty().then(() => {
templatesStore.stopLoading()
})
}
export default {
components: { Breadcrumb, OpenFormFooter, SingleTemplate },
mixins: [SeoMeta],
beforeRouteEnter (to, from, next) {
loadTemplates()
next()
},
setup () {
const authStore = useAuthStore()
const templatesStore = useTemplatesStore()
return {
authenticated : computed(() => authStore.check),
user : computed(() => authStore.user),
templates : computed(() => templatesStore.content),
templatesLoading : computed(() => templatesStore.loading),
industries : computed(() => templatesStore.industries),
types : computed(() => templatesStore.types)
}
},
data () {
return {
selectedIndustry: 'all',
searchTemplate: new Form({
search: ''
})
}
},
mounted () {},
computed: {
breadcrumbs () {
if (!this.type) {
return [{ route: { name: 'templates' }, label: 'Templates' }]
}
return [{ route: { name: 'templates' }, label: 'Templates' }, { label: this.type.name }]
},
type () {
return Object.values(this.types).find((type) => {
return type.slug === this.$route.params.slug
})
},
industriesOptions () {
return [{ name: 'All Industries', value: 'all' }].concat(Object.values(this.industries).map((industry) => {
return {
name: industry.name,
value: industry.slug
}
}))
},
otherTypes() {
return Object.values(this.types).filter((type) => {
return type.slug !== this.$route.params.slug
})
},
enrichedTemplates () {
let enrichedTemplates = this.templates
// Filter by current Type only
enrichedTemplates = enrichedTemplates.filter((item) => {
return (item.types && item.types.length > 0) ? item.types.includes(this.$route.params.slug) : false
})
// Filter by Selected Industry
if (this.selectedIndustry && this.selectedIndustry !== 'all') {
enrichedTemplates = enrichedTemplates.filter((item) => {
return (item.industries && item.industries.length > 0) ? item.industries.includes(this.selectedIndustry) : false
})
}
if (this.searchTemplate.search === '' || this.searchTemplate.search === null) {
return enrichedTemplates
}
// Fuze search
const fuzeOptions = {
keys: [
'name',
'slug',
'description',
'short_description'
]
}
const fuse = new Fuse(enrichedTemplates, fuzeOptions)
return fuse.search(this.searchTemplate.search).map((res) => {
return res.item
})
},
metaTitle () {
return this.type ? this.type.meta_title : 'Form Template Type'
},
metaDescription () {
if (!this.type) return null
return this.type.meta_description.substring(0, 140)
}
},
methods: {}
}
</script>
<style lang='scss'>
.nf-text {
@apply space-y-4;
h2 {
@apply text-sm font-normal tracking-widest text-gray-500 uppercase;
}
p {
@apply font-normal leading-7 text-gray-900 dark:text-gray-100;
}
ol {
@apply list-decimal list-inside;
}
ul {
@apply list-disc list-inside;
}
}
</style>

View File

@ -0,0 +1,200 @@
<template>
<div class="flex flex-col min-h-full">
<breadcrumb :path="breadcrumbs"/>
<div v-if="templatesLoading" class="text-center my-4">
<Loader class="h-6 w-6 text-nt-blue mx-auto"/>
</div>
<p v-else-if="type === null || !type" class="text-center my-4">
We could not find this type.
</p>
<template v-else>
<section class="py-12 sm:py-16 bg-gray-50 border-b border-gray-200">
<div class="px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
<div class="text-center mx-auto">
<div class="font-semibold sm:w-full text-blue-500 mb-3">
{{ type.name }}
</div>
<h1 class="text-3xl sm:text-4xl lg:text-5xl font-bold tracking-tight text-gray-900">
{{ type.meta_title }}
</h1>
<p class="max-w-xl mx-auto text-gray-600 mt-4 text-lg font-normal">
{{ type.meta_description }}
</p>
</div>
</div>
</section>
<section class="bg-white py-12 sm:py-16">
<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">
<div class="flex items-center gap-4">
<div class="flex-1 sm:flex-none">
<select-input v-model="selectedIndustry" name="industry"
:options="industriesOptions" class="w-full sm:w-auto md:w-56"
/>
</div>
</div>
<div class="flex-1 w-full md:max-w-xs">
<text-input name="search" :form="searchTemplate" placeholder="Search..."/>
</div>
</div>
<div v-if="templatesLoading" class="text-center mt-4">
<Loader class="h-6 w-6 text-nt-blue mx-auto"/>
</div>
<p v-else-if="enrichedTemplates.length === 0" class="text-center mt-4">
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" :slug="template.slug"/>
</div>
</div>
</div>
</section>
<section class="py-12 bg-white border-t border-gray-200 sm:py-16">
<div class="px-4 mx-auto sm:px-6 lg:px-8 max-w-7xl">
<p class="text-gray-600 font-normal">
{{ type.description }}
</p>
</div>
</section>
<section class="py-12 bg-white border-t border-gray-200 sm:py-16">
<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">
Other Types
</h4>
<v-button :to="{name:'templates'}" color="white" size="small" :arrow="true">
View All Templates
</v-button>
</div>
<div class="grid grid-cols-1 gap-8 mt-8 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<router-link v-for="row in otherTypes" :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"
>
{{ row.name }}
</router-link>
</div>
</div>
</section>
</template>
<open-form-footer class="mt-8 border-t"/>
</div>
</template>
<script>
import {computed} from 'vue'
import SeoMeta from '../../../mixins/seo-meta.js'
import OpenFormFooter from '../../../components/pages/OpenFormFooter.vue'
import Breadcrumb from '~/components/global/Breadcrumb.vue'
import SingleTemplate from '../../../components/pages/templates/SingleTemplate.vue'
const authStore = useAuthStore()
const templatesStore = useTemplatesStore()
const route = useRoute()
// State
const selectedIndustry = ref('all')
const searchTemplate = useForm({
search: ''
})
// Computed
const authenticated = computed(() => authStore.check)
const user = computed(() => authStore.user)
const templates = computed(() => templatesStore.getAll)
const breadcrumbs = computed(() => {
if (!type) {
return [{route: {name: 'templates'}, label: 'Templates'}]
}
return [{route: {name: 'templates'}, label: 'Templates'}, {label: type.name}]
})
const type = computed(() => templatesStore.types.value.get(route.params.slug))
const types = computed(() => [...templatesStore.types.value.values()])
const industriesOptions = computed(() => [{name: 'All Industries', value: 'all'}].concat(
[...templatesStore.types.values.values()].map((industry) => {
return {
name: industry.name,
value: industry.slug
}
})))
// enrichedTemplates()
// {
// let enrichedTemplates = this.templates
//
// // Filter by current Type only
// enrichedTemplates = enrichedTemplates.filter((item) => {
// return (item.types && item.types.length > 0) ? item.types.includes(this.$route.params.slug) : false
// })
//
// // Filter by Selected Industry
// if (this.selectedIndustry && this.selectedIndustry !== 'all') {
// enrichedTemplates = enrichedTemplates.filter((item) => {
// return (item.industries && item.industries.length > 0) ? item.industries.includes(this.selectedIndustry) : false
// })
// }
//
// if (this.searchTemplate.search === '' || this.searchTemplate.search === null) {
// return enrichedTemplates
// }
//
// // Fuze search
// const fuzeOptions = {
// keys: [
// 'name',
// 'slug',
// 'description',
// 'short_description'
// ]
// }
// const fuse = new Fuse(enrichedTemplates, fuzeOptions)
// return fuse.search(this.searchTemplate.search).map((res) => {
// return res.item
// })
// }
// ,
// metaTitle()
// {
// return this.type ? this.type.meta_title : 'Form Template Type'
// }
// ,
// metaDescription()
// {
// if (!this.type) return null
// return this.type.meta_description.substring(0, 140)
// }
</script>
<style lang='scss'>
.nf-text {
@apply space-y-4;
h2 {
@apply text-sm font-normal tracking-widest text-gray-500 uppercase;
}
p {
@apply font-normal leading-7 text-gray-900 dark:text-gray-100;
}
ol {
@apply list-decimal list-inside;
}
ul {
@apply list-disc list-inside;
}
}
</style>

View File

@ -1,5 +1,7 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import {useContentStore} from "~/composables/stores/useContentStore.js"; import {useContentStore} from "~/composables/stores/useContentStore.js";
import templateTypes from "~/data/forms/templates/types.json"
import industryTypes from "~/data/forms/templates/industries.json"
const templatesEndpoint = 'templates' const templatesEndpoint = 'templates'
export const useTemplatesStore = defineStore('templates', () => { export const useTemplatesStore = defineStore('templates', () => {
@ -7,29 +9,26 @@ export const useTemplatesStore = defineStore('templates', () => {
const contentStore = useContentStore('slug') const contentStore = useContentStore('slug')
const allLoaded = ref(false) const allLoaded = ref(false)
const industries = ref({}) const industries = ref(new Map)
const types = ref({}) const types = ref(new Map)
const getTemplateTypes = computed((state) => (slugs) => { const getTemplateTypes = (slugs) => {
if (state.types.length === 0) return null return slugs.map((slug) => {
return Object.values(state.types).filter((val) => slugs.includes(val.slug)).map((item) => { return types.value.get(slug)
return item.name }).filter((item) => item !== undefined)
}) }
// todo: use map const getTemplateIndustries =(slugs) => {
}) return slugs.map((slug) => {
const getTemplateIndustries = computed((state) => (slugs) => { return industries.value.get(slug)
if (state.industries.length === 0) return null }).filter((item) => item !== undefined)
return Object.values(state.industries).filter((val) => slugs.includes(val.slug)).map((item) => { }
return item.name
})
})
const loadTypesAndIndustries = function() { const initTypesAndIndustries = () => {
if (Object.keys(this.industries).length === 0 || Object.keys(this.types).length === 0) { if (types.value.size === 0) {
// const files = import.meta.glob('~/data/forms/templates/*.json') types.value = new Map(Object.entries(templateTypes))
// console.log(await files['/data/forms/templates/industries.json']()) }
// this.industries = await files['/data/forms/templates/industries.json']() if (industries.value.size === 0) {
// this.types = await files['/data/forms/templates/types.json']() industries.value = new Map(Object.entries(industryTypes))
} }
} }
@ -39,7 +38,7 @@ export const useTemplatesStore = defineStore('templates', () => {
types, types,
getTemplateTypes, getTemplateTypes,
getTemplateIndustries, getTemplateIndustries,
loadTypesAndIndustries, initTypesAndIndustries
} }
}) })
@ -51,3 +50,8 @@ export const fetchAllTemplates = () => {
return useOpnApi(templatesEndpoint) return useOpnApi(templatesEndpoint)
} }
export const loadTypesAndIndustries = () => {
// Load the json files
}