@code-coaching/vuetiful 0.14.2 → 0.15.0
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/dist/style.css +1 -1
- package/dist/styles/all.css +77 -2
- package/dist/types/components/atoms/VAvatar.test.d.ts +1 -0
- package/dist/types/components/atoms/VAvatar.vue.d.ts +69 -0
- package/dist/types/components/atoms/index.d.ts +2 -1
- package/dist/types/utils/dark-mode/dark-mode.vue.d.ts +3 -3
- package/dist/types/utils/theme/theme-switcher.vue.d.ts +3 -3
- package/dist/vuetiful.es.mjs +58 -2
- package/dist/vuetiful.umd.js +9 -9
- package/package.json +1 -1
- package/src/components/atoms/VAvatar.test.ts +105 -0
- package/src/components/atoms/VAvatar.vue +51 -0
- package/src/components/atoms/index.ts +2 -0
package/package.json
CHANGED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { mount } from "@vue/test-utils";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
import { VAvatar } from ".";
|
|
4
|
+
|
|
5
|
+
test("VAvatar", () => {
|
|
6
|
+
expect(VAvatar).toBeTruthy();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe("VAvatar props", () => {
|
|
10
|
+
test("VAvatar defaults", () => {
|
|
11
|
+
const wrapper = mount(VAvatar);
|
|
12
|
+
|
|
13
|
+
expect(wrapper.classes()).toContain("avatar");
|
|
14
|
+
expect(wrapper.classes()).toContain("w-16");
|
|
15
|
+
expect(wrapper.classes()).toContain("rounded-token");
|
|
16
|
+
|
|
17
|
+
const avatarText = wrapper.find(".avatar-text");
|
|
18
|
+
expect(avatarText.exists()).toBe(true);
|
|
19
|
+
expect(avatarText.text()).toBe("");
|
|
20
|
+
expect(avatarText.classes()).toContain("dark:fill-on-surface-token");
|
|
21
|
+
expect(avatarText.classes()).toContain("fill-base-token");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("VAvatar initials", () => {
|
|
25
|
+
const wrapper = mount(VAvatar, {
|
|
26
|
+
props: {
|
|
27
|
+
initials: "JD",
|
|
28
|
+
class: "variant-filled",
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(wrapper.classes()).toContain("avatar");
|
|
33
|
+
expect(wrapper.classes()).toContain("w-16");
|
|
34
|
+
expect(wrapper.classes()).toContain("rounded-token");
|
|
35
|
+
|
|
36
|
+
const avatarText = wrapper.find(".avatar-text");
|
|
37
|
+
expect(avatarText.exists()).toBe(true);
|
|
38
|
+
expect(avatarText.text()).toBe("JD");
|
|
39
|
+
expect(avatarText.classes()).toContain("dark:fill-base-token");
|
|
40
|
+
expect(avatarText.classes()).toContain("fill-on-surface-token");
|
|
41
|
+
|
|
42
|
+
const avatarImage = wrapper.find(".avatar-image");
|
|
43
|
+
expect(avatarImage.exists()).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("VAvatar initials fill", () => {
|
|
47
|
+
const wrapper = mount(VAvatar, {
|
|
48
|
+
props: {
|
|
49
|
+
initials: "JD",
|
|
50
|
+
fill: "custom-fill-class",
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(wrapper.classes()).toContain("avatar");
|
|
55
|
+
expect(wrapper.classes()).toContain("w-16");
|
|
56
|
+
expect(wrapper.classes()).toContain("rounded-token");
|
|
57
|
+
|
|
58
|
+
const avatarText = wrapper.find(".avatar-text");
|
|
59
|
+
expect(avatarText.exists()).toBe(true);
|
|
60
|
+
expect(avatarText.text()).toBe("JD");
|
|
61
|
+
expect(avatarText.classes()).toContain("custom-fill-class");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("VAvatar image", () => {
|
|
65
|
+
const wrapper = mount(VAvatar, {
|
|
66
|
+
props: {
|
|
67
|
+
src: "https://via.placeholder.com/150",
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
expect(wrapper.classes()).toContain("avatar");
|
|
72
|
+
expect(wrapper.classes()).toContain("w-16");
|
|
73
|
+
expect(wrapper.classes()).toContain("rounded-token");
|
|
74
|
+
|
|
75
|
+
const avatarText = wrapper.find(".avatar-text");
|
|
76
|
+
expect(avatarText.exists()).toBe(false);
|
|
77
|
+
|
|
78
|
+
const avatarImage = wrapper.find(".avatar-image");
|
|
79
|
+
expect(avatarImage.exists()).toBe(true);
|
|
80
|
+
expect(avatarImage.attributes("src")).toBe("https://via.placeholder.com/150");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("VAvatar image fallback", async () => {
|
|
84
|
+
const wrapper = mount(VAvatar, {
|
|
85
|
+
props: {
|
|
86
|
+
src: "https://via.placeholder.com/150",
|
|
87
|
+
fallback: "/image/john-duck.png",
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(wrapper.classes()).toContain("avatar");
|
|
92
|
+
expect(wrapper.classes()).toContain("w-16");
|
|
93
|
+
expect(wrapper.classes()).toContain("rounded-token");
|
|
94
|
+
|
|
95
|
+
const avatarText = wrapper.find(".avatar-text");
|
|
96
|
+
expect(avatarText.exists()).toBe(false);
|
|
97
|
+
|
|
98
|
+
const avatarImage = wrapper.find(".avatar-image");
|
|
99
|
+
avatarImage.trigger("error");
|
|
100
|
+
await wrapper.vm.$nextTick();
|
|
101
|
+
|
|
102
|
+
expect(avatarImage.exists()).toBe(true);
|
|
103
|
+
expect(avatarImage.attributes("src")).toBe("/image/john-duck.png");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { CssClasses } from "@/index";
|
|
3
|
+
import { computed, ref, useAttrs } from "vue";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
// Initials
|
|
7
|
+
initials: { type: String, default: "" },
|
|
8
|
+
fill: { type: String as () => CssClasses, default: "" },
|
|
9
|
+
|
|
10
|
+
// Image
|
|
11
|
+
src: { type: String, default: "" },
|
|
12
|
+
alt: { type: String, default: "" },
|
|
13
|
+
fallback: { type: String, default: "" },
|
|
14
|
+
|
|
15
|
+
width: { type: String as () => CssClasses, default: "w-16" },
|
|
16
|
+
rounded: { type: String as () => CssClasses, default: "rounded-token" },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const imgSrc = ref(props.src);
|
|
20
|
+
const fillInitials = computed(() => {
|
|
21
|
+
if (props.fill) return props.fill;
|
|
22
|
+
|
|
23
|
+
const attrs = useAttrs();
|
|
24
|
+
const classString = attrs.class as string | undefined;
|
|
25
|
+
|
|
26
|
+
if (classString?.includes("variant-filled")) {
|
|
27
|
+
return "fill-on-surface-token dark:fill-base-token";
|
|
28
|
+
}
|
|
29
|
+
return "dark:fill-on-surface-token fill-base-token";
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
<template>
|
|
33
|
+
<figure
|
|
34
|
+
:class="`avatar isolate flex aspect-square items-center justify-center overflow-hidden font-semibold ${rounded} ${width}`"
|
|
35
|
+
>
|
|
36
|
+
<img class="avatar-image" v-if="src" :src="imgSrc" :alt="alt" @error="() => (imgSrc = fallback)" />
|
|
37
|
+
<svg v-else class="avatar-initials h-full w-full" viewBox="0 0 512 512">
|
|
38
|
+
<text
|
|
39
|
+
x="50%"
|
|
40
|
+
y="50%"
|
|
41
|
+
dominant-baseline="central"
|
|
42
|
+
text-anchor="middle"
|
|
43
|
+
font-weight="bold"
|
|
44
|
+
:font-size="150"
|
|
45
|
+
:class="`avatar-text ${fillInitials}`"
|
|
46
|
+
>
|
|
47
|
+
{{ String(initials).substring(0, 2).toUpperCase() }}
|
|
48
|
+
</text>
|
|
49
|
+
</svg>
|
|
50
|
+
</figure>
|
|
51
|
+
</template>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import VAvatar from "./VAvatar.vue";
|
|
1
2
|
import VBadge from "./VBadge.vue";
|
|
2
3
|
import VButton from "./VButton.vue";
|
|
3
4
|
import VChip from "./VChip.vue";
|
|
@@ -13,6 +14,7 @@ import VSwitchGroup from "./VSwitch/VSwitchGroup.vue";
|
|
|
13
14
|
import VSwitchLabel from "./VSwitch/VSwitchLabel.vue";
|
|
14
15
|
|
|
15
16
|
export {
|
|
17
|
+
VAvatar,
|
|
16
18
|
VButton,
|
|
17
19
|
VBadge,
|
|
18
20
|
VChip,
|