navigation on collections and dynamic routing improvements
This commit is contained in:
parent
5c56af0dad
commit
44b55d9bbb
11 changed files with 117 additions and 48 deletions
18
components/CollectionDetail.vue
Normal file
18
components/CollectionDetail.vue
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<template>
|
||||||
|
<div class="min-h-[calc(100vh-9rem)] container mx-auto py-12">
|
||||||
|
{{ data }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import type SharedHero from "../types/component/sharedHero";
|
||||||
|
import type { ComponentTypes } from "../types/component/baseComponent";
|
||||||
|
import type Article from "../types/collection/article";
|
||||||
|
import type Operation from "../types/collection/operation";
|
||||||
|
import type Event from "../types/collection/event";
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
data: Object as PropType<Article | Operation | Event>,
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="min-h-[calc(100vh-9rem)] w-full">
|
||||||
<SharedHero v-if="hero" :data="hero" />
|
<SharedHero v-if="hero" :data="hero" />
|
||||||
<div class="container mx-auto py-12 min-h-[50vh]">
|
<div class="container mx-auto py-12 min-h-[50vh]">
|
||||||
<div v-for="item in content" class="contents">
|
<div v-for="item in content" class="contents">
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
<SharedList v-else-if="item.__component == 'shared.list'" :data="item" />
|
<SharedList v-else-if="item.__component == 'shared.list'" :data="item" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -19,7 +21,7 @@ import type SharedHero from "../types/component/sharedHero";
|
||||||
import type { ComponentTypes } from "../types/component/baseComponent";
|
import type { ComponentTypes } from "../types/component/baseComponent";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
hero: Object as PropType<SharedHero>,
|
hero: { type: Object as PropType<SharedHero>, required: false, default: null },
|
||||||
content: Array<ComponentTypes>,
|
content: Array<ComponentTypes>,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
primary-link
|
primary-link
|
||||||
v-for="link in navbar.navbar_items"
|
v-for="link in navbar.navbar_items"
|
||||||
:key="link.id"
|
:key="link.id"
|
||||||
:to="`/${link.URL}/${link.default_active_child}`"
|
:to="`/${link.URL}/${link.default_active_child ?? ''}`"
|
||||||
:class="link.URL == params?.[0] ? 'active' : ''"
|
:class="link.URL == params?.[0] ? 'active' : ''"
|
||||||
>
|
>
|
||||||
{{ link.name }}
|
{{ link.name }}
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
v-for="sublink in navbar_sub_items"
|
v-for="sublink in navbar_sub_items"
|
||||||
:key="sublink.id"
|
:key="sublink.id"
|
||||||
:to="`/${params?.[0]}/${sublink.URL}`"
|
:to="`/${params?.[0]}/${sublink.URL}`"
|
||||||
:class="sublink.URL == params?.[1] ? 'active' : ''"
|
:class="sublink.URL == params?.[1] && !params[2] ? 'active' : ''"
|
||||||
>
|
>
|
||||||
{{ sublink.name }}
|
{{ sublink.name }}
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full max-h-60 h-60">
|
<div class="flex flex-col w-full max-h-72 h-72 overflow-hidden">
|
||||||
<NuxtPicture
|
<NuxtPicture
|
||||||
preload
|
preload
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
class="w-full h-full object-cover object-center"
|
class="w-full h-60 object-cover object-center"
|
||||||
:src="baseUrl + data?.banner.url"
|
:src="baseUrl + data?.banner.url"
|
||||||
:imgAttrs="{ class: 'w-full h-full object-cover object-center' }"
|
:imgAttrs="{ class: 'w-full h-60 object-cover object-center' }"
|
||||||
/>
|
/>
|
||||||
<div primary class="h-12 w-full px-12 justify-center items-center gap-5 flex">
|
<div primary class="h-12 min-h-12 w-full px-12 justify-center items-center gap-5 flex">
|
||||||
<p>{{ data?.title }}</p>
|
<p>{{ data?.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,41 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout name="default">
|
<NuxtLayout name="default">
|
||||||
<NotFound v-if="active_page_id == ''" />
|
<NotFound v-if="notFound" />
|
||||||
<ContentBuilder v-else class="min-h-[calc(100vh-9rem)] w-full" :hero="hero" :content="content" />
|
<ContentBuilder v-else-if="showContentBuilder" :hero="page?.hero" :content="page?.content" />
|
||||||
|
<CollectionDetail v-else :data="detail" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type Article from "../types/collection/article";
|
||||||
|
import type Event from "../types/collection/event";
|
||||||
|
import type Lookup from "../types/collection/lookup";
|
||||||
|
import type Operation from "../types/collection/operation";
|
||||||
import type Page from "../types/collection/page";
|
import type Page from "../types/collection/page";
|
||||||
|
import type NavbarSubItem from "../types/component/itemsNavbarSubItem";
|
||||||
import type Global from "../types/single/global";
|
import type Global from "../types/single/global";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
params: { slug: params },
|
params: { slug: params },
|
||||||
} = useRoute();
|
} = useRoute();
|
||||||
const baseUrl = useStrapiUrl().replace("/api", "");
|
const { findOne, find } = useStrapi();
|
||||||
const { findOne } = useStrapi();
|
|
||||||
|
|
||||||
const { data: global } = await useAsyncData("global", () => findOne<Global>("global"));
|
const { data: global } = await useAsyncData("global", () => findOne<Global>("global"));
|
||||||
const {
|
const {
|
||||||
navbar: { navbar_items },
|
navbar: { navbar_items },
|
||||||
} = global.value?.data ?? ({} as Global);
|
} = global.value?.data ?? ({} as Global);
|
||||||
|
|
||||||
const navbar_sub_items = computed(() => {
|
const navbar_sub_items = ref<NavbarSubItem[]>(navbar_items.find((ni) => ni.URL == params[0])?.navbar_sub_items ?? []);
|
||||||
return navbar_items.find((ni) => ni.URL == params[0])?.navbar_sub_items ?? [];
|
const active_item = ref<Page | null | undefined>(navbar_items.find((ni) => ni.URL == params[0])?.page);
|
||||||
});
|
const active_sub_item = ref<Page | null | undefined>(navbar_sub_items.value.find((si) => si.URL == params[1])?.page);
|
||||||
|
const active_page_id = ref<string>(active_sub_item.value?.documentId ?? active_item.value?.documentId ?? "");
|
||||||
const active_item = computed(() => {
|
|
||||||
return navbar_items.find((ni) => ni.URL == params[0])?.page;
|
|
||||||
});
|
|
||||||
const active_sub_item = computed(() => {
|
|
||||||
return navbar_sub_items.value.find((si) => si.URL == params[1])?.page;
|
|
||||||
});
|
|
||||||
const active_page_id = computed<string>(() => {
|
|
||||||
return active_sub_item.value?.documentId ?? active_item.value?.documentId ?? "";
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: pages } = await useAsyncData("pages", () =>
|
const { data: pages } = await useAsyncData("pages", () =>
|
||||||
findOne<Page>("pages", active_page_id.value, {
|
findOne<Page | Array<Page>>("pages", active_page_id.value, {
|
||||||
populate: {
|
populate: {
|
||||||
populate: "*",
|
populate: "*",
|
||||||
content: {
|
content: {
|
||||||
|
@ -45,7 +41,37 @@ const { data: pages } = await useAsyncData("pages", () =>
|
||||||
populate: "*",
|
populate: "*",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
filters: {
|
||||||
|
...(active_page_id.value == "" ? { slug: params[0] } : {}),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const { content, hero } = pages.value?.data ?? {};
|
const page = ref<Page | undefined>(Array.isArray(pages.value?.data) ? pages.value.data[0] : pages.value?.data);
|
||||||
|
|
||||||
|
let detail = ref<Article | Operation | Event | undefined>(undefined);
|
||||||
|
const searchDetail = params[2] || (params[1] && navbar_sub_items.value.length == 0);
|
||||||
|
if (searchDetail) {
|
||||||
|
const paramsFind = params[2] ? [params[0], params[1]] : [params[0]];
|
||||||
|
const { data: lookup } = await useAsyncData("lookup", () => find<Lookup>("collection-lookups"));
|
||||||
|
const activeLookup: Lookup | undefined = lookup.value?.data.find((l) => paramsFind.includes(l.reference));
|
||||||
|
const { data: details } = await useAsyncData("detail", () =>
|
||||||
|
find<Article | Operation | Event>(activeLookup?.collection ?? "", {
|
||||||
|
populate: "*",
|
||||||
|
filters: {
|
||||||
|
slug: params[2] ?? params[1],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
detail.value = details.value?.data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const notFound = computed(() => {
|
||||||
|
if (searchDetail) return !detail.value;
|
||||||
|
else return active_page_id.value == "" && !page.value?.content && !page.value?.hero;
|
||||||
|
});
|
||||||
|
|
||||||
|
const showContentBuilder = computed(() => {
|
||||||
|
if (searchDetail) return !detail.value;
|
||||||
|
else return !!page.value?.content || !!page.value?.hero;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout name="landing">
|
<NuxtLayout name="landing">
|
||||||
<ContentBuilder class="min-h-[calc(100vh-9rem)] w-full" :content="content" />
|
<ContentBuilder :content="content" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
export default interface Article {
|
import type BaseCollection from "./baseCollection";
|
||||||
id: number;
|
|
||||||
documentId: string;
|
export default interface Article extends BaseCollection {
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
slug: string;
|
|
||||||
content: Array<{ type: string; children: Array<{ type: string; text: string }>; level?: number }>;
|
content: Array<{ type: string; children: Array<{ type: string; text: string }>; level?: number }>;
|
||||||
date: string;
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
publishedAt: string;
|
|
||||||
locale: string;
|
|
||||||
}
|
}
|
||||||
|
|
12
types/collection/baseCollection.ts
Normal file
12
types/collection/baseCollection.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
export default interface BaseCollection {
|
||||||
|
id: number;
|
||||||
|
documentId: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
slug: string;
|
||||||
|
date: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
publishedAt: string;
|
||||||
|
locale: string;
|
||||||
|
}
|
5
types/collection/event.ts
Normal file
5
types/collection/event.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import type BaseCollection from "./baseCollection";
|
||||||
|
|
||||||
|
export default interface Event extends BaseCollection {
|
||||||
|
content: Array<{ type: string; children: Array<{ type: string; text: string }>; level?: number }>;
|
||||||
|
}
|
9
types/collection/lookup.ts
Normal file
9
types/collection/lookup.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export default interface Lookup {
|
||||||
|
id: number;
|
||||||
|
documentId: string;
|
||||||
|
collection: string;
|
||||||
|
reference: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
publishedAt: Date;
|
||||||
|
}
|
5
types/collection/operation.ts
Normal file
5
types/collection/operation.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import type BaseCollection from "./baseCollection";
|
||||||
|
|
||||||
|
export default interface Operation extends BaseCollection {
|
||||||
|
content: Array<{ type: string; children: Array<{ type: string; text: string }>; level?: number }>;
|
||||||
|
}
|
Loading…
Reference in a new issue