srcdev-nuxt-components 9.1.18 → 9.1.20

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.
@@ -21,7 +21,12 @@
21
21
  "Bash(node -e \"const t = require\\('/Users/simoncornforth/websites/nuxt-components/node_modules/pinia-plugin-persistedstate'\\); console.log\\(Object.keys\\(t\\)\\)\")",
22
22
  "Bash(npx vue-tsc:*)",
23
23
  "Bash(git -C /Users/simoncornforth/websites/nuxt-components log --oneline -5)",
24
- "Bash(git -C /Users/simoncornforth/websites/nuxt-components show 16ac4ef --stat)"
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
+ "Bash(npm install:*)",
29
+ "Bash(npm run:*)"
25
30
  ],
26
31
  "additionalDirectories": [
27
32
  "/Users/simoncornforth/websites/nuxt-components/app/components/01.atoms/content-wrappers/content-width",
@@ -48,10 +48,19 @@ import type { NavItem, NavItemData } from "~/types/components/navigation-horizon
48
48
 
49
49
  ## Consuming app usage
50
50
 
51
- Once published, consumers import from the package barrel:
51
+ The chain that makes this work:
52
+
53
+ ```text
54
+ app/types/components/<component>.d.ts
55
+ → app/types/components/index.ts (export * from "./<component>.d")
56
+ → types.d.ts (export * from "./app/types/components")
57
+ → consumer import
58
+ ```
59
+
60
+ `types.d.ts` is the `"types"` entry point in `package.json`, so once a type is added to the barrel it is importable directly from the package name:
52
61
 
53
62
  ```ts
54
- import type { NavItem, NavItemData } from "nuxt-components/app/types/components";
63
+ import type { NavItem, NavItemData } from "srcdev-nuxt-components";
55
64
  ```
56
65
 
57
66
  ## Notes
@@ -20,9 +20,19 @@ Both the horizontal list and the panel include animated active/hover indicator d
20
20
 
21
21
  ## NavItemData type
22
22
 
23
+ **Within the layer:**
24
+
23
25
  ```ts
24
26
  import type { NavItemData } from "~/types/components/navigation-horizontal.d";
27
+ ```
25
28
 
29
+ **In a consuming app:**
30
+
31
+ ```ts
32
+ import type { NavItemData } from "srcdev-nuxt-components";
33
+ ```
34
+
35
+ ```ts
26
36
  const navItemData: NavItemData = {
27
37
  main: [
28
38
  { text: "Home", href: "/" },
@@ -0,0 +1,120 @@
1
+ # SocialIconsList Component
2
+
3
+ ## Overview
4
+
5
+ `SocialIconsList` renders a horizontal list of social network icon links. Each item is data-driven via the `items` prop — the component composes the full href from `baseHref + profileId` at render time. Icons are sourced from the `logos:*` Iconify collection (`@iconify-json/logos`), which uses brand colours baked into the SVG.
6
+
7
+ ---
8
+
9
+ ## Props reference
10
+
11
+ | Prop | Type | Default | Notes |
12
+ |------|------|---------|-------|
13
+ | `items` | `ISocialIcon[]` | — | **Required.** Array of social network items. |
14
+ | `label` | `string` | `"Social media profiles"` | `aria-label` applied to the `<ul>` element. |
15
+ | `styleClassPassthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root `<ul>`. |
16
+
17
+ ---
18
+
19
+ ## ISocialIcon type
20
+
21
+ ```ts
22
+ interface ISocialIcon {
23
+ networkName: string; // Used as aria-label: "{networkName} profile"
24
+ iconName: string; // Iconify icon name, e.g. "logos:instagram-icon"
25
+ baseHref: string; // Base URL including trailing slash, e.g. "https://www.instagram.com/"
26
+ profileId: string; // Profile identifier appended to baseHref
27
+ }
28
+ ```
29
+
30
+ The rendered `href` is `${baseHref}${profileId}`.
31
+
32
+ ### Importing the type
33
+
34
+ **Within the layer** (e.g. in another layer component or composable):
35
+
36
+ ```ts
37
+ import type { ISocialIcon } from "~/types/components/social-icons-list.d";
38
+ ```
39
+
40
+ **In a consuming app** — exported via the package barrel (`types.d.ts` → `app/types/components/index.ts`):
41
+
42
+ ```ts
43
+ import type { ISocialIcon } from "srcdev-nuxt-components";
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Standard social network values
49
+
50
+ | Network | `iconName` | `baseHref` |
51
+ |---------|-----------|-----------|
52
+ | Facebook | `logos:facebook` | `https://www.facebook.com/` |
53
+ | X (Twitter) | `logos:x` | `https://x.com/` |
54
+ | Instagram | `logos:instagram-icon` | `https://www.instagram.com/` |
55
+ | YouTube | `logos:youtube-icon` | `https://www.youtube.com/@` |
56
+ | TikTok | `logos:tiktok-icon` | `https://www.tiktok.com/@` |
57
+
58
+ ---
59
+
60
+ ## Usage example
61
+
62
+ ```vue
63
+ <SocialIconsList
64
+ :items="[
65
+ {
66
+ networkName: 'Instagram',
67
+ iconName: 'logos:instagram-icon',
68
+ baseHref: 'https://www.instagram.com/',
69
+ profileId: 'yourbrand',
70
+ },
71
+ {
72
+ networkName: 'TikTok',
73
+ iconName: 'logos:tiktok-icon',
74
+ baseHref: 'https://www.tiktok.com/@',
75
+ profileId: 'yourbrand',
76
+ },
77
+ ]"
78
+ />
79
+ ```
80
+
81
+ ---
82
+
83
+ ## CSS custom properties
84
+
85
+ | Property | Default | Notes |
86
+ |----------|---------|-------|
87
+ | `--theme-social-icon-size` | `2.4rem` | Width and height of each icon |
88
+ | `--theme-social-icon-gap` | `1.2rem` | Gap between icons in the flex row |
89
+
90
+ > **Note:** Iconify's `logos:*` styles are injected outside any CSS `@layer`, which means they override layered component styles. Icon sizing is applied via an inline `style` attribute on the `<Icon>` element so it takes precedence.
91
+
92
+ ---
93
+
94
+ ## Local style override scaffold
95
+
96
+ ```vue
97
+ <SocialIconsList :style-class-passthrough="['my-social-icons']" :items="items" />
98
+
99
+ <style>
100
+ /* ─── SocialIconsList local overrides ──────────────────────────────
101
+ Geometry and size only — brand colours are baked into logos: SVGs.
102
+ Delete this block if no overrides are needed.
103
+ ─────────────────────────────────────────────────────────────────── */
104
+ .social-icons-list {
105
+ &.my-social-icons {
106
+ /* --theme-social-icon-size: 3.2rem; */
107
+ /* --theme-social-icon-gap: 2rem; */
108
+ }
109
+ }
110
+ </style>
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Notes
116
+
117
+ - All links open in a new tab with `rel="noopener noreferrer"`.
118
+ - Each link carries `aria-label="{networkName} profile"` for screen reader accessibility.
119
+ - The `logos:*` Iconify collection requires `@iconify-json/logos` to be installed in the consumer app. Without it, icons will fall back to a CDN fetch (causing FOUC). See [icon-sets.md](../icon-sets.md).
120
+ - Auto-imported in Nuxt — no manual import needed.
@@ -59,7 +59,8 @@ Each skill is a single markdown file named `<area>-<task>.md`.
59
59
  ├── glass-panel.md — GlassPanel props, slots, CSS token API (--glass-panel-bg/border-color/shadow/highlight), theming override
60
60
  ├── navigation-horizontal.md — NavigationHorizontal props, NavItemData type, CSS token API, import path gotcha
61
61
  ├── input-copy-core.md — InputCopyCore: readonly copy-to-clipboard input; props, emits, slots, CSS classes, usage
62
- └── site-navigation.md — SiteNavigation: responsive nav with auto-collapse, burger menu, decorator indicators, CSS token API
62
+ ├── site-navigation.md — SiteNavigation: responsive nav with auto-collapse, burger menu, decorator indicators, CSS token API
63
+ └── social-icons-list.md — SocialIconsList: data-driven social icon links, ISocialIcon type, logos: icon names, CSS tokens
63
64
  ```
64
65
 
65
66
  ## Skill file template
@@ -1,10 +1,5 @@
1
1
  <template>
2
- <component
3
- :is="tag"
4
- class="profile-section"
5
- :class="[elementClasses]"
6
- :aria-labelledby="ariaLabelledby"
7
- >
2
+ <component :is="tag" class="profile-section" :class="[elementClasses]" :aria-labelledby="ariaLabelledby">
8
3
  <header class="profile-section-header">
9
4
  <slot v-if="hasEyebrowTextSlot" name="eyebrowText"></slot>
10
5
  <slot v-if="hasHeroTextSlot" name="heroText" :heading-id="headingId"></slot>
@@ -16,9 +11,9 @@
16
11
  </div>
17
12
  <div class="profile-info">
18
13
  <div class="profile-info-content">
19
- <div v-for="index in props.profileInfoCount" :key="index" class="profile-info-block">
20
- <slot :name="'profile-info-' + index">
21
- <p>Profile info content {{ index }}</p>
14
+ <div v-for="slotName in profileInfoSlots" :key="slotName" class="profile-info-block">
15
+ <slot :name="slotName">
16
+ <p>Profile info content {{ slotName }}</p>
22
17
  </slot>
23
18
  </div>
24
19
  </div>
@@ -58,6 +53,15 @@ const hasEyebrowTextSlot = computed(() => Boolean(slots.eyebrowText));
58
53
  const hasHeroTextSlot = computed(() => Boolean(slots.heroText));
59
54
  const hasProfileLinksSlot = computed(() => Boolean(slots.profileLinks));
60
55
 
56
+ const profileInfoSlots = computed(() => {
57
+ const provided = Object.keys(slots)
58
+ .filter((key) => /^profile-info-\d+$/.test(key))
59
+ .sort((a, b) => parseInt(a.split("-")[2] ?? "0") - parseInt(b.split("-")[2] ?? "0"));
60
+ return provided.length > 0
61
+ ? provided
62
+ : Array.from({ length: props.profileInfoCount }, (_, i) => `profile-info-${i + 1}`);
63
+ });
64
+
61
65
  const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
62
66
 
63
67
  watch(
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <ul class="social-icons-list" :class="[elementClasses]" :aria-label="label">
3
+ <li v-for="item in items" :key="item.networkName" class="social-icon-item">
4
+ <a
5
+ :href="`${item.baseHref}${item.profileId}`"
6
+ class="social-icon-link"
7
+ :aria-label="`${item.networkName} profile`"
8
+ rel="noopener noreferrer"
9
+ target="_blank"
10
+ >
11
+ <Icon
12
+ :name="item.iconName"
13
+ class="social-icon"
14
+ :style="{ width: 'var(--_icon-size)', height: 'var(--_icon-size)' }"
15
+ />
16
+ </a>
17
+ </li>
18
+ </ul>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import type { ISocialIcon } from "~/types/components/social-icons-list.d";
23
+
24
+ interface Props {
25
+ items: ISocialIcon[];
26
+ label?: string;
27
+ styleClassPassthrough?: string | string[];
28
+ }
29
+
30
+ const props = withDefaults(defineProps<Props>(), {
31
+ label: "Social media profiles",
32
+ styleClassPassthrough: () => [],
33
+ });
34
+
35
+ const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
36
+
37
+ watch(
38
+ () => props.styleClassPassthrough,
39
+ () => {
40
+ resetElementClasses(props.styleClassPassthrough);
41
+ }
42
+ );
43
+ </script>
44
+
45
+ <style lang="css">
46
+ @layer components {
47
+ .social-icons-list {
48
+ --_icon-size: var(--theme-social-icon-size, 2.4rem);
49
+ --_gap: var(--theme-social-icon-gap, 1.2rem);
50
+
51
+ display: flex;
52
+ flex-wrap: wrap;
53
+ gap: var(--_gap);
54
+ list-style: none;
55
+ padding: 0;
56
+ margin: 0;
57
+
58
+ .social-icon-item {
59
+ display: flex;
60
+
61
+ .social-icon-link {
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ text-decoration: none;
66
+ transition:
67
+ transform 200ms ease,
68
+ opacity 200ms ease;
69
+
70
+ &:hover,
71
+ &:focus-visible {
72
+ transform: scale(1.15);
73
+ opacity: 0.85;
74
+ }
75
+
76
+ &:focus-visible {
77
+ outline: 2px solid currentColor;
78
+ outline-offset: 3px;
79
+ border-radius: 2px;
80
+ }
81
+
82
+ .social-icon {
83
+ /* width: var(--_icon-size); */
84
+ /* height: var(--_icon-size); */
85
+ }
86
+ }
87
+ }
88
+ }
89
+ }
90
+ </style>
@@ -0,0 +1,111 @@
1
+ import SocialIconsList from "../SocialIconsList.vue";
2
+ import type { Meta, StoryObj } from "@nuxtjs/storybook";
3
+ import type { ISocialIcon } from "~/types/components/social-icons-list.d";
4
+
5
+ const sampleItems: ISocialIcon[] = [
6
+ {
7
+ networkName: "Facebook",
8
+ iconName: "logos:facebook",
9
+ baseHref: "https://www.facebook.com/",
10
+ profileId: "yourprofile",
11
+ },
12
+ {
13
+ networkName: "X (Twitter)",
14
+ iconName: "logos:x",
15
+ baseHref: "https://x.com/",
16
+ profileId: "yourhandle",
17
+ },
18
+ {
19
+ networkName: "Instagram",
20
+ iconName: "logos:instagram-icon",
21
+ baseHref: "https://www.instagram.com/",
22
+ profileId: "yourprofile",
23
+ },
24
+ {
25
+ networkName: "YouTube",
26
+ iconName: "logos:youtube-icon",
27
+ baseHref: "https://www.youtube.com/@",
28
+ profileId: "yourchannel",
29
+ },
30
+ {
31
+ networkName: "TikTok",
32
+ iconName: "logos:tiktok-icon",
33
+ baseHref: "https://www.tiktok.com/@",
34
+ profileId: "yourprofile",
35
+ },
36
+ ];
37
+
38
+ const meta: Meta<typeof SocialIconsList> = {
39
+ title: "Molecules/SocialIconsList",
40
+ component: SocialIconsList,
41
+ argTypes: {
42
+ items: {
43
+ control: "object",
44
+ description:
45
+ "Array of social network items. Each item requires networkName, iconName (Iconify logos: collection), baseHref, and profileId.",
46
+ },
47
+ label: {
48
+ control: "text",
49
+ description: "aria-label for the list element",
50
+ },
51
+ styleClassPassthrough: {
52
+ control: "object",
53
+ description: "Additional CSS classes applied to the root element",
54
+ },
55
+ },
56
+ args: {
57
+ items: sampleItems,
58
+ label: "Social media profiles",
59
+ styleClassPassthrough: ["m-40"],
60
+ },
61
+ };
62
+
63
+ export default meta;
64
+ type Story = StoryObj<typeof SocialIconsList>;
65
+
66
+ // ─── Stories ─────────────────────────────────────────────────────────────────
67
+
68
+ /** Default — all five networks at the standard icon size. */
69
+ export const Default: Story = {
70
+ render: (args) => ({
71
+ components: { SocialIconsList },
72
+ setup() {
73
+ return { args };
74
+ },
75
+ template: `<SocialIconsList v-bind="args" />`,
76
+ }),
77
+ };
78
+
79
+ /** Large icons — override icon size via CSS token. */
80
+ export const LargeIcons: Story = {
81
+ name: "Large Icons",
82
+ render: (args) => ({
83
+ components: { SocialIconsList },
84
+ setup() {
85
+ return { args };
86
+ },
87
+ template: `<SocialIconsList v-bind="args" style="--theme-social-icon-size: 4rem;" />`,
88
+ }),
89
+ };
90
+
91
+ /** Single network — only one item in the list. */
92
+ export const SingleNetwork: Story = {
93
+ name: "Single Network",
94
+ args: {
95
+ items: [
96
+ {
97
+ networkName: "Instagram",
98
+ iconName: "logos:instagram-icon",
99
+ baseHref: "https://www.instagram.com/",
100
+ profileId: "luxurylocs",
101
+ },
102
+ ],
103
+ },
104
+ render: (args) => ({
105
+ components: { SocialIconsList },
106
+ setup() {
107
+ return { args };
108
+ },
109
+ template: `<SocialIconsList v-bind="args" />`,
110
+ }),
111
+ };
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { mountSuspended } from "@nuxt/test-utils/runtime";
3
+ import SocialIconsList from "../SocialIconsList.vue";
4
+ import type { ISocialIcon } from "~/types/components/social-icons-list.d";
5
+
6
+ const defaultItems: ISocialIcon[] = [
7
+ {
8
+ networkName: "Facebook",
9
+ iconName: "logos:facebook",
10
+ baseHref: "https://www.facebook.com/",
11
+ profileId: "testprofile",
12
+ },
13
+ {
14
+ networkName: "Instagram",
15
+ iconName: "logos:instagram-icon",
16
+ baseHref: "https://www.instagram.com/",
17
+ profileId: "testhandle",
18
+ },
19
+ {
20
+ networkName: "YouTube",
21
+ iconName: "logos:youtube-icon",
22
+ baseHref: "https://www.youtube.com/@",
23
+ profileId: "testchannel",
24
+ },
25
+ ];
26
+
27
+ describe("SocialIconsList", () => {
28
+ it("mounts without error", async () => {
29
+ const wrapper = await mountSuspended(SocialIconsList, {
30
+ props: { items: defaultItems },
31
+ });
32
+ expect(wrapper.vm).toBeTruthy();
33
+ });
34
+
35
+ it("renders as a ul element", async () => {
36
+ const wrapper = await mountSuspended(SocialIconsList, {
37
+ props: { items: defaultItems },
38
+ });
39
+ expect(wrapper.element.tagName.toLowerCase()).toBe("ul");
40
+ });
41
+
42
+ it("renders the correct number of list items", async () => {
43
+ const wrapper = await mountSuspended(SocialIconsList, {
44
+ props: { items: defaultItems },
45
+ });
46
+ expect(wrapper.findAll(".social-icon-item").length).toBe(defaultItems.length);
47
+ });
48
+
49
+ it("renders the correct href for each item", async () => {
50
+ const wrapper = await mountSuspended(SocialIconsList, {
51
+ props: { items: defaultItems },
52
+ });
53
+ const links = wrapper.findAll(".social-icon-link");
54
+ defaultItems.forEach((item, i) => {
55
+ expect(links[i]!.attributes("href")).toBe(`${item.baseHref}${item.profileId}`);
56
+ });
57
+ });
58
+
59
+ it("renders aria-label on each link using networkName", async () => {
60
+ const wrapper = await mountSuspended(SocialIconsList, {
61
+ props: { items: defaultItems },
62
+ });
63
+ const links = wrapper.findAll(".social-icon-link");
64
+ defaultItems.forEach((item, i) => {
65
+ expect(links[i]!.attributes("aria-label")).toBe(`${item.networkName} profile`);
66
+ });
67
+ });
68
+
69
+ it("adds rel='noopener noreferrer' to each link", async () => {
70
+ const wrapper = await mountSuspended(SocialIconsList, {
71
+ props: { items: defaultItems },
72
+ });
73
+ const links = wrapper.findAll(".social-icon-link");
74
+ links.forEach((link) => {
75
+ expect(link.attributes("rel")).toBe("noopener noreferrer");
76
+ });
77
+ });
78
+
79
+ it("opens each link in a new tab", async () => {
80
+ const wrapper = await mountSuspended(SocialIconsList, {
81
+ props: { items: defaultItems },
82
+ });
83
+ const links = wrapper.findAll(".social-icon-link");
84
+ links.forEach((link) => {
85
+ expect(link.attributes("target")).toBe("_blank");
86
+ });
87
+ });
88
+
89
+ it("uses the default aria-label on the list", async () => {
90
+ const wrapper = await mountSuspended(SocialIconsList, {
91
+ props: { items: defaultItems },
92
+ });
93
+ expect(wrapper.attributes("aria-label")).toBe("Social media profiles");
94
+ });
95
+
96
+ it("uses a custom label prop as aria-label on the list", async () => {
97
+ const wrapper = await mountSuspended(SocialIconsList, {
98
+ props: { items: defaultItems, label: "Follow us" },
99
+ });
100
+ expect(wrapper.attributes("aria-label")).toBe("Follow us");
101
+ });
102
+
103
+ it("renders an empty list when items is empty", async () => {
104
+ const wrapper = await mountSuspended(SocialIconsList, {
105
+ props: { items: [] },
106
+ });
107
+ expect(wrapper.findAll(".social-icon-item").length).toBe(0);
108
+ });
109
+
110
+ it("applies styleClassPassthrough classes to the root element", async () => {
111
+ const wrapper = await mountSuspended(SocialIconsList, {
112
+ props: { items: defaultItems, styleClassPassthrough: ["custom-class", "another-class"] },
113
+ });
114
+ expect(wrapper.classes()).toContain("custom-class");
115
+ expect(wrapper.classes()).toContain("another-class");
116
+ });
117
+
118
+ it("renders the correct HTML structure", async () => {
119
+ const wrapper = await mountSuspended(SocialIconsList, {
120
+ props: { items: defaultItems },
121
+ });
122
+ expect(wrapper.html()).toMatchSnapshot();
123
+ });
124
+ });
@@ -0,0 +1,9 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`SocialIconsList > renders the correct HTML structure 1`] = `
4
+ "<ul class="social-icons-list" aria-label="Social media profiles">
5
+ <li class="social-icon-item"><a href="https://www.facebook.com/testprofile" class="social-icon-link" aria-label="Facebook profile" rel="noopener noreferrer" target="_blank"><span class="iconify i-logos:facebook social-icon" aria-hidden="true" style="width: var(--_icon-size); height: var(--_icon-size);"></span></a></li>
6
+ <li class="social-icon-item"><a href="https://www.instagram.com/testhandle" class="social-icon-link" aria-label="Instagram profile" rel="noopener noreferrer" target="_blank"><span class="iconify i-logos:instagram-icon social-icon" aria-hidden="true" style="width: var(--_icon-size); height: var(--_icon-size);"></span></a></li>
7
+ <li class="social-icon-item"><a href="https://www.youtube.com/@testchannel" class="social-icon-link" aria-label="YouTube profile" rel="noopener noreferrer" target="_blank"><span class="iconify i-logos:youtube-icon social-icon" aria-hidden="true" style="width: var(--_icon-size); height: var(--_icon-size);"></span></a></li>
8
+ </ul>"
9
+ `;
@@ -1,5 +1,3 @@
1
- // composables/useWhatsApp.ts
2
-
3
1
  export const useWhatsApp = () => {
4
2
  const config = useRuntimeConfig();
5
3
 
@@ -12,7 +12,6 @@
12
12
  src: '/images/services/service-balayage.jpg',
13
13
  alt: 'Profile picture of Natasha, the mobile hairdresser in Bath',
14
14
  }"
15
- :profile-info-count="3"
16
15
  >
17
16
  <template #eyebrowText>
18
17
  <EyebrowText tag="p" font-size="large" text-content="About Natasha" :style-class-passthrough="['mb-0']" />
@@ -66,6 +65,35 @@
66
65
  </p>
67
66
  </template>
68
67
 
68
+ <template #profile-info-4>
69
+ <HeroText
70
+ tag="h3"
71
+ axis="horizontal"
72
+ font-size="heading"
73
+ :text-content="[
74
+ { text: 'Follow me on', styleClass: 'normal' },
75
+ { text: 'social media', styleClass: 'accent' },
76
+ ]"
77
+ :style-class-passthrough="['mb-20']"
78
+ />
79
+ <SocialIconsList
80
+ :items="[
81
+ {
82
+ networkName: 'Facebook',
83
+ iconName: 'logos:facebook',
84
+ baseHref: 'https://www.facebook.com/',
85
+ profileId: 'luxurylocsbynatasha',
86
+ },
87
+ {
88
+ networkName: 'Instagram',
89
+ iconName: 'skill-icons:instagram',
90
+ baseHref: 'https://www.instagram.com/',
91
+ profileId: 'luxurylocsbynatasha',
92
+ },
93
+ ]"
94
+ />
95
+ </template>
96
+
69
97
  <template #profileLinks>
70
98
  <InputButtonCore
71
99
  variant="secondary"
@@ -10,3 +10,4 @@ export * from "./qr-code.d"
10
10
  export * from "./alert-mask-core.d"
11
11
  export * from "./hero-text"
12
12
  export * from "./navigation-horizontal.d"
13
+ export * from "./social-icons-list.d"
@@ -0,0 +1,6 @@
1
+ export interface ISocialIcon {
2
+ networkName: string;
3
+ iconName: string;
4
+ baseHref: string;
5
+ profileId: string;
6
+ }
@@ -12,6 +12,7 @@ const ICON_SETS = [
12
12
  "@iconify-json/bitcoin-icons",
13
13
  "@iconify-json/gravity-ui",
14
14
  "@iconify-json/ic",
15
+ "@iconify-json/logos",
15
16
  "@iconify-json/lucide",
16
17
  "@iconify-json/material-symbols",
17
18
  "@iconify-json/mdi",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.1.18",
4
+ "version": "9.1.20",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",
@@ -45,6 +45,7 @@
45
45
  "@iconify-json/bitcoin-icons": "*",
46
46
  "@iconify-json/gravity-ui": "*",
47
47
  "@iconify-json/ic": "*",
48
+ "@iconify-json/logos": "*",
48
49
  "@iconify-json/lucide": "*",
49
50
  "@iconify-json/material-symbols": "*",
50
51
  "@iconify-json/mdi": "*",
@@ -66,6 +67,9 @@
66
67
  "@iconify-json/ic": {
67
68
  "optional": true
68
69
  },
70
+ "@iconify-json/logos": {
71
+ "optional": true
72
+ },
69
73
  "@iconify-json/lucide": {
70
74
  "optional": true
71
75
  },
@@ -86,6 +90,7 @@
86
90
  "@iconify-json/bitcoin-icons": "1.2.4",
87
91
  "@iconify-json/gravity-ui": "1.2.12",
88
92
  "@iconify-json/ic": "*",
93
+ "@iconify-json/logos": "1.2.11",
89
94
  "@iconify-json/lucide": "*",
90
95
  "@iconify-json/material-symbols": "1.2.64",
91
96
  "@iconify-json/mdi": "1.2.3",