@studio-fes/layer-strapi 0.1.2 → 0.1.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @studio-fes/layer-strapi
2
2
 
3
+ ## 0.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Add Video and Media component to render image or video based on context, update useStrapiSEO
8
+
3
9
  ## 0.1.2
4
10
 
5
11
  ### Patch Changes
@@ -2,13 +2,13 @@
2
2
  import type { NuxtImgProps } from '@studio-fes/layer-base/app/components/Image.vue'
3
3
  import type { StrapiFileFragment } from '~/types/graphql-operations'
4
4
 
5
- interface CraftImageProps {
5
+ export interface StrapiImageProps extends NuxtImgProps {
6
6
  image?: StrapiFileFragment
7
7
  }
8
8
 
9
- const props = defineProps<NuxtImgProps & CraftImageProps>()
9
+ const props = defineProps<StrapiImageProps>()
10
10
  const imageProps = computed(() => ({
11
- ...props,
11
+ ...reactiveOmit(props, 'image'),
12
12
  ...parseStrapiImage(props.image),
13
13
  }))
14
14
  </script>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import type { StrapiImageProps } from '@studio-fes/layer-strapi/app/components/StrapiImage.vue'
3
+ import type { StrapiVideoProps } from '~/components/StrapiVideo.vue'
4
+ import type { StrapiFileFragment } from '~/types/graphql-operations'
5
+
6
+ const props = defineProps<{
7
+ media: StrapiFileFragment
8
+ imgProps?: StrapiImageProps
9
+ videoProps?: StrapiVideoProps
10
+ }>()
11
+
12
+ const isVideo = computed(() => !mediaIsImage(props.media))
13
+ const isImage = computed(() => mediaIsImage(props.media))
14
+ </script>
15
+
16
+ <template>
17
+ <StrapiImage
18
+ v-if="isImage"
19
+ v-bind="imgProps"
20
+ :image="media"
21
+ />
22
+ <StrapiVideo
23
+ v-else-if="isVideo"
24
+ v-bind="videoProps"
25
+ :video="media"
26
+ >
27
+ <template #default="{ progress, isPlaying }">
28
+ <slot name="media-chrome" :progress :is-playing />
29
+ </template>
30
+ </StrapiVideo>
31
+ <pre v-else>There is no format for you.</pre>
32
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ import type { VideoProps } from '@studio-fes/layer-base/app/components/Video.vue'
3
+ import type { StrapiFileFragment } from '~/types/graphql-operations'
4
+ import Video from '@studio-fes/layer-base/app/components/Video.vue'
5
+
6
+ export interface StrapiVideoProps extends VideoProps {
7
+ video?: StrapiFileFragment
8
+ }
9
+
10
+ const props = defineProps<StrapiVideoProps>()
11
+
12
+ const videoProps = computed(() => ({
13
+ ...reactiveOmit(props, 'video'),
14
+ ...parseStrapiVideo(props.video),
15
+ }))
16
+ </script>
17
+
18
+ <template>
19
+ <Video
20
+ v-if="videoProps"
21
+ v-bind="videoProps"
22
+ >
23
+ <template #default="{ progress, isPlaying }">
24
+ <slot :progress :is-playing />
25
+ </template>
26
+ </Video>
27
+ </template>
@@ -1,37 +1,15 @@
1
- import type { MetaSocialFragment, SeoMetaFragment } from '~/types/graphql-operations'
1
+ import type { SeoMetaFragment } from '~/types/graphql-operations'
2
2
 
3
3
  export function useStrapiSEO(seoData?: MaybeRefOrGetter<SeoMetaFragment>) {
4
4
  const nuxtApp = useNuxtApp()
5
5
  const runtimeConfig = useRuntimeConfig()
6
+ const nuxtImage = useImage()
6
7
 
7
8
  const seo = computed(() => {
8
9
  if (!seoData)
9
10
  return {}
10
11
 
11
- const { metaTitle, metaDescription, metaImage, metaSocial, metaRobots, keywords } = toValue(seoData)
12
-
13
- const metaSocials = (metaSocial as MetaSocialFragment[]).map((social: MetaSocialFragment) => {
14
- let key = null
15
-
16
- switch (social.socialNetwork) {
17
- case 'Facebook':
18
- key = 'og'
19
- break
20
- case 'Twitter':
21
- key = 'twitter'
22
- break
23
- }
24
-
25
- if (!key)
26
- return []
27
-
28
- return [
29
- { property: `${key}:title`, content: social.title || metaTitle },
30
- { property: `${key}:description`, content: social.description || metaDescription },
31
- { property: `${key}:image`, content: runtimeConfig.public.imageDomain + (social.image || metaImage)?.url },
32
- { property: `${key}:image:alt`, content: (social.image || metaImage)?.alternativeText || metaTitle },
33
- ]
34
- })
12
+ const { metaTitle, metaDescription, metaImage, openGraph, metaRobots, keywords } = toValue(seoData)
35
13
 
36
14
  return {
37
15
  title: metaTitle,
@@ -39,8 +17,11 @@ export function useStrapiSEO(seoData?: MaybeRefOrGetter<SeoMetaFragment>) {
39
17
  { name: 'description', content: metaDescription },
40
18
  { name: 'robots', content: metaRobots },
41
19
  { name: 'keywords', content: keywords },
20
+ { property: `og:title`, content: openGraph?.ogTitle || metaTitle },
21
+ { property: `og:description`, content: openGraph?.ogDescription || metaDescription },
22
+ { property: `og:image`, content: nuxtImage(runtimeConfig.public.imageDomain + (openGraph?.ogImage || metaImage)?.url, { width: 1200, height: 630, quality: 60 }) },
23
+ { property: `og:image:alt`, content: (openGraph?.ogImage || metaImage)?.alternativeText || metaTitle },
42
24
  { property: 'twitter:card', content: 'summary_large_image' },
43
- ...metaSocials.flat(),
44
25
  ],
45
26
  }
46
27
  })
@@ -36,8 +36,8 @@ export interface EntryInterfaceTypeFragment {
36
36
  * metaImage {
37
37
  * ...StrapiFile
38
38
  * }
39
- * metaSocial {
40
- * ...MetaSocial
39
+ * openGraph {
40
+ * ...OpenGraph
41
41
  * }
42
42
  * keywords
43
43
  * metaRobots
@@ -52,14 +52,37 @@ export interface SeoMetaFragment {
52
52
  id: string | number
53
53
  keywords?: string
54
54
  metaDescription: string
55
- metaImage: StrapiFileFragment
55
+ metaImage?: StrapiFileFragment
56
56
  metaRobots?: string
57
- metaSocial?: (MetaSocialFragment | null)[]
58
57
  metaTitle: string
59
58
  metaViewport?: string
59
+ openGraph?: OpenGraphFragment
60
60
  structuredData?: any
61
61
  }
62
62
 
63
+ /**
64
+ *
65
+ * @example
66
+ * ```graphql
67
+ * fragment OpenGraph on ComponentSharedOpenGraph {
68
+ * ogTitle
69
+ * ogDescription
70
+ * ogImage {
71
+ * ...StrapiFile
72
+ * }
73
+ * ogUrl
74
+ * ogType
75
+ * }
76
+ * ```
77
+ */
78
+ export interface OpenGraphFragment {
79
+ ogDescription: string
80
+ ogImage?: StrapiFileFragment
81
+ ogTitle: string
82
+ ogType?: string
83
+ ogUrl?: string
84
+ }
85
+
63
86
  /**
64
87
  *
65
88
  * @example
@@ -82,26 +105,3 @@ export interface StrapiFileFragment {
82
105
  url: string
83
106
  width?: number
84
107
  }
85
-
86
- /**
87
- *
88
- * @example
89
- * ```graphql
90
- * fragment MetaSocial on ComponentSharedMetaSocial {
91
- * description
92
- * id
93
- * socialNetwork
94
- * title
95
- * image {
96
- * ...StrapiFile
97
- * }
98
- * }
99
- * ```
100
- */
101
- export interface MetaSocialFragment {
102
- description: string
103
- id: string | number
104
- image?: StrapiFileFragment
105
- socialNetwork: EnumComponentsharedmetasocialSocialnetwork
106
- title: string
107
- }
@@ -16,8 +16,8 @@ export function throw404(
16
16
  message: string = 'Page Not Found.',
17
17
  ): never {
18
18
  throw createError({
19
- statusCode: 404,
20
- statusMessage: message,
19
+ status: 404,
20
+ statusText: message,
21
21
  fatal: true,
22
22
  })
23
23
  }
@@ -33,8 +33,8 @@ export function throw500(
33
33
  message: string = 'Server Error',
34
34
  ): never {
35
35
  throw createError({
36
- statusCode: 500,
37
- statusMessage: message,
36
+ status: 500,
37
+ statusText: message,
38
38
  fatal: true,
39
39
  })
40
40
  }
@@ -67,7 +67,7 @@ export function checkPageData(response: Awaited<ReturnType<typeof useAsyncData<G
67
67
  throw500('No data returned from the server.')
68
68
  }
69
69
  if (response.error.value || response.data.value?.errors?.length) {
70
- throw500(response.error.value?.statusMessage || response.error.value?.message || response.data.value?.errors?.map((e: any) => e.message).join(', ') || 'Unknown error occurred.')
70
+ throw500(response.error.value?.statusText || response.error.value?.message || response.data.value?.errors?.map((e: any) => e.message).join(', ') || 'Unknown error occurred.')
71
71
  }
72
72
 
73
73
  if (!response.data.value?.data) {
@@ -14,12 +14,10 @@ export function parseStrapiImage(image: StrapiFileFragment | undefined): NuxtImg
14
14
  height,
15
15
  src: runtimeConfig.public.imageDomain + src,
16
16
  alt,
17
- format: 'webp',
18
17
  } as {
19
18
  width: number
20
19
  height: number
21
20
  src: string
22
21
  alt: string
23
- format?: string
24
22
  }
25
23
  }
@@ -0,0 +1,17 @@
1
+ import type { VideoProps } from '@studio-fes/layer-base/app/components/Video.vue'
2
+ import type { StrapiFileFragment } from '~/types/graphql-operations'
3
+
4
+ export function parseStrapiVideo(video: StrapiFileFragment | null | undefined): VideoProps {
5
+ if (!video)
6
+ return {}
7
+
8
+ const runtimeConfig = useRuntimeConfig()
9
+ const id = useState(() => uuidv4())
10
+
11
+ return {
12
+ id: `video-${id.value}`,
13
+ src: runtimeConfig.public.imageDomain + video.url,
14
+ width: video.width,
15
+ height: video.height,
16
+ }
17
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@studio-fes/layer-strapi",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "main": "./nuxt.config.ts",
6
6
  "scripts": {
7
7
  "dev": "nuxi dev",
@@ -20,9 +20,9 @@
20
20
  },
21
21
  "devDependencies": {
22
22
  "@studio-fes/layer-base": "workspace:*",
23
- "@types/node": "^25.1.0",
24
- "eslint": "^9.39.2",
25
- "nuxt": "^4.3.0",
23
+ "@types/node": "^25.2.3",
24
+ "eslint": "^10.0.0",
25
+ "nuxt": "^4.3.1",
26
26
  "typescript": "^5.9.3",
27
27
  "vue": "latest"
28
28
  },