@iqual/nuxt-icms 1.0.12 → 1.0.14
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/components/Media/Image/index.vue +1 -1
- package/components/Media/RemoteVideo/index.vue +18 -11
- package/components/Media/Video/index.vue +6 -4
- package/components/Paragraph/Media/index.vue +13 -8
- package/package.json +1 -1
- package/server/graphqlMiddleware.serverOptions.ts +3 -3
- package/tests/pages.spec.ts +101 -0
- package/vitest.config.mts +2 -2
- package/pages/__tests__/index.ts +0 -77
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
>
|
|
19
19
|
<img
|
|
20
20
|
:src="thumbnailUrl"
|
|
21
|
-
class="absolute left-0 top-0 size-full object-cover
|
|
21
|
+
class="absolute left-0 top-0 aspect-video size-full object-cover"
|
|
22
22
|
:class="elementClass"
|
|
23
23
|
:alt="thumbnailAlt"
|
|
24
24
|
/>
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
<SpriteSymbol name="play" class="z-10 size-[75px]" />
|
|
27
27
|
</button>
|
|
28
28
|
|
|
29
|
-
<figcaption
|
|
30
|
-
v-
|
|
31
|
-
|
|
29
|
+
<figcaption
|
|
30
|
+
v-if="showCaption && media?.caption"
|
|
31
|
+
v-text="media?.caption"
|
|
32
|
+
:class="figcaptionClass"
|
|
33
|
+
/>
|
|
32
34
|
</figure>
|
|
33
35
|
</VuepalRemoteVideo>
|
|
34
36
|
</template>
|
|
@@ -36,13 +38,18 @@
|
|
|
36
38
|
<script lang="ts" setup>
|
|
37
39
|
import type { MediaRemoteVideoFragment } from '#graphql-operations'
|
|
38
40
|
|
|
39
|
-
const props =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
const props = withDefaults(
|
|
42
|
+
defineProps<{
|
|
43
|
+
media: MediaRemoteVideoFragment
|
|
44
|
+
mediaClass?: string
|
|
45
|
+
elementClass?: string
|
|
46
|
+
showCaption?: boolean
|
|
47
|
+
figcaptionClass?: string
|
|
48
|
+
}>(),
|
|
49
|
+
{
|
|
50
|
+
figcaptionClass: 'mt-2 italic text-center',
|
|
51
|
+
},
|
|
52
|
+
)
|
|
46
53
|
|
|
47
54
|
const isPlaying = ref(false)
|
|
48
55
|
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
<source v-if="media?.url?.path" :src="media.url.path" type="video/mp4" />
|
|
13
13
|
Your browser does not support the video tag.
|
|
14
14
|
</video>
|
|
15
|
-
<figcaption
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
<figcaption
|
|
16
|
+
v-if="showCaption && media?.caption"
|
|
17
|
+
v-text="media?.caption"
|
|
18
|
+
:class="figcaptionClass"
|
|
19
|
+
/>
|
|
18
20
|
</figure>
|
|
19
21
|
</template>
|
|
20
22
|
|
|
21
23
|
<script lang="ts" setup>
|
|
22
|
-
|
|
23
24
|
import type { MediaVideoFragment } from '#graphql-operations'
|
|
24
25
|
|
|
25
26
|
withDefaults(
|
|
@@ -39,6 +40,7 @@ withDefaults(
|
|
|
39
40
|
videoMuted: true,
|
|
40
41
|
videoAutoplay: true,
|
|
41
42
|
videoLoop: false,
|
|
43
|
+
figcaptionClass: 'mt-2 italic text-center',
|
|
42
44
|
},
|
|
43
45
|
)
|
|
44
46
|
</script>
|
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
<div :class="rowClassList">
|
|
4
4
|
<div :class="columnClassList">
|
|
5
5
|
<DesignSystemMoleculesMediaSlider
|
|
6
|
-
v-if="media && media.length"
|
|
6
|
+
v-if="media && media.length > 1"
|
|
7
7
|
:media="media"
|
|
8
8
|
:colorScheme="colorScheme"
|
|
9
|
-
|
|
9
|
+
showCaption
|
|
10
10
|
:sliderClass="mediaSliderClassList"
|
|
11
11
|
:elementClass="mediaElementClassList"
|
|
12
|
-
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<Media
|
|
15
|
+
v-else-if="media && media.length === 1 && media[0]"
|
|
16
|
+
:media="media[0]"
|
|
17
|
+
imageSizes="xs:100vw sm:100vw md:100vw lg:1284px"
|
|
18
|
+
elementClass="rounded-lg"
|
|
19
|
+
showCaption
|
|
13
20
|
/>
|
|
14
21
|
</div>
|
|
15
22
|
</div>
|
|
@@ -17,14 +24,14 @@
|
|
|
17
24
|
</template>
|
|
18
25
|
|
|
19
26
|
<script lang="ts" setup>
|
|
20
|
-
import type {
|
|
27
|
+
import type { ParagraphIcmsLayoutMediaFragment } from '#graphql-operations'
|
|
21
28
|
|
|
22
|
-
defineProps<
|
|
29
|
+
defineProps<ParagraphIcmsLayoutMediaFragment>()
|
|
23
30
|
|
|
24
31
|
const { options, isEditing } = useAttrs().blokkliData
|
|
25
32
|
|
|
26
33
|
const mediaSliderClassList = computed(() => {
|
|
27
|
-
const classList = []
|
|
34
|
+
const classList = ['my-0']
|
|
28
35
|
if (options.value.width !== 'full') {
|
|
29
36
|
classList.push('rounded-lg overflow-hidden')
|
|
30
37
|
}
|
|
@@ -58,7 +65,6 @@ const rowClassList = computed(() => {
|
|
|
58
65
|
})
|
|
59
66
|
|
|
60
67
|
const imageSizes = computed(() => {
|
|
61
|
-
|
|
62
68
|
if (options.value.width === 'full') {
|
|
63
69
|
return 'xs:100vw sm:100vw md:100vw lg:100vw'
|
|
64
70
|
}
|
|
@@ -79,5 +85,4 @@ const columnClassList = computed(() => {
|
|
|
79
85
|
|
|
80
86
|
return classList
|
|
81
87
|
})
|
|
82
|
-
|
|
83
88
|
</script>
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineGraphqlServerOptions } from 'nuxt-graphql-middleware/server-options'
|
|
2
|
-
import { extractCacheability } from '
|
|
3
|
-
import type { GraphqlCacheability } from '
|
|
2
|
+
import { extractCacheability } from '@iqual/nuxt-icms/server/utils/cacheability'
|
|
3
|
+
import type { GraphqlCacheability } from '@iqual/nuxt-icms/server/helpers'
|
|
4
4
|
import { defaultLangcode, langcodes } from '#nuxt-language-negotiation/config'
|
|
5
|
-
import { buildProxyRequestHeaders } from '
|
|
5
|
+
import { buildProxyRequestHeaders } from '@iqual/nuxt-icms/server/helpers/request'
|
|
6
6
|
|
|
7
7
|
export default defineGraphqlServerOptions<{
|
|
8
8
|
extensions: {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { promises as fsp } from 'fs'
|
|
3
|
+
import { describe, it, expect } from 'vitest'
|
|
4
|
+
import * as ts from 'typescript'
|
|
5
|
+
import { parse as parseSfc } from '@vue/compiler-sfc'
|
|
6
|
+
|
|
7
|
+
// Recursively find all Vue files in a directory
|
|
8
|
+
async function findVueFiles(
|
|
9
|
+
dir: string,
|
|
10
|
+
ignorePatterns: string[] = [],
|
|
11
|
+
): Promise<string[]> {
|
|
12
|
+
const entries = await fsp.readdir(dir, { withFileTypes: true })
|
|
13
|
+
const files: string[] = []
|
|
14
|
+
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
const fullPath = path.join(dir, entry.name)
|
|
17
|
+
|
|
18
|
+
// Skip if path matches any ignore pattern
|
|
19
|
+
if (ignorePatterns.some((pattern) => fullPath.includes(pattern))) {
|
|
20
|
+
continue
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (entry.isDirectory()) {
|
|
24
|
+
const subFiles = await findVueFiles(fullPath, ignorePatterns)
|
|
25
|
+
files.push(...subFiles)
|
|
26
|
+
} else if (entry.name.endsWith('.vue')) {
|
|
27
|
+
files.push(fullPath)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return files
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Parse a Vue SFC and check if the component's script calls the given function at least once.
|
|
35
|
+
function functionIsCalledAtLeastOnce(
|
|
36
|
+
vueFileContents: string,
|
|
37
|
+
functionName: string,
|
|
38
|
+
): boolean {
|
|
39
|
+
const result = parseSfc(vueFileContents)
|
|
40
|
+
const script = result.descriptor.scriptSetup?.content
|
|
41
|
+
if (!script) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
const sourceFile = ts.createSourceFile(
|
|
45
|
+
'temp.ts',
|
|
46
|
+
script,
|
|
47
|
+
ts.ScriptTarget.ES2015,
|
|
48
|
+
true,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
let isCalled = false
|
|
52
|
+
|
|
53
|
+
function visit(node: ts.Node) {
|
|
54
|
+
if (
|
|
55
|
+
ts.isCallExpression(node) &&
|
|
56
|
+
node.expression.getText(sourceFile) === functionName
|
|
57
|
+
) {
|
|
58
|
+
isCalled = true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!isCalled) {
|
|
62
|
+
ts.forEachChild(node, visit)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ts.forEachChild(sourceFile, visit)
|
|
67
|
+
|
|
68
|
+
return isCalled
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe('The Nuxt page component', async () => {
|
|
72
|
+
const rootDir = path.resolve(__dirname, './../app/pages')
|
|
73
|
+
const ignorePatterns = ['blokkli']
|
|
74
|
+
|
|
75
|
+
const pageFilePaths = await findVueFiles(rootDir, ignorePatterns)
|
|
76
|
+
console.log(pageFilePaths)
|
|
77
|
+
|
|
78
|
+
const pageComponentFiles = await Promise.all(
|
|
79
|
+
pageFilePaths.map((filePath) => {
|
|
80
|
+
return fsp.readFile(filePath, { encoding: 'utf8' }).then((content) => {
|
|
81
|
+
return {
|
|
82
|
+
filePath,
|
|
83
|
+
content,
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
}),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
pageComponentFiles.forEach(({ filePath, content }) => {
|
|
90
|
+
it(`"${filePath}" should call useDrupalRouteQuery()`, () => {
|
|
91
|
+
expect(
|
|
92
|
+
functionIsCalledAtLeastOnce(content, 'useDrupalRouteQuery'),
|
|
93
|
+
).toEqual(true)
|
|
94
|
+
})
|
|
95
|
+
it(`"${filePath}" should call renderPageDependencies()`, () => {
|
|
96
|
+
expect(
|
|
97
|
+
functionIsCalledAtLeastOnce(content, 'renderPageDependencies'),
|
|
98
|
+
).toEqual(true)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
})
|
package/vitest.config.mts
CHANGED
|
@@ -6,9 +6,9 @@ export default defineVitestConfig({
|
|
|
6
6
|
globals: true,
|
|
7
7
|
environment: 'nuxt',
|
|
8
8
|
alias: {
|
|
9
|
-
'~': path.resolve(__dirname, './'),
|
|
9
|
+
'~': path.resolve(__dirname, './app'),
|
|
10
|
+
'~~': path.resolve(__dirname, './'),
|
|
10
11
|
},
|
|
11
|
-
include: ['**/__tests__/*.*'],
|
|
12
12
|
coverage: {
|
|
13
13
|
all: true,
|
|
14
14
|
provider: 'v8',
|
package/pages/__tests__/index.ts
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import { promises as fsp } from 'fs'
|
|
3
|
-
import { describe, it, expect } from 'vitest'
|
|
4
|
-
import { glob } from 'glob'
|
|
5
|
-
import * as ts from 'typescript'
|
|
6
|
-
import { parse as parseSfc } from '@vue/compiler-sfc'
|
|
7
|
-
|
|
8
|
-
// Parse a Vue SFC and check if the component's script calls the given function at least once.
|
|
9
|
-
function functionIsCalledAtLeastOnce(
|
|
10
|
-
vueFileContents: string,
|
|
11
|
-
functionName: string,
|
|
12
|
-
): boolean {
|
|
13
|
-
const result = parseSfc(vueFileContents)
|
|
14
|
-
const script = result.descriptor.scriptSetup?.content
|
|
15
|
-
if (!script) {
|
|
16
|
-
return false
|
|
17
|
-
}
|
|
18
|
-
const sourceFile = ts.createSourceFile(
|
|
19
|
-
'temp.ts',
|
|
20
|
-
script,
|
|
21
|
-
ts.ScriptTarget.ES2015,
|
|
22
|
-
true,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
let isCalled = false
|
|
26
|
-
|
|
27
|
-
function visit(node: ts.Node) {
|
|
28
|
-
if (
|
|
29
|
-
ts.isCallExpression(node) &&
|
|
30
|
-
node.expression.getText(sourceFile) === functionName
|
|
31
|
-
) {
|
|
32
|
-
isCalled = true
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!isCalled) {
|
|
36
|
-
ts.forEachChild(node, visit)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
ts.forEachChild(sourceFile, visit)
|
|
41
|
-
|
|
42
|
-
return isCalled
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
describe('The Nuxt page component', async () => {
|
|
46
|
-
const pageComponentFiles = await glob(
|
|
47
|
-
path.resolve(__dirname, './../**/*.vue'),
|
|
48
|
-
{},
|
|
49
|
-
).then((pageFilePaths) => {
|
|
50
|
-
console.log(pageFilePaths)
|
|
51
|
-
return Promise.all(
|
|
52
|
-
pageFilePaths.map((filePath) => {
|
|
53
|
-
return fsp.readFile(filePath, { encoding: 'utf8' }).then((content) => {
|
|
54
|
-
return {
|
|
55
|
-
filePath,
|
|
56
|
-
content,
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
}),
|
|
60
|
-
)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
pageComponentFiles.forEach(({ filePath, content }) => {
|
|
64
|
-
it(`"${filePath}" should call useDrupalRouteQuery()`, () => {
|
|
65
|
-
expect(functionIsCalledAtLeastOnce(content, 'useDrupalRoute')).toEqual(
|
|
66
|
-
true,
|
|
67
|
-
)
|
|
68
|
-
})
|
|
69
|
-
it(`"${filePath}" should call setBreadcrumbLinksFromRoute()`, () => {
|
|
70
|
-
expect(
|
|
71
|
-
functionIsCalledAtLeastOnce(content, 'setBreadcrumbLinksFromRoute') ||
|
|
72
|
-
functionIsCalledAtLeastOnce(content, 'setBreadcrumbLinks') ||
|
|
73
|
-
functionIsCalledAtLeastOnce(content, 'useDrupalRoute'),
|
|
74
|
-
).toEqual(true)
|
|
75
|
-
})
|
|
76
|
-
})
|
|
77
|
-
})
|