Finishing the templates pages
This commit is contained in:
parent
bb519907f6
commit
8e70d6be98
|
@ -1,51 +1,48 @@
|
|||
<template>
|
||||
<div v-if="template">
|
||||
<!-- <template v-if="displayAll">-->
|
||||
<!-- <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"-->
|
||||
<!-- >-->
|
||||
<!-- <svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"-->
|
||||
<!-- fill="currentColor"-->
|
||||
<!-- >-->
|
||||
<!-- <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"-->
|
||||
<!-- clip-rule="evenodd"-->
|
||||
<!-- />-->
|
||||
<!-- </svg>-->
|
||||
<!-- New-->
|
||||
<!-- </span>-->
|
||||
<!-- <span v-for="item in types"-->
|
||||
<!-- 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 }}-->
|
||||
<!-- </span>-->
|
||||
<!-- <span v-for="item in industries"-->
|
||||
<!-- 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 }}-->
|
||||
<!-- </span>-->
|
||||
<!-- </template>-->
|
||||
<!-- <template v-else>-->
|
||||
<!-- <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"-->
|
||||
<!-- >-->
|
||||
<!-- {{ types[0] }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>-->
|
||||
<!-- </span>-->
|
||||
<!-- <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"-->
|
||||
<!-- >-->
|
||||
<!-- {{ industries[0] }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>-->
|
||||
<!-- </span>-->
|
||||
<!-- </template>-->
|
||||
<div>
|
||||
<template v-if="displayAll">
|
||||
<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"
|
||||
>
|
||||
<svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<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"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
New
|
||||
</span>
|
||||
<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"
|
||||
>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<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"
|
||||
>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<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"
|
||||
>
|
||||
{{ types[0].name }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>
|
||||
</span>
|
||||
<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"
|
||||
>
|
||||
{{ industries[0].name }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue'
|
||||
import { useTemplatesStore } from '../../../stores/templates'
|
||||
<script setup>
|
||||
|
||||
export default {
|
||||
props: {
|
||||
const props = defineProps({
|
||||
template: {
|
||||
type: Object,
|
||||
required: true
|
||||
|
@ -54,31 +51,9 @@ export default {
|
|||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
setup () {
|
||||
const templatesStore = useTemplatesStore()
|
||||
return {
|
||||
templatesStore
|
||||
}
|
||||
},
|
||||
|
||||
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: {}
|
||||
}
|
||||
const templatesStore = useTemplatesStore()
|
||||
const types = computed(() => templatesStore.getTemplateTypes(props.template.types))
|
||||
const industries = computed(() => templatesStore.getTemplateIndustries(props.template.industries))
|
||||
</script>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
|
@ -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">
|
||||
<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"
|
||||
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">
|
||||
<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"
|
||||
class="text-gray-600 dark:text-gray-400 transition-colors duration-300 hover:text-nt-blue"
|
||||
>
|
||||
|
@ -79,9 +79,9 @@
|
|||
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import Form from 'vform'
|
||||
import Fuse from 'fuse.js'
|
||||
import SingleTemplate from './SingleTemplate.vue'
|
||||
import {refThrottled} from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
name: 'TemplatesList',
|
||||
|
@ -100,23 +100,22 @@ export default {
|
|||
setup() {
|
||||
const authStore = useAuthStore()
|
||||
const templatesStore = useTemplatesStore()
|
||||
const search = ref('')
|
||||
const throttledSearch = refThrottled(search, 1000)
|
||||
return {
|
||||
search,
|
||||
throttledSearch,
|
||||
user: computed(() => authStore.user),
|
||||
industries: computed(() => templatesStore.industries),
|
||||
types: computed(() => templatesStore.types)
|
||||
industries: computed(() => [...templatesStore.industries.values()]),
|
||||
types: computed(() => [...templatesStore.types.values()])
|
||||
}
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
selectedType: 'all',
|
||||
selectedIndustry: 'all',
|
||||
searchTemplate: new Form({
|
||||
search: ''
|
||||
})
|
||||
}),
|
||||
|
||||
watch: {},
|
||||
|
||||
computed: {
|
||||
industriesOptions() {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ export default {
|
|||
]
|
||||
}
|
||||
const fuse = new Fuse(enrichedTemplates, fuzeOptions)
|
||||
return fuse.search(this.searchTemplate.search).map((res) => {
|
||||
return fuse.search(this.throttledSearch).map((res) => {
|
||||
return res.item
|
||||
})
|
||||
}
|
||||
|
|
|
@ -45,9 +45,9 @@
|
|||
<p class="mt-2 text-lg font-normal text-gray-600">
|
||||
{{ cleanQuotes(template.short_description) }}
|
||||
</p>
|
||||
<!-- <template-tags :slug="template.slug" :display-all="true"-->
|
||||
<!-- class="flex flex-wrap items-center justify-center gap-3 mt-4 md:justify-start"-->
|
||||
<!-- />-->
|
||||
<template-tags :template="template" :display-all="true"
|
||||
class="flex flex-wrap items-center justify-center gap-3 mt-4 md:justify-start"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -226,6 +226,7 @@ const {data: relatedTemplatesData} = await useAsyncData('related-templates', ()
|
|||
}))
|
||||
})
|
||||
templatesStore.save(relatedTemplatesData.value)
|
||||
templatesStore.initTypesAndIndustries()
|
||||
|
||||
// State
|
||||
const showFormTemplateModal = ref(false)
|
||||
|
@ -235,7 +236,7 @@ const breadcrumbs = computed(() => {
|
|||
if (!template.value) {
|
||||
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 canEditTemplate = computed(() => authStore.authenticated && template.value && (authStore.user.admin || authStore.user.template_editor || template.creator_id === authStore.user.id))
|
||||
|
|
|
@ -31,6 +31,7 @@ const templatesStore = useTemplatesStore()
|
|||
|
||||
if (!templatesStore.allLoaded) {
|
||||
templatesStore.startLoading()
|
||||
templatesStore.initTypesAndIndustries()
|
||||
const {data} = await fetchAllTemplates()
|
||||
templatesStore.set(data.value)
|
||||
templatesStore.allLoaded = true
|
||||
|
|
|
@ -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">
|
||||
<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"
|
||||
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 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 { useAuthStore } from '../../../stores/auth.js'
|
||||
import { useTemplatesStore } from '../../../stores/templates.js'
|
||||
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'
|
||||
import SingleTemplate from '../../../components/pages/templates/SingleTemplate.vue'
|
||||
|
||||
const loadTemplates = function () {
|
||||
const templatesStore = useTemplatesStore()
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import {defineStore} from 'pinia'
|
||||
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'
|
||||
export const useTemplatesStore = defineStore('templates', () => {
|
||||
|
@ -7,29 +9,26 @@ export const useTemplatesStore = defineStore('templates', () => {
|
|||
const contentStore = useContentStore('slug')
|
||||
|
||||
const allLoaded = ref(false)
|
||||
const industries = ref({})
|
||||
const types = ref({})
|
||||
const industries = ref(new Map)
|
||||
const types = ref(new Map)
|
||||
|
||||
const getTemplateTypes = computed((state) => (slugs) => {
|
||||
if (state.types.length === 0) return null
|
||||
return Object.values(state.types).filter((val) => slugs.includes(val.slug)).map((item) => {
|
||||
return item.name
|
||||
})
|
||||
// todo: use map
|
||||
})
|
||||
const getTemplateIndustries = computed((state) => (slugs) => {
|
||||
if (state.industries.length === 0) return null
|
||||
return Object.values(state.industries).filter((val) => slugs.includes(val.slug)).map((item) => {
|
||||
return item.name
|
||||
})
|
||||
})
|
||||
const getTemplateTypes = (slugs) => {
|
||||
return slugs.map((slug) => {
|
||||
return types.value.get(slug)
|
||||
}).filter((item) => item !== undefined)
|
||||
}
|
||||
const getTemplateIndustries =(slugs) => {
|
||||
return slugs.map((slug) => {
|
||||
return industries.value.get(slug)
|
||||
}).filter((item) => item !== undefined)
|
||||
}
|
||||
|
||||
const loadTypesAndIndustries = function() {
|
||||
if (Object.keys(this.industries).length === 0 || Object.keys(this.types).length === 0) {
|
||||
// const files = import.meta.glob('~/data/forms/templates/*.json')
|
||||
// console.log(await files['/data/forms/templates/industries.json']())
|
||||
// this.industries = await files['/data/forms/templates/industries.json']()
|
||||
// this.types = await files['/data/forms/templates/types.json']()
|
||||
const initTypesAndIndustries = () => {
|
||||
if (types.value.size === 0) {
|
||||
types.value = new Map(Object.entries(templateTypes))
|
||||
}
|
||||
if (industries.value.size === 0) {
|
||||
industries.value = new Map(Object.entries(industryTypes))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +38,7 @@ export const useTemplatesStore = defineStore('templates', () => {
|
|||
types,
|
||||
getTemplateTypes,
|
||||
getTemplateIndustries,
|
||||
loadTypesAndIndustries,
|
||||
initTypesAndIndustries
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -51,3 +50,8 @@ export const fetchAllTemplates = () => {
|
|||
return useOpnApi(templatesEndpoint)
|
||||
}
|
||||
|
||||
export const loadTypesAndIndustries = () => {
|
||||
// Load the json files
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue