@meeovi/layer-commerce 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/app/components/catalog/product/ProductAccordion/types.ts +3 -3
  2. package/app/components/catalog/product/ProductProperties/types.ts +3 -3
  3. package/app/components/catalog/product/ProductSlider/types.ts +5 -5
  4. package/app/components/catalog/product/RecommendedProducts/types.ts +3 -3
  5. package/app/components/catalog/product/bestsellers.vue +8 -20
  6. package/app/components/catalog/product/deals.vue +7 -22
  7. package/app/components/catalog/product/exclusives.vue +8 -10
  8. package/app/components/catalog/product/featuredproducts.vue +8 -20
  9. package/app/components/catalog/product/latestproducts.vue +8 -20
  10. package/app/components/catalog/product/productCard.vue +55 -21
  11. package/app/components/catalog/product/productDetails.vue +20 -14
  12. package/app/components/catalog/product/relatedproducts.vue +5 -20
  13. package/app/components/catalog/product/sizeOptions.vue +3 -8
  14. package/app/components/catalog/shops/relatedstores.vue +6 -21
  15. package/app/components/categories/chart/[id].vue +200 -0
  16. package/app/components/categories/chart/add-chart.vue +142 -0
  17. package/app/components/categories/chart/chart.vue +82 -0
  18. package/app/components/categories/chart/monthlyChart.vue +46 -0
  19. package/app/components/categories/chart/weeklyChart.vue +46 -0
  20. package/app/components/categories/chart/yearlyChart.vue +46 -0
  21. package/app/components/categories/charts.vue +118 -0
  22. package/app/components/categories/deals.vue +101 -0
  23. package/app/components/categories/eats.vue +49 -0
  24. package/app/components/categories/restaurants.vue +26 -0
  25. package/app/components/categories/station/[id].vue +72 -0
  26. package/app/components/categories/stations.vue +124 -0
  27. package/app/components/categories/time/time.vue +63 -0
  28. package/app/components/categories/travel.vue +75 -0
  29. package/app/components/categories/weather/weather.vue +44 -0
  30. package/app/components/content/pages/showcases.vue +1 -1
  31. package/app/components/marketing/promotions/giftcards.vue +20 -45
  32. package/app/components/marketing/promotions/subscriptions.vue +8 -21
  33. package/app/components/placeholders/Comments.vue +15 -0
  34. package/app/components/placeholders/CreateListBtn.vue +7 -0
  35. package/app/components/placeholders/Event.vue +9 -0
  36. package/app/components/placeholders/ListShowcases.vue +9 -0
  37. package/app/components/placeholders/Short.vue +9 -0
  38. package/app/components/placeholders/Space.vue +9 -0
  39. package/app/components/placeholders/Tag.vue +7 -0
  40. package/app/components/sales/CheckoutAddress/types.ts +12 -11
  41. package/app/components/sales/OrderSummary/types.ts +3 -3
  42. package/app/components/sales/incentives.vue +13 -37
  43. package/app/composables/cart/registry.ts +7 -0
  44. package/app/composables/index.ts +1 -0
  45. package/app/composables/products/registry.ts +7 -0
  46. package/app/composables/registry.ts +21 -0
  47. package/app/composables/useCatalog.ts +64 -0
  48. package/app/composables/useContent.ts +57 -0
  49. package/app/composables/useProducts/types.ts +15 -10
  50. package/app/pages/brand/[...slug].vue +1 -1
  51. package/app/pages/departments/[...slug].vue +385 -0
  52. package/app/pages/departments/category/[...slug].vue +135 -0
  53. package/app/pages/product/[...id].vue +3 -3
  54. package/app/pages/shop/[...slug].vue +12 -18
  55. package/app/pages/shops.vue +18 -25
  56. package/global.d.ts +14 -0
  57. package/package.json +4 -2
  58. package/tsconfig.json +10 -1
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <div>
3
+ <v-card elevation="0" style="min-height: 100vh !important;">
4
+ <v-layout>
5
+ <v-main>
6
+ <v-tabs center-active v-model="tab" bg-color="transparent">
7
+ <div v-for="(menu, index) in dealbar?.menus" :key="index">
8
+ <v-tab :value="menu?.value">{{ menu?.name }}</v-tab>
9
+ </div>
10
+ </v-tabs>
11
+
12
+ <v-card-text>
13
+ <v-tabs-window v-model="tab">
14
+ <v-tabs-window-item :value="dealbar?.menus[0]?.value">
15
+ <v-row>
16
+ <v-col cols="3" v-for="products in dealsProducts" :key="products">
17
+ <productCard :product="products" />
18
+ </v-col>
19
+ </v-row>
20
+ </v-tabs-window-item>
21
+
22
+ <v-tabs-window-item :value="dealbar?.menus[1]?.value">
23
+ <v-row>
24
+ <v-col cols="3" v-for="products in dollar" :key="products">
25
+ <productCard :product="products" />
26
+ </v-col>
27
+ </v-row>
28
+ </v-tabs-window-item>
29
+ </v-tabs-window>
30
+ </v-card-text>
31
+ </v-main>
32
+ </v-layout>
33
+ </v-card>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup>
38
+ import {
39
+ ref
40
+ } from 'vue'
41
+ import productCard from '#commerce/app/components/catalog/product/productCard.vue'
42
+
43
+
44
+ const {
45
+ $directus,
46
+ $readItem,
47
+ $readItems
48
+ } = useNuxtApp()
49
+
50
+ const {
51
+ data: dealbar
52
+ } = await useAsyncData('dealbar', () => {
53
+ return $directus.request($readItem('navigation', '49', {
54
+ fields: ['*', {
55
+ '*': ['*']
56
+ }]
57
+ }))
58
+ })
59
+
60
+ const {
61
+ data: dealsProducts
62
+ } = await useAsyncData('dealsProducts', () => {
63
+ return $directus.request($readItems('products', {
64
+ fields: ['*', {
65
+ '*': ['*']
66
+ }],
67
+ filter: {
68
+ price: {
69
+ _lte: 20
70
+ }
71
+ }
72
+ }))
73
+ })
74
+
75
+ const {
76
+ data: dollar
77
+ } = await useAsyncData('dollar', () => {
78
+ return $directus.request($readItems('products', {
79
+ fields: ['*', {
80
+ '*': ['*']
81
+ }],
82
+ filter: {
83
+ price: {
84
+ _lte: 1
85
+ }
86
+ }
87
+ }))
88
+ })
89
+
90
+ const tab = ref(null)
91
+ const props = defineProps({
92
+ category: {
93
+ type: Number,
94
+ required: true,
95
+ },
96
+ });
97
+
98
+ useHead({
99
+ title: 'Deals',
100
+ })
101
+ </script>
@@ -0,0 +1,49 @@
1
+ <template :style="`background: ${categoryEats?.color}`">
2
+ <div>
3
+ <v-toolbar :title="`Meeovi ${categoryEats?.name}`" :color="categoryEats?.color" :style="`color: ${categoryEats?.colortext}; font: bold;`"></v-toolbar>
4
+ <v-row class="eatsPage">
5
+ <v-col cols="12" v-for="(eats, index) in eats" :key="index">
6
+ <shorts :short="eats" />
7
+ </v-col>
8
+ </v-row>
9
+ </div>
10
+ </template>
11
+
12
+ <script setup>
13
+ import shorts from '@/components/placeholder/shorts.vue'
14
+ //import share from '~/components/partials/globals/share.vue'
15
+
16
+ const {
17
+ $directus,
18
+ $readItems,
19
+ $readItem
20
+ } = useNuxtApp()
21
+
22
+ const {
23
+ data: eats
24
+ } = await useAsyncData('eats', () => {
25
+ return $directus.request($readItems('shorts', {
26
+ filter: {
27
+ type: {
28
+ _eq: 'Eats'
29
+ },
30
+ status: {
31
+ _eq: 'Published'
32
+ }
33
+ },
34
+ fields: ['*', {
35
+ '*': ['*']
36
+ }]
37
+ }))
38
+ })
39
+
40
+ const {
41
+ data: categoryEats
42
+ } = await useAsyncData('categoryEats', () => {
43
+ return $directus.request($readItem('categories', '152', {
44
+ fields: ['*', {
45
+ '*': ['*']
46
+ }]
47
+ }))
48
+ })
49
+ </script>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div>
3
+ <v-card elevation="0">
4
+ <v-toolbar :title="restaurant?.name" color="#1F7087"></v-toolbar>
5
+
6
+ <v-card-text>
7
+ <v-row>
8
+ <v-col cols="12" v-for="item in restaurant?.items" :key="item.id">
9
+ <v-list-item>
10
+ <v-list-item-content>
11
+ <v-list-item-title>{{ item.name }}</v-list-item-title>
12
+ <v-list-item-subtitle>{{ item.description }}</v-list-item-subtitle>
13
+ </v-list-item-content>
14
+ </v-list-item>
15
+ </v-col>
16
+ </v-row>
17
+ </v-card-text>
18
+ </v-card>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup>
23
+ const props = defineProps({
24
+ restaurant: Object
25
+ })
26
+ </script>
@@ -0,0 +1,72 @@
1
+ <template>
2
+ <div class="contentPage">
3
+ <v-row>
4
+ <v-col cols="12">
5
+ <v-card color="#b02564">
6
+ <div class="d-flex flex-no-wrap justify-space-between">
7
+ <div>
8
+ <v-card-title class="text-h5">
9
+ {{ station?.name }} <share style="display: inline-block; font-size: 15px;" />
10
+ </v-card-title>
11
+
12
+ <v-card-subtitle>Format: {{ station?.format }}</v-card-subtitle>
13
+
14
+ <v-card-subtitle>Categories:
15
+ <div v-for="category in station?.categories" :key="category">
16
+ {{ category?.categories_id?.name }}
17
+ </div>
18
+ </v-card-subtitle>
19
+
20
+ <v-card-subtitle v-dompurify-html="station?.description"></v-card-subtitle>
21
+ </div>
22
+
23
+ <v-avatar class="ma-3" rounded="0" size="125">
24
+ <NuxtImg :src="`${$directus.url}/assets/${station?.image?.filename_disk}`" />
25
+ </v-avatar>
26
+ </div>
27
+
28
+ <audio :src="`${$directus.url}/assets/${station?.file?.filename_disk}`" controls loop class="radioStation"></audio>
29
+ </v-card>
30
+ </v-col>
31
+
32
+ <v-col cols="12">
33
+ <relatedstations />
34
+ </v-col>
35
+
36
+ <v-col cols="12">
37
+ <comments />
38
+ </v-col>
39
+ </v-row>
40
+ </div>
41
+ </template>
42
+
43
+ <script setup>
44
+ import {
45
+ ref,
46
+ computed
47
+ } from 'vue'
48
+ import relatedstations from '@/components/catalog/product/relatedstations.vue'
49
+ import comments from '~/components/partials/globals/comments.vue'
50
+ import share from '~/components/partials/globals/share.vue'
51
+
52
+ const route = useRoute()
53
+
54
+ const {
55
+ $directus,
56
+ $readItem
57
+ } = useNuxtApp()
58
+
59
+ const {
60
+ data: station
61
+ } = await useAsyncData('station', () => {
62
+ return $directus.request($readItem('radios', route.params.id, {
63
+ fields: ['*', {
64
+ '*': ['*']
65
+ }]
66
+ }))
67
+ })
68
+
69
+ useHead({
70
+ title: computed(() => station?.value?.name || 'Station Page'),
71
+ });
72
+ </script>
@@ -0,0 +1,124 @@
1
+ <template>
2
+ <div>
3
+ <!---->
4
+ <v-card elevation="0">
5
+ <v-toolbar :title="stationbar?.name" color="#b02564">
6
+ <v-dialog min-width="500">
7
+ <template v-slot:activator="{ props: activatorProps }">
8
+ <v-btn v-bind="activatorProps" prepend-icon="fas:fa fa-plus" title="Create a Station"
9
+ variant="flat">Create a Station
10
+ </v-btn>
11
+ </template>
12
+
13
+ <template v-slot:default="{ isActive }">
14
+ <createstation />
15
+ </template>
16
+ </v-dialog>
17
+ </v-toolbar>
18
+
19
+ <v-tabs v-model="tab" bg-color="#b02564">
20
+ <div v-for="(menu, index) in stationbar?.menus" :key="index">
21
+ <v-tab :value="menu?.value">{{ menu?.name }}</v-tab>
22
+ </div>
23
+ </v-tabs>
24
+
25
+ <v-card-text>
26
+ <v-tabs-window v-model="tab">
27
+ <v-tabs-window-item value="one">
28
+ <v-row style="padding-top: 15px;">
29
+ <v-col cols="6" v-for="(stations, index) in stations" :key="index">
30
+ <station :radio="stations" />
31
+ </v-col>
32
+ </v-row>
33
+ </v-tabs-window-item>
34
+
35
+ <v-tabs-window-item value="two">
36
+ <v-row style="padding-top: 15px;">
37
+ <v-col cols="6" v-for="(stations, index) in livestations" :key="index">
38
+ <station :radio="stations" />
39
+ </v-col>
40
+ </v-row>
41
+ </v-tabs-window-item>
42
+
43
+ <v-tabs-window-item value="three">
44
+ <v-row style="padding-top: 15px;">
45
+ <v-col cols="6" v-for="(stations, index) in mystations" :key="index">
46
+ <station :radio="stations" />
47
+ </v-col>
48
+ </v-row>
49
+ </v-tabs-window-item>
50
+ </v-tabs-window>
51
+ </v-card-text>
52
+ </v-card>
53
+
54
+ </div>
55
+ </template>
56
+
57
+ <script setup>
58
+ import station from '../../../../commerce/app/components/catalog/product/radiostation.vue'
59
+ import createstation from '../../../../commerce/app/components/catalog/product/add-station.vue'
60
+ import { ref } from 'vue'
61
+ import {
62
+ useUserStore
63
+ } from '../../../../auth/app/stores/user'
64
+
65
+ const userStore = useUserStore()
66
+
67
+ const tab = ref(null);
68
+ const {
69
+ $directus,
70
+ $readItems,
71
+ $readItem
72
+ } = useNuxtApp()
73
+
74
+ const userDisplayName = computed(() => {
75
+ return userStore.user?.name || userStore.user?.username || 'User'
76
+ })
77
+
78
+ const {
79
+ data: stations
80
+ } = await useAsyncData('stations', () => {
81
+ return $directus.request($readItems('radios', {
82
+ fields: ['*', { '*': ['*'] }]
83
+ }))
84
+ })
85
+
86
+ const {
87
+ data: livestations
88
+ } = await useAsyncData('livestations', () => {
89
+ return $directus.request($readItems('radios', {
90
+ filter: {
91
+ type: {
92
+ _eq: "Live"
93
+ }
94
+ },
95
+ fields: ['*', { '*': ['*'] }]
96
+ }))
97
+ })
98
+
99
+ const {
100
+ data: mystations
101
+ } = await useAsyncData('mystations', () => {
102
+ return $directus.request($readItems('radios', {
103
+ filter: {
104
+ creator: {
105
+ _eq: `${userDisplayName.value}`
106
+ }
107
+ }
108
+ }))
109
+ })
110
+
111
+ const {
112
+ data: stationbar
113
+ } = await useAsyncData('stationbar', () => {
114
+ return $directus.request($readItem('navigation', '34'))
115
+ })
116
+
117
+ definePageMeta({
118
+ middleware: ['authenticated'],
119
+ })
120
+
121
+ useHead({
122
+ title: 'Radio Stations',
123
+ })
124
+ </script>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <div>
3
+ <h1 class="mbr-section-title mbr-fonts-style mbr-white mb-3 display-1" id="dateTime">
4
+ </h1>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup>
9
+ import {
10
+ onMounted,
11
+ onUnmounted
12
+ } from 'vue';
13
+ const {
14
+ $directus,
15
+ $readItem
16
+ } = useNuxtApp()
17
+
18
+ const {
19
+ data: department
20
+ } = await useAsyncData('department', () => {
21
+ return $directus.request($readItem('departments', '68', {
22
+ fields: ['*', '*', '*']
23
+ }))
24
+ })
25
+
26
+ let intervalId;
27
+
28
+ const updateDateTime = () => {
29
+ const months = [
30
+ "January", "February", "March", "April", "May", "June", "July",
31
+ "August", "September", "October", "November", "December"
32
+ ];
33
+ const date = new Date();
34
+ const monthName = months[date.getMonth()];
35
+ const formattedDate = date.toLocaleString();
36
+
37
+ const dateTimeElement = document.getElementById("dateTime");
38
+ if (dateTimeElement) {
39
+ dateTimeElement.innerHTML = `${monthName} ${formattedDate}`;
40
+ }
41
+ };
42
+
43
+ onMounted(() => {
44
+ updateDateTime(); // Initial update
45
+ intervalId = setInterval(updateDateTime, 1000);
46
+ });
47
+
48
+ onUnmounted(() => {
49
+ if (intervalId) {
50
+ clearInterval(intervalId);
51
+ }
52
+ });
53
+
54
+ const props = defineProps({
55
+ category: {
56
+ type: String,
57
+ required: true,
58
+ },
59
+ });
60
+ const {
61
+ category
62
+ } = props;
63
+ </script>
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <div>
3
+ <div id="map" style="height: 400px;"></div>
4
+ <p v-if="locationError">{{ locationError }}</p>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup>
9
+ import {
10
+ onMounted,
11
+ ref
12
+ } from 'vue';
13
+
14
+ const props = defineProps({
15
+ category: {
16
+ type: String,
17
+ required: true,
18
+ },
19
+ });
20
+
21
+ const mapInstance = ref(null);
22
+ const locationError = ref(null);
23
+
24
+ onMounted(() => {
25
+ import('leaflet').then((L) => {
26
+ // Create the map with a default view
27
+ mapInstance.value = L.map('map').setView([0, 0], 2);
28
+
29
+ // Add the tile layer
30
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
31
+ attribution: '&copy; <NuxtLink to="https://www.openstreetmap.org/">OpenStreetMap</NuxtLink> contributors',
32
+ maxZoom: 18,
33
+ }).addTo(mapInstance.value);
34
+
35
+ // Try to get the user's location
36
+ if ("geolocation" in navigator) {
37
+ navigator.geolocation.getCurrentPosition(
38
+ (position) => {
39
+ const {
40
+ latitude,
41
+ longitude
42
+ } = position.coords;
43
+ mapInstance.value.setView([latitude, longitude], 13);
44
+
45
+ // Add a marker at the user's location
46
+ L.marker([latitude, longitude])
47
+ .addTo(mapInstance.value)
48
+ .bindPopup('You are here!')
49
+ .openPopup();
50
+ },
51
+ (error) => {
52
+ console.error("Error getting location:", error.message);
53
+ locationError.value =
54
+ `Unable to get your location: ${error.message}. Using default view.`;
55
+ // Fallback to a default location (e.g., New York City)
56
+ mapInstance.value.setView([40.7128, -74.0060], 13);
57
+ }, {
58
+ enableHighAccuracy: true,
59
+ timeout: 10000, // Increased timeout to 10 seconds
60
+ maximumAge: 0
61
+ }
62
+ );
63
+ } else {
64
+ locationError.value =
65
+ "Geolocation is not supported by this browser. Using default view.";
66
+ // Fallback to a default location
67
+ mapInstance.value.setView([40.7128, -74.0060], 13);
68
+ }
69
+ });
70
+ });
71
+ </script>
72
+
73
+ <style>
74
+ @import 'leaflet/dist/leaflet.css';
75
+ </style>
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <div>
3
+ <div id="ww_5134399f73857" v='1.3' loc='auto' a='{"t":"responsive","lang":"en","sl_lpl":1,"ids":[],"font":"Arial","sl_ics":"one_a","sl_sot":"celsius","cl_bkg":"image","cl_font":"#FFFFFF","cl_cloud":"#FFFFFF","cl_persp":"#81D4FA","cl_sun":"#FFC107","cl_moon":"#FFC107","cl_thund":"#FF5722","cl_odd":"#0000000a"}'>Weather Data Source: <NuxtLink href="https://wetterlang.de" id="ww_5134399f73857_u" target="_blank">Wetter vorhersage 30 tage</NuxtLink></div>
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ import {
9
+ onMounted,
10
+ ref
11
+ } from 'vue'
12
+
13
+ const widgetId = 'ww_5134399f73857'
14
+
15
+ const loadExternalScript = (src) => {
16
+ return new Promise((resolve, reject) => {
17
+ const script = document.createElement('script')
18
+ script.type = 'text/javascript';
19
+ script.src = src
20
+ script.async = true
21
+ script.onload = resolve
22
+ document.head.appendChild(script)
23
+ })
24
+ }
25
+
26
+ onMounted(async () => {
27
+ try {
28
+ await loadExternalScript(`https://app3.weatherwidget.org/js/?id=${widgetId}`)
29
+ // You may need a delay to allow the widget script to initialize
30
+ setTimeout(() => {
31
+ // Check if additional initialization is needed here
32
+ }, 100)
33
+ } catch (error) {
34
+ console.error('Failed to load weather widget script:', error)
35
+ }
36
+ })
37
+
38
+ const props = defineProps({
39
+ category: {
40
+ type: String,
41
+ required: true,
42
+ },
43
+ });
44
+ </script>
@@ -35,7 +35,7 @@
35
35
 
36
36
  <script setup>
37
37
  import createshowcase from '@/components/catalog/product/add-showcase.vue'
38
- import listShowcases from '#lists/app/components/related/list.vue'
38
+ import listShowcases from '@/components/placeholders/ListShowcases.vue'
39
39
 
40
40
  const {
41
41
  $directus,
@@ -47,7 +47,8 @@
47
47
  import productCard from '~/components/catalog/product/productCard.vue'
48
48
  import {
49
49
  ref,
50
- onMounted
50
+ onMounted,
51
+ computed
51
52
  } from 'vue';
52
53
  import {
53
54
  useUserStore
@@ -60,61 +61,35 @@
60
61
  return userStore.name || userStore.username || 'User'
61
62
  })
62
63
 
63
- const {
64
- $directus,
65
- $readItems,
66
- $readItem
67
- } = useNuxtApp()
64
+ const { $commerce } = useNuxtApp()
65
+ import { useCatalogFallback } from '../../../composables/useCatalog'
66
+ const catalog = useCatalogFallback()
68
67
 
69
68
  const {
70
69
  data: cards
71
- } = await useAsyncData('cards', () => {
72
- return $directus.request($readItems('products', {
73
- fields: ['*',
74
- 'image.*',
75
- 'currency.currency_id.*'
76
- ],
77
- filter: {
78
- product_types: {
79
- product_types_id: {
80
- name: {
81
- _eq: "Gift Card"
82
- }
83
- }
84
- }
85
- }
86
- }))
70
+ } = await useAsyncData('cards', async () => {
71
+ return await catalog.listProducts({
72
+ fields: ['*', 'image.*', 'currency.currency_id.*'],
73
+ filter: { product_types: { product_types_id: { name: { _eq: 'Gift Card' } } } }
74
+ })
87
75
  })
88
76
 
89
77
  const {
90
78
  data: mycards
91
- } = await useAsyncData('mycards', () => {
92
- return $directus.request($readItems('products', {
93
- fields: ['*',
94
- 'image.*',
95
- 'currency.currency_id.*'
96
- ],
97
- filter: {
98
- product_types: {
99
- product_types_id: {
100
- name: {
101
- _eq: "Gift Card"
102
- }
103
- }
104
- },
105
- user: {
106
- directus_users: {
107
- _eq: `${userDisplayName.user.displayName}`
108
- }
109
- }
110
- }
111
- }))
79
+ } = await useAsyncData('mycards', async () => {
80
+ // user-specific filtering may not map directly to adapters; fall back handled by composable
81
+ return await catalog.listProducts({
82
+ fields: ['*', 'image.*', 'currency.currency_id.*'],
83
+ filter: { product_types: { product_types_id: { name: { _eq: 'Gift Card' } } }, user: { directus_users: { _eq: `${userDisplayName.user.displayName}` } } }
84
+ })
112
85
  })
113
86
 
114
87
  const {
115
88
  data: callouts
116
- } = await useAsyncData('callouts', () => {
117
- return $directus.request($readItem('callouts', '4'))
89
+ } = await useAsyncData('callouts', async () => {
90
+ // callouts remain stored in Directus; use Nuxt runtime for these CMS pieces
91
+ const nuxtApp = useNuxtApp() as any
92
+ return nuxtApp.$directus ? await nuxtApp.$directus.request(nuxtApp.$readItem('callouts', '4')) : null
118
93
  })
119
94
 
120
95
  useHead({