@vc-shell/framework 1.1.58 → 1.1.60
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 +13 -0
- package/dist/assets/154365acf3010d96.woff2 +0 -0
- package/dist/assets/475937116ee3314a.woff2 +0 -0
- package/dist/assets/49791943b3872376.woff2 +0 -0
- package/dist/assets/7a5aa5abd625137f.ttf +0 -0
- package/dist/assets/ac1a99b3d05d8232.woff +0 -0
- package/dist/assets/ccc878931d74181b.woff2 +0 -0
- package/dist/assets/ee6983981ffcbb41.woff2 +0 -0
- package/dist/framework.js +3670 -3644
- package/dist/index.css +9 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts +5 -0
- package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts +6 -1
- package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts.map +1 -1
- package/dist/{vendor-intlify-core-base-Bvt2vJFV.js → vendor-intlify-core-base-FyGSkd6r.js} +167 -166
- package/dist/{vendor-intlify-message-compiler-1VxNzq21.js → vendor-intlify-message-compiler-D_vL9-DK.js} +2 -2
- package/dist/vendor-intlify-shared-BMbzEQSk.js +144 -0
- package/dist/vendor-lucide-vue-next-m0L4DzUL.js +29780 -0
- package/dist/{vendor-prosemirror-commands-BqYcdumy.js → vendor-prosemirror-commands-C6teL3Xo.js} +3 -3
- package/dist/{vendor-prosemirror-dropcursor-zknUsW5x.js → vendor-prosemirror-dropcursor-CwZhBUcZ.js} +2 -2
- package/dist/{vendor-prosemirror-gapcursor-DjOZhP78.js → vendor-prosemirror-gapcursor-COcwb4TJ.js} +4 -4
- package/dist/{vendor-prosemirror-history-l8l3CFac.js → vendor-prosemirror-history-DmPvdOpr.js} +2 -2
- package/dist/{vendor-prosemirror-keymap-C17r08p-.js → vendor-prosemirror-keymap-CS1uIBpE.js} +1 -1
- package/dist/{vendor-prosemirror-markdown-WJEDhc-w.js → vendor-prosemirror-markdown-sO1Pn6SW.js} +1 -1
- package/dist/{vendor-prosemirror-model-BN5TnJD_.js → vendor-prosemirror-model-DwojkhDQ.js} +68 -82
- package/dist/{vendor-prosemirror-schema-list-CR0gi7aY.js → vendor-prosemirror-schema-list-rrOzMlj0.js} +2 -2
- package/dist/{vendor-prosemirror-state-B0bFP8WI.js → vendor-prosemirror-state-BN86J-Ko.js} +2 -2
- package/dist/{vendor-prosemirror-tables-B1txTKlC.js → vendor-prosemirror-tables-C7XMqyon.js} +5 -5
- package/dist/{vendor-prosemirror-transform-Bo7kNPme.js → vendor-prosemirror-transform-B0c_LAV_.js} +1 -1
- package/dist/{vendor-prosemirror-view--C7TZvmQ.js → vendor-prosemirror-view-DyWzmy4t.js} +3 -3
- package/dist/{vendor-tiptap-core-CczYXVC4.js → vendor-tiptap-core-BgwY40dr.js} +7 -7
- package/dist/{vendor-tiptap-extension-blockquote-Dm7YbSqy.js → vendor-tiptap-extension-blockquote-BVW0VVC0.js} +1 -1
- package/dist/{vendor-tiptap-extension-bold-YKANgJQB.js → vendor-tiptap-extension-bold-xhi5xxPT.js} +1 -1
- package/dist/{vendor-tiptap-extension-bubble-menu-gh-OpViI.js → vendor-tiptap-extension-bubble-menu-DhWtcCL3.js} +2 -2
- package/dist/{vendor-tiptap-extension-bullet-list-CZWmGEbV.js → vendor-tiptap-extension-bullet-list-Ba21suMY.js} +1 -1
- package/dist/{vendor-tiptap-extension-code-Bg0UZ8tC.js → vendor-tiptap-extension-code-DFTxp7wE.js} +1 -1
- package/dist/{vendor-tiptap-extension-code-block-DQJ_tCBi.js → vendor-tiptap-extension-code-block-B2KK5g8S.js} +2 -2
- package/dist/{vendor-tiptap-extension-document-CpCZXWQI.js → vendor-tiptap-extension-document-CW8jybcc.js} +1 -1
- package/dist/{vendor-tiptap-extension-dropcursor-BVniwBbO.js → vendor-tiptap-extension-dropcursor-DdRuETKJ.js} +2 -2
- package/dist/{vendor-tiptap-extension-floating-menu-FkBnPfW6.js → vendor-tiptap-extension-floating-menu-Da7fpnr7.js} +2 -2
- package/dist/{vendor-tiptap-extension-gapcursor-XdrpVWvW.js → vendor-tiptap-extension-gapcursor-CafmhWSf.js} +2 -2
- package/dist/{vendor-tiptap-extension-hard-break-N0r28gea.js → vendor-tiptap-extension-hard-break-n9aI6ybJ.js} +1 -1
- package/dist/{vendor-tiptap-extension-heading-CY1DvT1I.js → vendor-tiptap-extension-heading-xj24usOy.js} +1 -1
- package/dist/{vendor-tiptap-extension-history-BUL3NsZ9.js → vendor-tiptap-extension-history-C2uOLua2.js} +2 -2
- package/dist/{vendor-tiptap-extension-horizontal-rule-D27m_G1b.js → vendor-tiptap-extension-horizontal-rule--uXIYeaK.js} +2 -2
- package/dist/{vendor-tiptap-extension-image-CbjGZU8i.js → vendor-tiptap-extension-image-BJx5lyoG.js} +1 -1
- package/dist/{vendor-tiptap-extension-italic-zyDDu_SW.js → vendor-tiptap-extension-italic-DPAViC4y.js} +1 -1
- package/dist/{vendor-tiptap-extension-link-Bcv4UeMa.js → vendor-tiptap-extension-link-aDGmrWTi.js} +2 -2
- package/dist/{vendor-tiptap-extension-list-item-DZU6bwbc.js → vendor-tiptap-extension-list-item-DE9dJ64Q.js} +1 -1
- package/dist/{vendor-tiptap-extension-ordered-list-BXSeGf29.js → vendor-tiptap-extension-ordered-list-CcNtDDJm.js} +1 -1
- package/dist/{vendor-tiptap-extension-paragraph-PDX7FACk.js → vendor-tiptap-extension-paragraph-DvlrAzIW.js} +1 -1
- package/dist/{vendor-tiptap-extension-placeholder-Ue_ElAEg.js → vendor-tiptap-extension-placeholder-DyW7px66.js} +3 -3
- package/dist/{vendor-tiptap-extension-strike-rl2UQZzW.js → vendor-tiptap-extension-strike-DMMLEFkd.js} +1 -1
- package/dist/{vendor-tiptap-extension-table-B59LhE4D.js → vendor-tiptap-extension-table-BpegTABL.js} +3 -3
- package/dist/{vendor-tiptap-extension-table-cell-9N0NKfpg.js → vendor-tiptap-extension-table-cell-8rHRq4BW.js} +1 -1
- package/dist/{vendor-tiptap-extension-table-header-DJTZtK2Z.js → vendor-tiptap-extension-table-header-DZ1y7iS2.js} +1 -1
- package/dist/{vendor-tiptap-extension-table-row-D7Upcsrg.js → vendor-tiptap-extension-table-row-DmkNUw4L.js} +1 -1
- package/dist/{vendor-tiptap-extension-text-Buc1GYNc.js → vendor-tiptap-extension-text-Cwas3TQT.js} +1 -1
- package/dist/{vendor-tiptap-extension-underline-COmEda96.js → vendor-tiptap-extension-underline-Hz5uJRfR.js} +1 -1
- package/dist/{vendor-tiptap-markdown-QcGJtrvN.js → vendor-tiptap-markdown-Dj1XZWg4.js} +4 -4
- package/dist/{vendor-tiptap-starter-kit-rn_ARLXy.js → vendor-tiptap-starter-kit-Cxj07T7v.js} +19 -19
- package/dist/{vendor-tiptap-vue-3-KDP_yBZF.js → vendor-tiptap-vue-3-DF4kzEFI.js} +3 -3
- package/dist/{vendor-vue-i18n-DPtOLen3.js → vendor-vue-i18n-DC6m6S7G.js} +34 -34
- package/package.json +8 -5
- package/ui/components/atoms/vc-icon/composables/use-icon.ts +1 -1
- package/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue +5 -6
- package/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue +31 -37
- package/ui/components/atoms/vc-icon/vc-icon.vue +186 -43
- package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +70 -23
- package/ui/components/atoms/vc-icon/vc-material-icon.vue +37 -45
- package/dist/vendor-iconify-vue-D4fihzvl.js +0 -1205
- package/dist/vendor-intlify-shared-D7kiPMOG.js +0 -130
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:
|
|
4
|
-
|
|
2
|
+
<i
|
|
3
|
+
:class="[
|
|
4
|
+
'vc-fa-icon',
|
|
5
|
+
!hasCustomSize && `vc-fa-icon--${size}`,
|
|
6
|
+
iconClasses,
|
|
7
|
+
variant ? `vc-fa-icon--${variant}` : '',
|
|
8
|
+
]"
|
|
5
9
|
:style="mergedStyle"
|
|
6
10
|
aria-hidden="true"
|
|
7
|
-
|
|
11
|
+
></i>
|
|
8
12
|
</template>
|
|
9
13
|
|
|
10
14
|
<script lang="ts" setup>
|
|
11
15
|
import { computed } from "vue";
|
|
12
|
-
import { Icon } from "@iconify/vue";
|
|
13
16
|
import type { IconSize, IconVariant } from "./types";
|
|
14
17
|
import { useIcon } from "./composables";
|
|
15
18
|
|
|
@@ -62,40 +65,31 @@ const mergedStyle = computed(() => {
|
|
|
62
65
|
return styles;
|
|
63
66
|
});
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
style = "solid";
|
|
77
|
-
break;
|
|
78
|
-
case "far":
|
|
79
|
-
style = "regular";
|
|
80
|
-
break;
|
|
81
|
-
case "fab":
|
|
82
|
-
style = "brands";
|
|
83
|
-
break;
|
|
84
|
-
case "fal":
|
|
85
|
-
style = "light";
|
|
86
|
-
break;
|
|
87
|
-
case "fad":
|
|
88
|
-
style = "duotone";
|
|
89
|
-
break;
|
|
90
|
-
default:
|
|
91
|
-
// Use the already processed name from slice(1), not the original props.icon
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
name = name.replace("fa-", "");
|
|
68
|
+
// Compute the FontAwesome class from the icon string
|
|
69
|
+
const iconClasses = computed(() => {
|
|
70
|
+
// If icon already has a style prefix (fas, far, fal, fab), use it as is
|
|
71
|
+
if (
|
|
72
|
+
props.icon.startsWith("fas ") ||
|
|
73
|
+
props.icon.startsWith("far ") ||
|
|
74
|
+
props.icon.startsWith("fal ") ||
|
|
75
|
+
props.icon.startsWith("fab ") ||
|
|
76
|
+
props.icon.startsWith("fad ")
|
|
77
|
+
) {
|
|
78
|
+
return props.icon;
|
|
96
79
|
}
|
|
97
80
|
|
|
98
|
-
|
|
81
|
+
// If icon starts with fa-, add the default style prefix
|
|
82
|
+
if (props.icon.startsWith("fa-")) {
|
|
83
|
+
return `fas ${props.icon}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// If icon contains fa- but doesn't start with a style prefix, assume the style prefix is included
|
|
87
|
+
if (props.icon.includes("fa-")) {
|
|
88
|
+
return props.icon;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Otherwise, assume it's a bare icon name and add both the style prefix and fa- prefix
|
|
92
|
+
return `fas fa-${props.icon}`;
|
|
99
93
|
});
|
|
100
94
|
</script>
|
|
101
95
|
|
|
@@ -110,6 +110,16 @@ const sizeMap = {
|
|
|
110
110
|
xxxl: 64,
|
|
111
111
|
} as const;
|
|
112
112
|
|
|
113
|
+
// Scaling factors for different icon types to make them visually equal
|
|
114
|
+
const scalingFactors = {
|
|
115
|
+
fontawesome: 1, // base reference
|
|
116
|
+
material: 1.1,
|
|
117
|
+
bootstrap: 0.95,
|
|
118
|
+
lucide: 1.2,
|
|
119
|
+
custom: 1,
|
|
120
|
+
svg: 1,
|
|
121
|
+
};
|
|
122
|
+
|
|
113
123
|
// Function to detect icon type if not explicitly specified
|
|
114
124
|
const detectIconType = computed((): IconType => {
|
|
115
125
|
if (typeof props.icon !== "string") {
|
|
@@ -152,16 +162,16 @@ const normalizedIconName = computed(() => {
|
|
|
152
162
|
return props.icon;
|
|
153
163
|
}
|
|
154
164
|
|
|
155
|
-
|
|
165
|
+
if (detectIconType.value === "material" && props.icon.startsWith("material-")) {
|
|
166
|
+
return props.icon.replace(/^material-/, "");
|
|
167
|
+
}
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
case "lucide":
|
|
161
|
-
return props.icon.replace(/^lucide-/, "");
|
|
162
|
-
default:
|
|
163
|
-
return props.icon;
|
|
169
|
+
if (detectIconType.value === "lucide" && props.icon.startsWith("lucide-")) {
|
|
170
|
+
const baseName = props.icon.replace(/^lucide-/, "");
|
|
171
|
+
return baseName.endsWith("Icon") ? baseName : `${baseName}Icon`;
|
|
164
172
|
}
|
|
173
|
+
|
|
174
|
+
return props.icon;
|
|
165
175
|
});
|
|
166
176
|
|
|
167
177
|
// Check if icon is a Material Design symbol
|
|
@@ -176,7 +186,7 @@ const isLucideIcon = computed(() => detectIconType.value === "lucide");
|
|
|
176
186
|
// Check if icon is a Font Awesome Icon
|
|
177
187
|
const isFontAwesomeIcon = computed(() => detectIconType.value === "fontawesome");
|
|
178
188
|
|
|
179
|
-
// Check if icon is a component or can be resolved as a component
|
|
189
|
+
// Check if the icon is a component or can be resolved as a component
|
|
180
190
|
const isCustomIcon = computed(() => {
|
|
181
191
|
if (typeof props.icon !== "string") {
|
|
182
192
|
return true; // Component instance passed directly
|
|
@@ -191,13 +201,25 @@ const isCustomIcon = computed(() => {
|
|
|
191
201
|
return false;
|
|
192
202
|
}
|
|
193
203
|
|
|
194
|
-
//
|
|
204
|
+
// Check for Lucide icons - they could be resolved as components
|
|
195
205
|
if (isLucideIcon.value) {
|
|
196
|
-
|
|
206
|
+
try {
|
|
207
|
+
const iconName =
|
|
208
|
+
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
209
|
+
const resolved = resolveComponent(iconName);
|
|
210
|
+
return resolved !== iconName;
|
|
211
|
+
} catch (e) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
//
|
|
200
|
-
|
|
216
|
+
// Check if string is a component name that can be resolved
|
|
217
|
+
try {
|
|
218
|
+
const resolved = resolveComponent(props.icon);
|
|
219
|
+
return resolved !== props.icon; // If resolved is different from original string, it's a component name
|
|
220
|
+
} catch (e) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
201
223
|
});
|
|
202
224
|
|
|
203
225
|
// Get the component instance for rendering
|
|
@@ -211,14 +233,15 @@ const safeIcon = computed(() => {
|
|
|
211
233
|
return "i";
|
|
212
234
|
}
|
|
213
235
|
|
|
214
|
-
//
|
|
215
|
-
|
|
236
|
+
// Try to resolve component by name (mostly for Lucide icons)
|
|
237
|
+
try {
|
|
216
238
|
const iconName =
|
|
217
239
|
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
218
|
-
|
|
240
|
+
const resolved = resolveComponent(iconName);
|
|
241
|
+
return resolved !== iconName ? resolved : "i"; // Return resolved component or fallback to 'i'
|
|
242
|
+
} catch (e) {
|
|
243
|
+
return "i";
|
|
219
244
|
}
|
|
220
|
-
|
|
221
|
-
return "i";
|
|
222
245
|
});
|
|
223
246
|
|
|
224
247
|
// Determine which component to render
|
|
@@ -292,32 +315,82 @@ const containerStyle = computed(() => {
|
|
|
292
315
|
|
|
293
316
|
// Prepare props for the rendered component
|
|
294
317
|
const componentProps = computed(() => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
318
|
+
if (isMaterialIcon.value) {
|
|
319
|
+
// Clean the name from possible suffixes of the icon type
|
|
320
|
+
const cleanIconName =
|
|
321
|
+
typeof normalizedIconName.value === "string"
|
|
322
|
+
? normalizedIconName.value.replace(/-outlined$|-rounded$|-sharp$/, "")
|
|
323
|
+
: normalizedIconName.value;
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
icon: cleanIconName,
|
|
327
|
+
size: props.size,
|
|
328
|
+
variant: props.variant,
|
|
329
|
+
type: "outlined",
|
|
330
|
+
fill: 0,
|
|
331
|
+
weight: 300,
|
|
332
|
+
grade: 0,
|
|
333
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (isBootstrapIcon.value) {
|
|
338
|
+
// For Bootstrap icons
|
|
339
|
+
const iconName = typeof props.icon === "string" ? props.icon : "";
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
icon: iconName,
|
|
343
|
+
size: props.size,
|
|
344
|
+
variant: props.variant,
|
|
345
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (isLucideIcon.value) {
|
|
350
|
+
// For Lucide icons
|
|
351
|
+
const iconName =
|
|
352
|
+
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
icon: iconName,
|
|
356
|
+
size: props.size,
|
|
357
|
+
variant: props.variant,
|
|
358
|
+
strokeWidth: 1.5,
|
|
359
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (isFontAwesomeIcon.value) {
|
|
364
|
+
// For Font Awesome icons
|
|
365
|
+
return {
|
|
366
|
+
icon: typeof props.icon === "string" ? props.icon : "",
|
|
367
|
+
size: props.size,
|
|
368
|
+
variant: props.variant,
|
|
369
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (isSvgIcon.value) {
|
|
374
|
+
return {
|
|
375
|
+
icon: svgPath.value,
|
|
376
|
+
size: props.size,
|
|
377
|
+
variant: props.variant,
|
|
378
|
+
strokeWidth: 1.5,
|
|
379
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
380
|
+
basePath: props.basePath,
|
|
381
|
+
};
|
|
320
382
|
}
|
|
383
|
+
|
|
384
|
+
if (isCustomIcon.value) {
|
|
385
|
+
return {
|
|
386
|
+
size: props.size,
|
|
387
|
+
width: calculatedSize.value,
|
|
388
|
+
height: calculatedSize.value,
|
|
389
|
+
color: props.variant ? `var(--icon-color-${props.variant})` : "currentColor",
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return {};
|
|
321
394
|
});
|
|
322
395
|
|
|
323
396
|
// Check if icon is an SVG icon
|
|
@@ -461,4 +534,74 @@ const svgPath = computed(() => {
|
|
|
461
534
|
min-height: calc(var(--icon-size-xxxl) * 1.33);
|
|
462
535
|
font-size: var(--icon-size-xxxl); /* Set font-size for the container */
|
|
463
536
|
}
|
|
537
|
+
|
|
538
|
+
/* Material Icons specific styles */
|
|
539
|
+
.material-symbols-outlined,
|
|
540
|
+
.material-symbols-rounded,
|
|
541
|
+
.material-symbols-sharp {
|
|
542
|
+
font-family: "Material Symbols Outlined";
|
|
543
|
+
font-weight: normal;
|
|
544
|
+
font-style: normal;
|
|
545
|
+
line-height: 1;
|
|
546
|
+
letter-spacing: normal;
|
|
547
|
+
text-transform: none;
|
|
548
|
+
white-space: nowrap;
|
|
549
|
+
word-wrap: normal;
|
|
550
|
+
direction: ltr;
|
|
551
|
+
font-feature-settings: "liga";
|
|
552
|
+
-webkit-font-feature-settings: "liga";
|
|
553
|
+
-webkit-font-smoothing: antialiased;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/* Bootstrap Icons specific styles */
|
|
557
|
+
[class^="bi-"],
|
|
558
|
+
[class*=" bi-"] {
|
|
559
|
+
font-family: bootstrap-icons !important;
|
|
560
|
+
font-style: normal;
|
|
561
|
+
font-weight: normal !important;
|
|
562
|
+
font-variant: normal;
|
|
563
|
+
text-transform: none;
|
|
564
|
+
line-height: 1;
|
|
565
|
+
-webkit-font-smoothing: antialiased;
|
|
566
|
+
-moz-osx-font-smoothing: grayscale;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Font Awesome Icons */
|
|
570
|
+
[class^="fa-"],
|
|
571
|
+
[class*=" fa-"],
|
|
572
|
+
[class~="fas"],
|
|
573
|
+
[class~="far"],
|
|
574
|
+
[class~="fal"],
|
|
575
|
+
[class~="fab"],
|
|
576
|
+
[class~="fad"] {
|
|
577
|
+
font-family: "Font Awesome 6 Free", "Font Awesome 6 Brands", "Font Awesome 6 Duotone", "Font Awesome 6 Pro";
|
|
578
|
+
font-style: normal;
|
|
579
|
+
font-weight: normal;
|
|
580
|
+
font-variant: normal;
|
|
581
|
+
text-transform: none;
|
|
582
|
+
line-height: 1;
|
|
583
|
+
-webkit-font-smoothing: antialiased;
|
|
584
|
+
-moz-osx-font-smoothing: grayscale;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/* Font weight adjustments for Font Awesome */
|
|
588
|
+
.fas,
|
|
589
|
+
.fa-solid {
|
|
590
|
+
font-weight: 900;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.far,
|
|
594
|
+
.fa-regular {
|
|
595
|
+
font-weight: 400;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.fal,
|
|
599
|
+
.fa-light {
|
|
600
|
+
font-weight: 300;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.fab,
|
|
604
|
+
.fa-brands {
|
|
605
|
+
font-family: "Font Awesome 6 Brands";
|
|
606
|
+
}
|
|
464
607
|
</style>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:
|
|
2
|
+
<component
|
|
3
|
+
:is="resolvedIconComponent"
|
|
4
|
+
v-if="resolvedIconComponent"
|
|
4
5
|
:class="[
|
|
5
6
|
'vc-lucide-icon',
|
|
6
7
|
!hasCustomSize && `vc-lucide-icon--${size}`,
|
|
@@ -9,12 +10,18 @@
|
|
|
9
10
|
:style="computedStyle"
|
|
10
11
|
aria-hidden="true"
|
|
11
12
|
/>
|
|
13
|
+
<span
|
|
14
|
+
v-else
|
|
15
|
+
:class="['vc-lucide-icon', !hasCustomSize && `vc-lucide-icon--${size}`]"
|
|
16
|
+
>
|
|
17
|
+
<i class="vc-lucide-icon__fallback">❓</i>
|
|
18
|
+
</span>
|
|
12
19
|
</template>
|
|
13
20
|
|
|
14
21
|
<script lang="ts" setup>
|
|
15
|
-
import { computed } from "vue";
|
|
16
|
-
import { Icon } from "@iconify/vue";
|
|
22
|
+
import { computed, markRaw, onMounted, ref } from "vue";
|
|
17
23
|
import type { IconSize, IconVariant } from "./types";
|
|
24
|
+
import type { Component } from "vue";
|
|
18
25
|
import { useIcon } from "./composables";
|
|
19
26
|
|
|
20
27
|
interface Props {
|
|
@@ -33,6 +40,11 @@ interface Props {
|
|
|
33
40
|
*/
|
|
34
41
|
variant?: IconVariant;
|
|
35
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Stroke width for SVG
|
|
45
|
+
*/
|
|
46
|
+
strokeWidth?: number;
|
|
47
|
+
|
|
36
48
|
/**
|
|
37
49
|
* Custom size in pixels
|
|
38
50
|
*/
|
|
@@ -41,11 +53,15 @@ interface Props {
|
|
|
41
53
|
|
|
42
54
|
const props = withDefaults(defineProps<Props>(), {
|
|
43
55
|
size: "m",
|
|
56
|
+
strokeWidth: 1.5,
|
|
44
57
|
});
|
|
45
58
|
|
|
46
59
|
// Check if using custom size to conditionally apply CSS class
|
|
47
60
|
const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
|
|
48
61
|
|
|
62
|
+
// Component reference for Lucide icon
|
|
63
|
+
const resolvedIconComponent = ref<Component | null>(null);
|
|
64
|
+
|
|
49
65
|
// Use the shared icon composable for consistent scaling
|
|
50
66
|
const { iconStyle } = useIcon({
|
|
51
67
|
type: "lucide",
|
|
@@ -54,40 +70,71 @@ const { iconStyle } = useIcon({
|
|
|
54
70
|
customSize: props.customSize,
|
|
55
71
|
});
|
|
56
72
|
|
|
73
|
+
// Normalize the icon name for Lucide
|
|
74
|
+
const normalizedIconName = computed(() => {
|
|
75
|
+
if (!props.icon) return "HelpCircleIcon";
|
|
76
|
+
|
|
77
|
+
// Handle removal of lucide- prefix
|
|
78
|
+
let name = props.icon;
|
|
79
|
+
if (name.startsWith("lucide-")) {
|
|
80
|
+
name = name.substring(7);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Ensure name ends with 'Icon'
|
|
84
|
+
if (!name.endsWith("Icon")) {
|
|
85
|
+
name = `${name}Icon`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Convert to PascalCase if kebab-case
|
|
89
|
+
if (name.includes("-")) {
|
|
90
|
+
name = name
|
|
91
|
+
.split("-")
|
|
92
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
93
|
+
.join("");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Ensure first letter is capitalized
|
|
97
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
57
100
|
// Combine the shared icon styles with Lucide-specific settings
|
|
58
101
|
const computedStyle = computed(() => {
|
|
59
102
|
const styles = { ...iconStyle.value };
|
|
60
103
|
|
|
104
|
+
if (props.strokeWidth) {
|
|
105
|
+
styles.strokeWidth = props.strokeWidth.toString();
|
|
106
|
+
}
|
|
107
|
+
|
|
61
108
|
// If using custom size, make sure size is applied with !important
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
109
|
+
if (hasCustomSize.value) {
|
|
110
|
+
if (styles.width) styles.width = `${styles.width.replace("px", "")}px !important`;
|
|
111
|
+
if (styles.height) styles.height = `${styles.height.replace("px", "")}px !important`;
|
|
112
|
+
}
|
|
66
113
|
|
|
67
114
|
return styles;
|
|
68
115
|
});
|
|
69
116
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
// Dynamically import the Lucide icon
|
|
118
|
+
onMounted(async () => {
|
|
119
|
+
try {
|
|
120
|
+
// Import from lucide-vue-next
|
|
121
|
+
const module = await import("lucide-vue-next");
|
|
122
|
+
|
|
123
|
+
// Get the icon component safely with type checking
|
|
124
|
+
const iconName = normalizedIconName.value;
|
|
125
|
+
if (module && typeof module === "object" && iconName in module) {
|
|
126
|
+
resolvedIconComponent.value = markRaw(module[iconName as keyof typeof module] as Component);
|
|
127
|
+
} else {
|
|
128
|
+
console.warn(`Lucide icon not found: ${iconName}`);
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error(`Error loading Lucide icon: ${normalizedIconName.value}`, error);
|
|
78
132
|
}
|
|
79
|
-
|
|
80
|
-
return `lucide:${name}`;
|
|
81
133
|
});
|
|
82
134
|
</script>
|
|
83
135
|
|
|
84
136
|
<style lang="scss">
|
|
85
137
|
.vc-lucide-icon {
|
|
86
|
-
& g,
|
|
87
|
-
& path {
|
|
88
|
-
stroke-width: var(--vc-lucide-icon-stroke-width, 1.5);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
138
|
display: inline-flex;
|
|
92
139
|
align-items: center;
|
|
93
140
|
justify-content: center;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
v-if="finalIconName"
|
|
4
|
-
:icon="finalIconName"
|
|
2
|
+
<span
|
|
5
3
|
:class="[
|
|
6
4
|
'vc-material-icon',
|
|
5
|
+
'material-symbols-' + type,
|
|
7
6
|
!hasCustomSize && `vc-material-icon--${size}`,
|
|
8
7
|
variant ? `vc-material-icon--${variant}` : '',
|
|
9
8
|
]"
|
|
10
|
-
:style="
|
|
9
|
+
:style="iconStyle"
|
|
11
10
|
aria-hidden="true"
|
|
12
|
-
|
|
11
|
+
>
|
|
12
|
+
{{ icon }}
|
|
13
|
+
</span>
|
|
13
14
|
</template>
|
|
14
15
|
|
|
15
16
|
<script lang="ts" setup>
|
|
16
|
-
import {
|
|
17
|
-
import { Icon, loadIcon } from "@iconify/vue";
|
|
17
|
+
import { computed } from "vue";
|
|
18
18
|
import type { IconSize, IconVariant } from "./types";
|
|
19
19
|
import { useIcon } from "./composables";
|
|
20
20
|
|
|
21
21
|
interface Props {
|
|
22
22
|
/**
|
|
23
|
-
* Material icon name
|
|
23
|
+
* Material icon name (e.g., "home", "settings", "account_circle")
|
|
24
24
|
*/
|
|
25
25
|
icon: string;
|
|
26
26
|
|
|
@@ -29,6 +29,11 @@ interface Props {
|
|
|
29
29
|
*/
|
|
30
30
|
size?: IconSize;
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Type of the Material icon (outlined, rounded, sharp)
|
|
34
|
+
*/
|
|
35
|
+
type?: "outlined" | "rounded" | "sharp";
|
|
36
|
+
|
|
32
37
|
/**
|
|
33
38
|
* Icon color variant
|
|
34
39
|
*/
|
|
@@ -42,57 +47,36 @@ interface Props {
|
|
|
42
47
|
|
|
43
48
|
const props = withDefaults(defineProps<Props>(), {
|
|
44
49
|
size: "m",
|
|
50
|
+
type: "outlined",
|
|
45
51
|
});
|
|
46
52
|
|
|
47
|
-
// Check if using custom size to conditionally apply CSS class
|
|
48
53
|
const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
|
|
49
54
|
|
|
50
|
-
// Use the shared icon composable for consistent scaling
|
|
51
55
|
const { iconStyle } = useIcon({
|
|
52
56
|
type: "material",
|
|
53
57
|
size: props.size,
|
|
54
58
|
variant: props.variant,
|
|
55
59
|
customSize: props.customSize,
|
|
56
60
|
});
|
|
57
|
-
|
|
58
|
-
const finalIconName = ref("");
|
|
59
|
-
|
|
60
|
-
watch(
|
|
61
|
-
() => props.icon,
|
|
62
|
-
(icon) => {
|
|
63
|
-
const collection = "material-symbols-light";
|
|
64
|
-
|
|
65
|
-
const cleanIconName = icon.replace(/_/g, "-");
|
|
66
|
-
const baseIcon = `${collection}:${cleanIconName}`;
|
|
67
|
-
const outlineIcon = `${collection}:${cleanIconName}-outline`;
|
|
68
|
-
|
|
69
|
-
loadIcon(outlineIcon)
|
|
70
|
-
.then(() => {
|
|
71
|
-
finalIconName.value = outlineIcon;
|
|
72
|
-
})
|
|
73
|
-
.catch(() => {
|
|
74
|
-
finalIconName.value = baseIcon;
|
|
75
|
-
});
|
|
76
|
-
},
|
|
77
|
-
{ immediate: true },
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
// Combine the shared icon styles with Material-specific settings
|
|
81
|
-
const computedStyle = computed(() => {
|
|
82
|
-
const styles = { ...iconStyle.value };
|
|
83
|
-
|
|
84
|
-
// font-variation-settings is not applicable for SVG icons
|
|
85
|
-
// If using custom size, make sure fontSize is applied with !important
|
|
86
|
-
if (hasCustomSize.value && styles.fontSize) {
|
|
87
|
-
styles.fontSize = `${styles.fontSize.replace("px", "")}px !important`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return styles;
|
|
91
|
-
});
|
|
92
61
|
</script>
|
|
93
62
|
|
|
94
63
|
<style lang="scss">
|
|
95
64
|
.vc-material-icon {
|
|
65
|
+
display: inline-flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
font-feature-settings: "liga"; // Enable ligatures for icons
|
|
69
|
+
font-style: normal;
|
|
70
|
+
font-weight: normal;
|
|
71
|
+
letter-spacing: normal;
|
|
72
|
+
line-height: 1;
|
|
73
|
+
text-transform: none;
|
|
74
|
+
white-space: nowrap;
|
|
75
|
+
word-wrap: normal;
|
|
76
|
+
-webkit-font-smoothing: antialiased;
|
|
77
|
+
text-rendering: optimizeLegibility;
|
|
78
|
+
|
|
79
|
+
// Sizes
|
|
96
80
|
&--xs {
|
|
97
81
|
font-size: var(--icon-size-xs);
|
|
98
82
|
}
|
|
@@ -121,6 +105,7 @@ const computedStyle = computed(() => {
|
|
|
121
105
|
font-size: var(--icon-size-xxxl);
|
|
122
106
|
}
|
|
123
107
|
|
|
108
|
+
// Variants
|
|
124
109
|
&--warning {
|
|
125
110
|
color: var(--icon-color-warning);
|
|
126
111
|
}
|
|
@@ -133,4 +118,11 @@ const computedStyle = computed(() => {
|
|
|
133
118
|
color: var(--icon-color-success);
|
|
134
119
|
}
|
|
135
120
|
}
|
|
121
|
+
|
|
122
|
+
// Base class provided by the @material-symbols/font-300 package
|
|
123
|
+
.material-symbols-outlined,
|
|
124
|
+
.material-symbols-rounded,
|
|
125
|
+
.material-symbols-sharp {
|
|
126
|
+
font-family: "Material Symbols Outlined", "Material Symbols Rounded", "Material Symbols Sharp";
|
|
127
|
+
}
|
|
136
128
|
</style>
|