srcdev-nuxt-components 9.1.35 → 9.1.37

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.
@@ -18,36 +18,13 @@
18
18
  "Bash(git show:*)",
19
19
  "Edit(/.claude/skills/components/**)",
20
20
  "Bash(npx nuxi:*)",
21
- "Bash(node -e \"const t = require\\('/Users/simoncornforth/websites/nuxt-components/node_modules/pinia-plugin-persistedstate'\\); console.log\\(Object.keys\\(t\\)\\)\")",
22
21
  "Bash(npx vue-tsc:*)",
23
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -5)",
24
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 16ac4ef --stat)",
25
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -8)",
26
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 5597a15 --stat)",
27
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 5597a15 -- \"*.vue\" \"*.css\")",
28
22
  "Bash(npm install:*)",
29
23
  "Bash(npm run:*)",
30
24
  "Bash(git add:*)",
31
- "Bash(ls /Users/simoncornforth/websites/nuxt-components/*.md)",
32
25
  "Bash(gh release:*)",
33
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components status)",
34
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components add .claude/skills/components/services-section.md .claude/skills/components/services-section-grid.md .claude/skills/index.md app/components/03.organisms/services/services-grids/ServicesSectionGrid.vue app/components/03.organisms/services/services-section/ServicesSection.vue app/components/03.organisms/services/services-card/stories/ app/components/03.organisms/services/services-card/tests/ app/components/03.organisms/services/services-grids/stories/ app/components/03.organisms/services/services-grids/tests/ app/components/03.organisms/services/services-section/stories/ app/components/03.organisms/services/services-section/tests/)",
35
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components commit -m ':*)",
36
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline v9.1.22..HEAD)",
37
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline c401cea..HEAD)",
38
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 3058d63 --stat)",
39
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 0f99d7a --stat)",
40
26
  "Bash(node -e ':*)"
41
27
  ],
42
- "additionalDirectories": [
43
- "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/content-wrappers/content-width",
44
- "/Users/simoncornforth/websites/nuxt-components/.claude/skills",
45
- "/Users/simoncornforth/websites/nuxt-components/app/components/02.molecules/navigation/site-navigation/tests",
46
- "/Users/simoncornforth/websites/luxury-locs-by-natasha-nuxt3/app/pages",
47
- "/Users/simoncornforth/websites/nuxt-components/app/assets/styles/extends-layer",
48
- "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms",
49
- "/private/tmp",
50
- "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/banner-video"
51
- ]
28
+ "additionalDirectories": []
52
29
  }
53
30
  }
@@ -7,7 +7,35 @@
7
7
  "Bash(grep '\"\"typescript\"\"' package.json)",
8
8
  "Bash(grep '\"\"@vue/language-server\\\\|@volar\\\\|vue-tsc\"\"' package.json)",
9
9
  "Bash(npx nuxi prepare)",
10
- "Bash(ls -la /Users/simoncornforth/websites/luxury-locs-by-natasha-nuxt3/.env*)"
10
+ "Bash(ls -la /Users/simoncornforth/websites/luxury-locs-by-natasha-nuxt3/.env*)",
11
+ "Bash(node -e \"const t = require\\('/Users/simoncornforth/websites/nuxt-components/node_modules/pinia-plugin-persistedstate'\\); console.log\\(Object.keys\\(t\\)\\)\")",
12
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -5)",
13
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 16ac4ef --stat)",
14
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -8)",
15
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 5597a15 --stat)",
16
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 5597a15 -- \"*.vue\" \"*.css\")",
17
+ "Bash(ls /Users/simoncornforth/websites/nuxt-components/*.md)",
18
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components status)",
19
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components add .claude/skills/components/services-section.md .claude/skills/components/services-section-grid.md .claude/skills/index.md app/components/03.organisms/services/services-grids/ServicesSectionGrid.vue app/components/03.organisms/services/services-section/ServicesSection.vue app/components/03.organisms/services/services-card/stories/ app/components/03.organisms/services/services-card/tests/ app/components/03.organisms/services/services-grids/stories/ app/components/03.organisms/services/services-grids/tests/ app/components/03.organisms/services/services-section/stories/ app/components/03.organisms/services/services-section/tests/)",
20
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components commit -m ':*)",
21
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline v9.1.22..HEAD)",
22
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline c401cea..HEAD)",
23
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 3058d63 --stat)",
24
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 0f99d7a --stat)",
25
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components diff app/components/parallax/SectionParallax.vue)",
26
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components diff HEAD app/components/parallax/SectionParallax.vue)",
27
+ "Bash(git -C /Users/simoncornforth/websites/nuxt-components diff --cached)"
28
+ ],
29
+ "additionalDirectories": [
30
+ "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/content-wrappers/content-width",
31
+ "/Users/simoncornforth/websites/nuxt-components/.claude/skills",
32
+ "/Users/simoncornforth/websites/nuxt-components/.claude/skills/components",
33
+ "/Users/simoncornforth/websites/nuxt-components/app/components/02.molecules/navigation/site-navigation/tests",
34
+ "/Users/simoncornforth/websites/luxury-locs-by-natasha-nuxt3/app/pages",
35
+ "/Users/simoncornforth/websites/nuxt-components/app/assets/styles/extends-layer",
36
+ "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms",
37
+ "/private/tmp",
38
+ "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/banner-video"
11
39
  ]
12
40
  }
13
41
  }
@@ -0,0 +1,84 @@
1
+ # CaptureQrCode
2
+
3
+ Live camera QR code scanner. Streams the device camera, detects QR codes in real time, and displays the decoded results inline. Handles camera errors, page visibility changes, and route navigation — stopping media streams cleanly in all cases.
4
+
5
+ **File**: `app/components/02.molecules/qr-code/CaptureQrCode.vue`
6
+
7
+ ## Prerequisites
8
+
9
+ The `nuxt-qrcode` Nuxt module must be registered in the consuming app's `nuxt.config.ts`:
10
+
11
+ ```typescript
12
+ // nuxt.config.ts
13
+ export default defineNuxtConfig({
14
+ modules: ["nuxt-qrcode"],
15
+ });
16
+ ```
17
+
18
+ Camera access requires a secure context (HTTPS or localhost) and the user granting camera permission.
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root element |
25
+
26
+ ## CSS classes
27
+
28
+ | Class | Where | Description |
29
+ |-------|-------|-------------|
30
+ | `.capture-qr-stream` | root | always present |
31
+ | `.camera-stopped` | inner | shown when camera is off but no error |
32
+ | `.camera-error` | inner | shown when an error has occurred |
33
+ | `.scanned-results` | inner | shown when at least one code has been decoded |
34
+
35
+ ## Behaviour
36
+
37
+ - Camera starts automatically on mount (`state.cameraOn = true`)
38
+ - When the page becomes hidden (tab switch, minimize), the camera stops and media streams are released
39
+ - On route leave (`onBeforeRouteLeave`), the camera stops and streams are released
40
+ - On `<KeepAlive>` deactivate/activate, camera is stopped/restarted accordingly
41
+ - If the user denies camera permission or another error occurs, the `.camera-error` state is shown with the error message and a **Reset camera** button
42
+ - Detected QR codes replace the previous results — each scan is a fresh result set
43
+ - Results are displayed as a `<ul>` inside `.scanned-results`
44
+
45
+ ## Usage
46
+
47
+ Drop in where camera scanning is needed. No configuration required beyond the module being present:
48
+
49
+ ```vue
50
+ <CaptureQrCode />
51
+ ```
52
+
53
+ With styling:
54
+
55
+ ```vue
56
+ <CaptureQrCode style-class-passthrough="my-scanner" />
57
+ ```
58
+
59
+ ## CSS override
60
+
61
+ The root element is a square (`aspect-ratio: 1 / 1`) by default. Override in a consuming page or component:
62
+
63
+ ```css
64
+ .my-scanner.capture-qr-stream {
65
+ aspect-ratio: auto;
66
+ max-width: 40rem;
67
+ }
68
+
69
+ .my-scanner .camera-error {
70
+ padding: 1.6rem;
71
+ border-radius: 0.8rem;
72
+ background-color: var(--theme-surface-error);
73
+ }
74
+
75
+ .my-scanner .scanned-results {
76
+ margin-block-start: 1.6rem;
77
+ font-size: 1.4rem;
78
+ }
79
+ ```
80
+
81
+ ## Notes
82
+
83
+ - The component does not emit the detected values — results are rendered inline. To act on scan results in a parent, extend the component or use `nuxt-qrcode`'s `QrcodeStream` directly with `@detect`.
84
+ - Media streams are stopped via two strategies: via the `QrcodeStream` component ref and via a document-level `querySelectorAll("video")` sweep — the sweep acts as a safety net if the ref is unavailable.
@@ -0,0 +1,84 @@
1
+ # DecodeQrCode
2
+
3
+ QR code decoder for static images. Accepts images via file picker or drag-and-drop, decodes any QR codes found, and displays the results inline.
4
+
5
+ **File**: `app/components/02.molecules/qr-code/DecodeQrCode.vue`
6
+
7
+ ## Prerequisites
8
+
9
+ The `nuxt-qrcode` Nuxt module must be registered in the consuming app's `nuxt.config.ts`:
10
+
11
+ ```typescript
12
+ // nuxt.config.ts
13
+ export default defineNuxtConfig({
14
+ modules: ["nuxt-qrcode"],
15
+ });
16
+ ```
17
+
18
+ No camera permission is required — this component works entirely with uploaded or dropped image files.
19
+
20
+ ## Props
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root element |
25
+
26
+ ## CSS classes
27
+
28
+ | Class | Where | Description |
29
+ |-------|-------|-------------|
30
+ | `.decode-qr-code` | root | always present |
31
+ | `.qr-code-capture` | file input | the `QrcodeCapture` file-picker element |
32
+ | `.qr-code-dropzone` | drop zone | the `QrcodeDropZone` drag-and-drop area |
33
+ | `.scanned-results` | inner | shown when at least one code has been decoded |
34
+
35
+ ## Behaviour
36
+
37
+ - Two input methods are rendered side by side: a file picker (`.qr-code-capture`) and a drag-and-drop zone (`.qr-code-dropzone`)
38
+ - Both share the same `onDetect` handler — results are displayed in the same `.scanned-results` list regardless of input method
39
+ - Detected QR codes replace the previous results — each decode is a fresh result set
40
+ - If the decoded array is empty, `.scanned-results` is hidden
41
+ - The drop zone has a dashed border and minimum height by default — style with `.qr-code-dropzone` to customise
42
+
43
+ ## Usage
44
+
45
+ Drop in where image-based QR decoding is needed:
46
+
47
+ ```vue
48
+ <DecodeQrCode />
49
+ ```
50
+
51
+ With styling:
52
+
53
+ ```vue
54
+ <DecodeQrCode style-class-passthrough="my-decoder" />
55
+ ```
56
+
57
+ ## CSS override
58
+
59
+ ```css
60
+ .my-decoder.decode-qr-code {
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 1.6rem;
64
+ }
65
+
66
+ .my-decoder .qr-code-dropzone {
67
+ min-height: 12rem;
68
+ border-radius: 1rem;
69
+ border-color: var(--theme-input-border);
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ }
74
+
75
+ .my-decoder .scanned-results {
76
+ margin-block-start: 1.6rem;
77
+ font-size: 1.4rem;
78
+ }
79
+ ```
80
+
81
+ ## Notes
82
+
83
+ - Like `CaptureQrCode`, results are rendered inline and not emitted. To act on results in a parent, extend the component or use `nuxt-qrcode`'s `QrcodeCapture` / `QrcodeDropZone` primitives directly.
84
+ - The component renders both input methods unconditionally. If only one is needed, use the underlying `QrcodeCapture` or `QrcodeDropZone` primitives directly.
@@ -0,0 +1,64 @@
1
+ # DisplayQrCode
2
+
3
+ Renders a styled QR code SVG from a string value. Supports colour, size, corner radius, and pixel/marker shape variants.
4
+
5
+ **File**: `app/components/01.atoms/qr-code/DisplayQrCode.vue`
6
+
7
+ ## Props
8
+
9
+ | Prop | Type | Default | Description |
10
+ |------|------|---------|-------------|
11
+ | `qr-value` | `string` | required | The string to encode into the QR code |
12
+ | `variant` | `QrCodeVariant` | `{ inner: "default", marker: "default", pixel: "default" }` | Shape variants for inner markers, outer markers, and pixels |
13
+ | `radius` | `number` | `0` | Corner rounding applied to pixels/markers (0–1 scale) |
14
+ | `black-color` | `string` | `"currentColor"` | Colour for the dark modules |
15
+ | `white-color` | `string` | `"transparent"` | Colour for the light modules |
16
+ | `size` | `string` | `"256px"` | Width of the QR code (height matches via `aspect-ratio: 1 / 1`) |
17
+ | `style-class-passthrough` | `string \| string[]` | `[]` | Extra classes on the root element |
18
+
19
+ ### QrCodeVariant type
20
+
21
+ ```typescript
22
+ import type { QrCodeVariant } from "srcdev-nuxt-components/types/components";
23
+
24
+ // Each field accepts: "default" | "circle" | "rounded" | "dots" | "classy" | "classy-rounded"
25
+ const variant: QrCodeVariant = {
26
+ inner: "circle",
27
+ marker: "rounded",
28
+ pixel: "dots",
29
+ };
30
+ ```
31
+
32
+ ## CSS classes
33
+
34
+ | Class | Where | Description |
35
+ |-------|-------|-------------|
36
+ | `.display-qr-code` | root | always present |
37
+
38
+ ## Usage
39
+
40
+ Minimal — encodes a URL with default styling:
41
+
42
+ ```vue
43
+ <DisplayQrCode qr-value="https://example.com" />
44
+ ```
45
+
46
+ Custom size, colour, and rounded pixels:
47
+
48
+ ```vue
49
+ <DisplayQrCode
50
+ qr-value="https://example.com"
51
+ size="320px"
52
+ black-color="#1a1a2e"
53
+ white-color="#f5f5f5"
54
+ :radius="0.5"
55
+ :variant="{ inner: 'circle', marker: 'rounded', pixel: 'default' }"
56
+ />
57
+ ```
58
+
59
+ ## Notes
60
+
61
+ - The component renders directly as the `Qrcode` element from `nuxt-qrcode` — there is no wrapper `<div>`. The `.display-qr-code` class is applied to the `Qrcode` root, which renders as an `<svg>`.
62
+ - `size` is applied via CSS `v-bind()` — pass any valid CSS length value (`px`, `rem`, `%`, etc.).
63
+ - `black-color` defaults to `currentColor`, so the QR code inherits the surrounding text colour automatically unless overridden.
64
+ - `white-color` defaults to `transparent`, making the background of the QR code see-through by default.
@@ -71,7 +71,10 @@ Each skill is a single markdown file named `<area>-<task>.md`.
71
71
  ├── scroll-reveal-frame.md — ScrollRevealFrame: generic parallax clipping frame, slot API, image grid pattern, CSS tokens, browser support
72
72
  ├── scroll-reveal-image.md — ScrollRevealImage: single-image parallax reveal, focalX, imgWidth/imgHeight, responsive frame height
73
73
  ├── site-navigation.md — SiteNavigation: responsive nav with auto-collapse, burger menu, decorator indicators, CSS token API
74
- └── social-icons-list.md — SocialIconsList: data-driven social icon links, ISocialIcon type, logos: icon names, CSS tokens
74
+ ├── social-icons-list.md — SocialIconsList: data-driven social icon links, ISocialIcon type, logos: icon names, CSS tokens
75
+ ├── display-qr-code.md — DisplayQrCode: QR code SVG from a string value, colour/size/variant/radius props, currentColor default
76
+ ├── capture-qr-code.md — CaptureQrCode: live camera scanner, error state, visibility/route/KeepAlive lifecycle, media stream cleanup
77
+ └── decode-qr-code.md — DecodeQrCode: file picker + drag-and-drop image decoder, shared results list, CSS override points
75
78
  ```
76
79
 
77
80
  ## Skill file template
@@ -1,6 +1,5 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { mountSuspended } from "@nuxt/test-utils/runtime";
3
- import { nextTick } from "vue";
4
3
  import BannerVideo from "../BannerVideo.vue";
5
4
 
6
5
  const defaultProps = {
@@ -41,9 +40,9 @@ describe("BannerVideo", () => {
41
40
 
42
41
  // ─── Root element ────────────────────────────────────────────────────────
43
42
 
44
- it("renders a <section> as the root element by default", async () => {
43
+ it("renders a <div> as the root element by default", async () => {
45
44
  const wrapper = await mountSuspended(BannerVideo, { props: defaultProps });
46
- expect(wrapper.element.tagName).toBe("SECTION");
45
+ expect(wrapper.element.tagName).toBe("DIV");
47
46
  });
48
47
 
49
48
  it("renders the specified tag as root", async () => {
@@ -194,15 +193,12 @@ describe("BannerVideo", () => {
194
193
  expect(wrapper.attributes("data-depth")).toBe("md");
195
194
  });
196
195
 
197
- it.each(["xs", "sm", "md", "lg", "xl"] as const)(
198
- "sets data-depth to %s when depth prop is %s",
199
- async (depth) => {
200
- const wrapper = await mountSuspended(BannerVideo, {
201
- props: { ...defaultProps, depth },
202
- });
203
- expect(wrapper.attributes("data-depth")).toBe(depth);
204
- }
205
- );
196
+ it.each(["xs", "sm", "md", "lg", "xl"] as const)("sets data-depth to %s when depth prop is %s", async (depth) => {
197
+ const wrapper = await mountSuspended(BannerVideo, {
198
+ props: { ...defaultProps, depth },
199
+ });
200
+ expect(wrapper.attributes("data-depth")).toBe(depth);
201
+ });
206
202
 
207
203
  // ─── CSS custom properties ───────────────────────────────────────────────
208
204
 
@@ -261,7 +257,10 @@ describe("BannerVideo", () => {
261
257
  });
262
258
 
263
259
  it("reflects verticalPosition prop in --_align-self", async () => {
264
- for (const [prop, expected] of [["start", "start"], ["end", "end"]] as const) {
260
+ for (const [prop, expected] of [
261
+ ["start", "start"],
262
+ ["end", "end"],
263
+ ] as const) {
265
264
  const wrapper = await mountSuspended(BannerVideo, {
266
265
  props: { ...defaultProps, verticalPosition: prop },
267
266
  });
@@ -276,7 +275,10 @@ describe("BannerVideo", () => {
276
275
  });
277
276
 
278
277
  it("reflects horizontalPosition prop in --_justify-self", async () => {
279
- for (const [prop, expected] of [["start", "start"], ["end", "end"]] as const) {
278
+ for (const [prop, expected] of [
279
+ ["start", "start"],
280
+ ["end", "end"],
281
+ ] as const) {
280
282
  const wrapper = await mountSuspended(BannerVideo, {
281
283
  props: { ...defaultProps, horizontalPosition: prop },
282
284
  });
@@ -1,13 +1,13 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`BannerVideo > renders correct HTML structure (all props set) 1`] = `
4
- "<header class="banner-video full-bleed" data-depth="xl" style="--_aspect-ratio: 16/9; --_align-self: center; --_justify-self: center;"><video class="video" autoplay="" muted="" loop="" playsinline="" preload="auto" poster="/images/banners/video/lake-banner.jpg" style="object-fit: cover;">
4
+ "<header class="banner-video full-bleed" data-depth="xl" style="--_aspect-ratio: 16/9; --_align-self: center; --_justify-self: center;"><video class="video" autoplay="" muted="" loop="" playsinline="" preload="auto" fetchpriority="high" poster="/images/banners/video/lake-banner.jpg" style="object-fit: cover;">
5
5
  <source src="/images/banners/video/lake-banner.mp4" type="video/mp4">
6
- </video><img width="1280" height="720" data-nuxt-img="" srcset="/_ipx/s_1280x720/images/banners/video/lake-banner.jpg 1x, /_ipx/s_2560x1440/images/banners/video/lake-banner.jpg 2x" class="fallback" alt="Lake banner" loading="eager" decoding="async" style="object-fit: cover; object-position: center center;" src="/_ipx/s_1280x720/images/banners/video/lake-banner.jpg"></header>"
6
+ </video><img width="1280" height="720" data-nuxt-img="" srcset="/_ipx/s_1280x720/images/banners/video/lake-banner.jpg 1x, /_ipx/s_2560x1440/images/banners/video/lake-banner.jpg 2x" class="fallback" alt="Lake banner" loading="eager" fetchpriority="high" decoding="async" style="object-fit: cover; object-position: center center;" src="/_ipx/s_1280x720/images/banners/video/lake-banner.jpg"></header>"
7
7
  `;
8
8
 
9
9
  exports[`BannerVideo > renders correct HTML structure (default props) 1`] = `
10
- "<section class="banner-video" data-depth="md" style="--_aspect-ratio: 21/9; --_align-self: center; --_justify-self: center;"><video class="video" autoplay="" muted="" loop="" playsinline="" preload="auto" poster="/images/banners/video/lake-banner.jpg" style="object-fit: cover;">
10
+ "<div class="banner-video" data-depth="md" style="--_aspect-ratio: 21/9; --_align-self: center; --_justify-self: center;"><video class="video" autoplay="" muted="" loop="" playsinline="" preload="auto" fetchpriority="high" poster="/images/banners/video/lake-banner.jpg" style="object-fit: cover;">
11
11
  <source src="/images/banners/video/lake-banner.mp4" type="video/mp4">
12
- </video><img width="1920" height="1080" data-nuxt-img="" srcset="/_ipx/s_1920x1080/images/banners/video/lake-banner.jpg 1x, /_ipx/s_3840x2160/images/banners/video/lake-banner.jpg 2x" class="fallback" alt="" loading="eager" decoding="async" style="object-fit: cover; object-position: center center;" src="/_ipx/s_1920x1080/images/banners/video/lake-banner.jpg"></section>"
12
+ </video><img width="1920" height="1080" data-nuxt-img="" srcset="/_ipx/s_1920x1080/images/banners/video/lake-banner.jpg 1x, /_ipx/s_3840x2160/images/banners/video/lake-banner.jpg 2x" class="fallback" alt="" loading="eager" fetchpriority="high" decoding="async" style="object-fit: cover; object-position: center center;" src="/_ipx/s_1920x1080/images/banners/video/lake-banner.jpg"></div>"
13
13
  `;
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <Qrcode
3
+ :value="qrValue"
4
+ class="display-qr-code"
5
+ :variant
6
+ :radius
7
+ :black-color
8
+ :white-color
9
+ :class="[elementClasses]"
10
+ />
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import type { QrCodeVariant } from "~/types/components";
15
+
16
+ interface Props {
17
+ qrValue: string;
18
+ variant?: QrCodeVariant;
19
+ radius?: number;
20
+ blackColor?: string;
21
+ whiteColor?: string;
22
+ size?: string;
23
+ styleClassPassthrough?: string | string[];
24
+ }
25
+
26
+ const props = withDefaults(defineProps<Props>(), {
27
+ variant: () => ({ inner: "default", marker: "default", pixel: "default" }),
28
+ radius: 0,
29
+ blackColor: "currentColor",
30
+ whiteColor: "transparent",
31
+ size: "256px",
32
+ styleClassPassthrough: () => [],
33
+ });
34
+
35
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
36
+
37
+ watch(
38
+ () => props.styleClassPassthrough,
39
+ () => resetElementClasses(props.styleClassPassthrough)
40
+ );
41
+ </script>
42
+
43
+ <style lang="css">
44
+ @layer components {
45
+ .display-qr-code {
46
+ aspect-ratio: 1 / 1;
47
+ width: v-bind(size);
48
+ }
49
+ }
50
+ </style>