srcdev-nuxt-components 9.1.43 → 9.1.44

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.
@@ -0,0 +1,191 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { mountSuspended } from "@nuxt/test-utils/runtime";
3
+ import DisplayChip from "../DisplayChip.vue";
4
+
5
+ describe("DisplayChip", () => {
6
+ // ─── Mount ───────────────────────────────────────────────────────────────
7
+
8
+ it("mounts without error", async () => {
9
+ const wrapper = await mountSuspended(DisplayChip);
10
+ expect(wrapper.vm).toBeTruthy();
11
+ });
12
+
13
+ // ─── Snapshots ───────────────────────────────────────────────────────────
14
+
15
+ it("renders correct HTML structure (default)", async () => {
16
+ const wrapper = await mountSuspended(DisplayChip);
17
+ expect(wrapper.html()).toMatchSnapshot();
18
+ });
19
+
20
+ it("renders correct HTML structure (with label)", async () => {
21
+ const wrapper = await mountSuspended(DisplayChip, {
22
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", label: "5" } },
23
+ });
24
+ expect(wrapper.html()).toMatchSnapshot();
25
+ });
26
+
27
+ it("renders correct HTML structure (with icon)", async () => {
28
+ const wrapper = await mountSuspended(DisplayChip, {
29
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", icon: "mdi:check" } },
30
+ });
31
+ expect(wrapper.html()).toMatchSnapshot();
32
+ });
33
+
34
+ it("renders correct HTML structure (square + styleClassPassthrough)", async () => {
35
+ const wrapper = await mountSuspended(DisplayChip, {
36
+ props: { shape: "square", styleClassPassthrough: ["online"] },
37
+ });
38
+ expect(wrapper.html()).toMatchSnapshot();
39
+ });
40
+
41
+ // ─── Root element ─────────────────────────────────────────────────────────
42
+
43
+ it("renders as <span> by default", async () => {
44
+ const wrapper = await mountSuspended(DisplayChip);
45
+ expect(wrapper.element.tagName).toBe("SPAN");
46
+ });
47
+
48
+ it("renders as <div> when tag='div'", async () => {
49
+ const wrapper = await mountSuspended(DisplayChip, { props: { tag: "div" } });
50
+ expect(wrapper.element.tagName).toBe("DIV");
51
+ });
52
+
53
+ // ─── Base class ───────────────────────────────────────────────────────────
54
+
55
+ it("always has the display-chip-core class", async () => {
56
+ const wrapper = await mountSuspended(DisplayChip);
57
+ expect(wrapper.classes()).toContain("display-chip-core");
58
+ });
59
+
60
+ // ─── Shape ────────────────────────────────────────────────────────────────
61
+
62
+ it("applies circle class by default", async () => {
63
+ const wrapper = await mountSuspended(DisplayChip);
64
+ expect(wrapper.classes()).toContain("circle");
65
+ });
66
+
67
+ it("applies square class when shape='square'", async () => {
68
+ const wrapper = await mountSuspended(DisplayChip, { props: { shape: "square" } });
69
+ expect(wrapper.classes()).toContain("square");
70
+ expect(wrapper.classes()).not.toContain("circle");
71
+ });
72
+
73
+ // ─── CSS custom properties ────────────────────────────────────────────────
74
+
75
+ it("sets CSS custom properties from config", async () => {
76
+ const wrapper = await mountSuspended(DisplayChip, {
77
+ props: {
78
+ config: { size: "16px", maskWidth: "3px", offset: "4px", angle: "45deg" },
79
+ },
80
+ });
81
+ const style = (wrapper.element as HTMLElement).style;
82
+ expect(style.getPropertyValue("--chip-size")).toBe("16px");
83
+ expect(style.getPropertyValue("--chip-mask-width")).toBe("3px");
84
+ expect(style.getPropertyValue("--chip-offset")).toBe("4px");
85
+ expect(style.getPropertyValue("--chip-angle")).toBe("45deg");
86
+ });
87
+
88
+ it("sets default CSS custom properties when no config is provided", async () => {
89
+ const wrapper = await mountSuspended(DisplayChip);
90
+ const style = (wrapper.element as HTMLElement).style;
91
+ expect(style.getPropertyValue("--chip-size")).toBe("12px");
92
+ expect(style.getPropertyValue("--chip-mask-width")).toBe("4px");
93
+ expect(style.getPropertyValue("--chip-offset")).toBe("0px");
94
+ expect(style.getPropertyValue("--chip-angle")).toBe("90deg");
95
+ });
96
+
97
+ // ─── Label ────────────────────────────────────────────────────────────────
98
+
99
+ it("does not render .chip-label when config has no label", async () => {
100
+ const wrapper = await mountSuspended(DisplayChip);
101
+ expect(wrapper.find(".chip-label").exists()).toBe(false);
102
+ });
103
+
104
+ it("renders .chip-label when config.label is set", async () => {
105
+ const wrapper = await mountSuspended(DisplayChip, {
106
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", label: "5" } },
107
+ });
108
+ expect(wrapper.find(".chip-label").exists()).toBe(true);
109
+ expect(wrapper.find(".chip-label").text()).toBe("5");
110
+ });
111
+
112
+ it.each([
113
+ ["A", "length-1"],
114
+ ["+2", "length-2"],
115
+ ["DND", "length-3"],
116
+ ])("applies length class for label '%s'", async (label, expectedClass) => {
117
+ const wrapper = await mountSuspended(DisplayChip, {
118
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", label } },
119
+ });
120
+ expect(wrapper.find(".chip-label").classes()).toContain(expectedClass);
121
+ });
122
+
123
+ it("truncates label to 3 characters when label exceeds maximum length", async () => {
124
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
125
+ const wrapper = await mountSuspended(DisplayChip, {
126
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", label: "ABCD" } },
127
+ });
128
+ expect(wrapper.find(".chip-label").text()).toBe("ABC");
129
+ warnSpy.mockRestore();
130
+ });
131
+
132
+ it("emits a console warning when label exceeds 3 characters", async () => {
133
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
134
+ await mountSuspended(DisplayChip, {
135
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", label: "ABCD" } },
136
+ });
137
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("exceeds maximum length of 3 characters"));
138
+ warnSpy.mockRestore();
139
+ });
140
+
141
+ // ─── Icon ─────────────────────────────────────────────────────────────────
142
+
143
+ it("does not render .chip-icon when config has no icon", async () => {
144
+ const wrapper = await mountSuspended(DisplayChip);
145
+ expect(wrapper.find(".chip-icon").exists()).toBe(false);
146
+ });
147
+
148
+ it("renders .chip-icon when config.icon is set", async () => {
149
+ const wrapper = await mountSuspended(DisplayChip, {
150
+ props: { config: { size: "12px", maskWidth: "4px", offset: "0px", angle: "90deg", icon: "mdi:check" } },
151
+ });
152
+ expect(wrapper.find(".chip-icon").exists()).toBe(true);
153
+ });
154
+
155
+ // ─── Slot ─────────────────────────────────────────────────────────────────
156
+
157
+ it("renders default slot content", async () => {
158
+ const wrapper = await mountSuspended(DisplayChip, {
159
+ slots: { default: "<div class='avatar'>SRC</div>" },
160
+ });
161
+ expect(wrapper.find(".avatar").exists()).toBe(true);
162
+ expect(wrapper.find(".avatar").text()).toBe("SRC");
163
+ });
164
+
165
+ // ─── styleClassPassthrough ────────────────────────────────────────────────
166
+
167
+ it("applies a single styleClassPassthrough string", async () => {
168
+ const wrapper = await mountSuspended(DisplayChip, {
169
+ props: { styleClassPassthrough: "online" },
170
+ });
171
+ expect(wrapper.classes()).toContain("online");
172
+ });
173
+
174
+ it("applies multiple styleClassPassthrough classes from an array", async () => {
175
+ const wrapper = await mountSuspended(DisplayChip, {
176
+ props: { styleClassPassthrough: ["online", "featured"] },
177
+ });
178
+ expect(wrapper.classes()).toContain("online");
179
+ expect(wrapper.classes()).toContain("featured");
180
+ });
181
+
182
+ it("updates classes when styleClassPassthrough prop changes", async () => {
183
+ const wrapper = await mountSuspended(DisplayChip, {
184
+ props: { styleClassPassthrough: ["online"] },
185
+ });
186
+ expect(wrapper.classes()).toContain("online");
187
+ await wrapper.setProps({ styleClassPassthrough: ["idle"] });
188
+ expect(wrapper.classes()).not.toContain("online");
189
+ expect(wrapper.classes()).toContain("idle");
190
+ });
191
+ });
@@ -0,0 +1,12 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`DisplayChip > renders correct HTML structure (default) 1`] = `"<span class="display-chip-core circle" style="--chip-size: 12px; --chip-mask-width: 4px; --chip-offset: 0px; --chip-angle: 90deg;"><!--v-if--><!--v-if--></span>"`;
4
+
5
+ exports[`DisplayChip > renders correct HTML structure (square + styleClassPassthrough) 1`] = `"<span class="display-chip-core square online" style="--chip-size: 12px; --chip-mask-width: 4px; --chip-offset: 0px; --chip-angle: 90deg;"><!--v-if--><!--v-if--></span>"`;
6
+
7
+ exports[`DisplayChip > renders correct HTML structure (with icon) 1`] = `
8
+ "<span class="display-chip-core circle" style="--chip-size: 12px; --chip-mask-width: 4px; --chip-offset: 0px; --chip-angle: 90deg;"><span class="iconify i-mdi:check chip-icon" aria-hidden="true"></span>
9
+ <!--v-if--></span>"
10
+ `;
11
+
12
+ exports[`DisplayChip > renders correct HTML structure (with label) 1`] = `"<span class="display-chip-core circle" style="--chip-size: 12px; --chip-mask-width: 4px; --chip-offset: 0px; --chip-angle: 90deg;"><!--v-if--><span class="chip-label length-1">5</span></span>"`;
@@ -5,26 +5,71 @@
5
5
  <LayoutRow tag="div" variant="popout">
6
6
  <h1 class="page-heading-2">Display Chip</h1>
7
7
 
8
- <form>
9
- <div class="form-row">
10
- <div class="form-col">
11
- <label for="size">Size - {{ chipConfig.size }}</label>
12
- <input @input="changeSize" id="size" type="range" min="1" max="24" :value="12" />
13
- </div>
14
- <div class="form-col">
15
- <label for="maskWidth">Mask Width - {{ chipConfig.maskWidth }}</label>
16
- <input @input="changeMaskWidth" id="maskWidth" type="range" min="0" max="12" :value="4" />
17
- </div>
18
- <div class="form-col">
19
- <label for="offset">Offset - {{ chipConfig.offset }}</label>
20
- <input @input="changeOffset" id="offset" type="range" min="-12" max="12" :value="2" />
21
- </div>
22
- <div class="form-col">
23
- <label for="angle">Angle - {{ chipConfig.angle }}</label>
24
- <input @input="changeAngle" id="angle" type="range" min="0" max="360" :value="45" />
8
+ <!-- ── QA Panel (dev only) ───────────────────────────────── -->
9
+ <div v-if="isDev" class="qa-panel">
10
+ <details class="qa-panel__details">
11
+ <summary class="qa-panel__summary">
12
+ <span class="qa-panel__title">QA DisplayChip</span>
13
+ <code class="qa-panel__status">
14
+ size:{{ qaSize }}px · mask:{{ qaMaskWidth }}px · offset:{{ qaOffset }}px · angle:{{ qaAngle }}deg
15
+ </code>
16
+ </summary>
17
+ <div class="qa-panel__body">
18
+
19
+ <div class="qa-panel__group">
20
+ <span class="qa-panel__label">Size</span>
21
+ <div class="qa-panel__chips">
22
+ <button
23
+ v-for="preset in sizePresets"
24
+ :key="preset"
25
+ class="qa-panel__chip"
26
+ :class="{ 'is-active': qaSize === preset }"
27
+ @click="qaSize = preset"
28
+ >{{ preset }}px</button>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="qa-panel__group">
33
+ <span class="qa-panel__label">Mask Width</span>
34
+ <div class="qa-panel__chips">
35
+ <button
36
+ v-for="preset in maskWidthPresets"
37
+ :key="preset"
38
+ class="qa-panel__chip"
39
+ :class="{ 'is-active': qaMaskWidth === preset }"
40
+ @click="qaMaskWidth = preset"
41
+ >{{ preset }}px</button>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="qa-panel__group">
46
+ <span class="qa-panel__label">Offset</span>
47
+ <div class="qa-panel__chips">
48
+ <button
49
+ v-for="preset in offsetPresets"
50
+ :key="preset"
51
+ class="qa-panel__chip"
52
+ :class="{ 'is-active': qaOffset === preset }"
53
+ @click="qaOffset = preset"
54
+ >{{ preset }}px</button>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="qa-panel__group">
59
+ <span class="qa-panel__label">Angle — {{ qaAngle }}deg</span>
60
+ <input
61
+ v-model.number="qaAngle"
62
+ type="range"
63
+ min="0"
64
+ max="360"
65
+ step="1"
66
+ class="qa-panel__range"
67
+ />
68
+ </div>
69
+
25
70
  </div>
26
- </div>
27
- </form>
71
+ </details>
72
+ </div>
28
73
 
29
74
  <section>
30
75
  <div class="dl">
@@ -106,6 +151,8 @@
106
151
  </template>
107
152
 
108
153
  <script setup lang="ts">
154
+ import type { DisplayChipConfig } from "~/types/components";
155
+
109
156
  definePageMeta({
110
157
  layout: false,
111
158
  });
@@ -118,59 +165,148 @@ useHead({
118
165
  },
119
166
  });
120
167
 
121
- const chipConfig = reactive({
122
- size: "12px",
123
- maskWidth: "4px",
124
- offset: "2px",
125
- angle: "45deg",
126
- });
168
+ // ── QA controls (dev only) ────────────────────────────────────────
169
+ const isDev = import.meta.dev;
170
+
171
+ const qaSize = ref(12);
172
+ const qaMaskWidth = ref(4);
173
+ const qaOffset = ref(2);
174
+ const qaAngle = ref(45);
127
175
 
128
- const changeSize = (e: Event) => {
129
- const target = e.target as HTMLInputElement;
130
- chipConfig.size = `${target.value}px`;
131
- };
132
-
133
- const changeMaskWidth = (e: Event) => {
134
- const target = e.target as HTMLInputElement;
135
- chipConfig.maskWidth = `${target.value}px`;
136
- };
137
-
138
- const changeOffset = (e: Event) => {
139
- const target = e.target as HTMLInputElement;
140
- chipConfig.offset = `${target.value}px`;
141
- };
142
-
143
- const changeAngle = (e: Event) => {
144
- const target = e.target as HTMLInputElement;
145
- chipConfig.angle = `${target.value}deg`;
146
- };
176
+ const sizePresets = [8, 10, 12, 16, 20, 24];
177
+ const maskWidthPresets = [0, 2, 4, 6, 8];
178
+ const offsetPresets = [-4, 0, 2, 4, 8];
179
+
180
+ const chipConfig = computed((): DisplayChipConfig => ({
181
+ size: `${qaSize.value}px`,
182
+ maskWidth: `${qaMaskWidth.value}px`,
183
+ offset: `${qaOffset.value}px`,
184
+ angle: `${qaAngle.value}deg`,
185
+ }));
147
186
  </script>
148
187
 
149
188
  <style lang="css">
150
189
  .ui-display-chip-page {
151
- form {
152
- margin-bottom: 2rem;
153
-
154
- .form-row {
155
- .form-col {
156
- display: grid;
157
- grid-template-columns: 200px 200px;
158
- gap: 1rem;
159
- padding: 0.5rem 0;
160
-
161
- label {
162
- font-weight: bold;
163
- }
190
+ /* ── QA Panel ──────────────────────────────────────────────────── */
164
191
 
165
- input {
166
- padding: 0.5rem;
167
- border: 1px solid var(--slate-07);
168
- border-radius: 4px;
169
- font-size: 1rem;
170
- }
171
- }
192
+ .qa-panel {
193
+ background: oklch(15% 0 0);
194
+ color: white;
195
+ font-size: 1.3rem;
196
+ }
197
+
198
+ .qa-panel__details {
199
+ padding: 1rem 2rem;
200
+ }
201
+
202
+ .qa-panel__summary {
203
+ cursor: pointer;
204
+ display: flex;
205
+ align-items: center;
206
+ gap: 1.6rem;
207
+ list-style: none;
208
+ user-select: none;
209
+
210
+ &::-webkit-details-marker { display: none; }
211
+ }
212
+
213
+ .qa-panel__title {
214
+ font-weight: 600;
215
+ font-size: 1.1rem;
216
+ text-transform: uppercase;
217
+ letter-spacing: 0.08em;
218
+ }
219
+
220
+ .qa-panel__status {
221
+ font-family: monospace;
222
+ font-size: 1.2rem;
223
+ background: oklch(0% 0 0 / 0.3);
224
+ padding: 0.2rem 0.8rem;
225
+ border-radius: 0.4rem;
226
+ user-select: text;
227
+ cursor: text;
228
+ }
229
+
230
+ .qa-panel__body {
231
+ display: flex;
232
+ flex-wrap: wrap;
233
+ gap: 2.4rem;
234
+ padding-block: 1.2rem 0.4rem;
235
+ }
236
+
237
+ .qa-panel__group {
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: 0.6rem;
241
+ }
242
+
243
+ .qa-panel__label {
244
+ font-size: 1.1rem;
245
+ text-transform: uppercase;
246
+ letter-spacing: 0.08em;
247
+ opacity: 0.55;
248
+ }
249
+
250
+ .qa-panel__chips {
251
+ display: flex;
252
+ flex-wrap: wrap;
253
+ gap: 0.4rem;
254
+ }
255
+
256
+ .qa-panel__chip {
257
+ font-family: monospace;
258
+ font-size: 1.2rem;
259
+ color: white;
260
+ background: oklch(0% 0 0 / 0.25);
261
+ border: 1px solid oklch(100% 0 0 / 0.18);
262
+ padding: 0.3rem 1rem;
263
+ border-radius: 0.4rem;
264
+ cursor: pointer;
265
+ transition: background 0.15s;
266
+
267
+ &:hover { background: oklch(0% 0 0 / 0.4); }
268
+
269
+ &.is-active {
270
+ background: oklch(55% 0.18 240);
271
+ border-color: oklch(55% 0.18 240);
272
+ }
273
+ }
274
+
275
+ .qa-panel__range {
276
+ appearance: none;
277
+ width: 18rem;
278
+ height: 0.4rem;
279
+ background: oklch(100% 0 0 / 0.18);
280
+ border-radius: 0.4rem;
281
+ outline: none;
282
+ cursor: pointer;
283
+
284
+ &::-webkit-slider-thumb {
285
+ appearance: none;
286
+ width: 1.4rem;
287
+ height: 1.4rem;
288
+ border-radius: 50%;
289
+ background: oklch(55% 0.18 240);
290
+ cursor: pointer;
291
+ transition: background 0.15s;
292
+ }
293
+
294
+ &::-moz-range-thumb {
295
+ width: 1.4rem;
296
+ height: 1.4rem;
297
+ border: none;
298
+ border-radius: 50%;
299
+ background: oklch(55% 0.18 240);
300
+ cursor: pointer;
301
+ transition: background 0.15s;
172
302
  }
303
+
304
+ &:hover::-webkit-slider-thumb { background: oklch(62% 0.18 240); }
305
+ &:hover::-moz-range-thumb { background: oklch(62% 0.18 240); }
173
306
  }
307
+
308
+ /* ── Demo grid ─────────────────────────────────────────────────── */
309
+
174
310
  section {
175
311
  margin-top: 2rem;
176
312
 
@@ -181,11 +317,10 @@ const changeAngle = (e: Event) => {
181
317
  align-items: center;
182
318
  justify-content: start;
183
319
 
184
- /* background-color: var(--slate-05); */
185
-
186
320
  .dt {
187
321
  font-weight: bold;
188
322
  }
323
+
189
324
  .dd {
190
325
  margin: 0;
191
326
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.1.43",
4
+ "version": "9.1.44",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",
@@ -1,148 +0,0 @@
1
- <template>
2
- <component
3
- :is="props.chip ? DisplayChip : as"
4
- v-bind="props.chip ? (typeof props.chip === 'object' ? { config: props.chip } : { config: chipDefaultConfig }) : {}"
5
- class="display-avatar"
6
- :class="[size, elementClasses]"
7
- :style-class-passthrough="elementClasses"
8
- >
9
- <slot name="default">
10
- <NuxtImg v-if="src" :src :alt="alt || 'Avatar'" width="100%" height="100%" class="avatar-image" />
11
- <span v-else>{{ fallback }}</span>
12
- </slot>
13
- <slot name="icon"></slot>
14
- </component>
15
- </template>
16
-
17
- <script setup lang="ts">
18
- import DisplayChip from "../display-chip/DisplayChip.vue";
19
- import type { DisplayChipProps } from "../../types/components";
20
-
21
- export interface AvatarSlots {
22
- default(props?: {}): any;
23
- icon(props?: {}): any;
24
- }
25
-
26
- const props = defineProps({
27
- as: {
28
- type: [String, Object] as PropType<any>,
29
- default: "span",
30
- },
31
- src: {
32
- type: String,
33
- default: undefined,
34
- },
35
- alt: {
36
- type: String,
37
- default: undefined,
38
- },
39
- text: {
40
- type: String,
41
- default: undefined,
42
- },
43
- size: {
44
- type: String as PropType<"xs" | "s" | "md" | "lg" | "xl" | string>,
45
- default: "md",
46
- },
47
- chip: {
48
- type: [Boolean, Object] as PropType<boolean | DisplayChipProps>,
49
- default: undefined,
50
- },
51
- class: {
52
- type: [String, Array, Object] as PropType<any>,
53
- default: undefined,
54
- },
55
- style: {
56
- type: [String, Array, Object] as PropType<any>,
57
- default: undefined,
58
- },
59
- styleClassPassthrough: {
60
- type: [String, Array] as PropType<string | string[]>,
61
- default: () => [],
62
- },
63
- });
64
-
65
- defineSlots<AvatarSlots>();
66
-
67
- const { elementClasses, resetElementClasses, updateElementClasses } = useStyleClassPassthrough(
68
- props.styleClassPassthrough
69
- );
70
-
71
- if (props.chip && typeof props.chip === "object" && !("styleClassPassthrough" in props.chip)) {
72
- updateElementClasses(["display-avatar", props.size]);
73
- }
74
-
75
- const fallback = computed(
76
- () =>
77
- props.text ||
78
- (props.alt || "")
79
- .split(" ")
80
- .map((word) => word.charAt(0))
81
- .join("")
82
- .substring(0, 2)
83
- );
84
-
85
- const chipDefaultConfig = {
86
- size: "12px",
87
- maskWidth: "4px",
88
- offset: "0px",
89
- angle: "90deg",
90
- };
91
-
92
- watch(
93
- () => props.styleClassPassthrough,
94
- () => {
95
- resetElementClasses(props.styleClassPassthrough);
96
- }
97
- );
98
- </script>
99
-
100
- <style lang="css">
101
- @layer components {
102
- .display-avatar {
103
- display: flex;
104
- align-items: center;
105
- justify-content: center;
106
- border-radius: 50%;
107
- color: var(--slate-03);
108
-
109
- isolation: isolate;
110
-
111
- &.xs {
112
- width: 24px;
113
- height: 24px;
114
- font-size: 0.75rem;
115
- }
116
- &.s {
117
- width: 32px;
118
- height: 32px;
119
- font-size: 0.875rem;
120
- }
121
- &.md {
122
- width: 40px;
123
- height: 40px;
124
- font-size: 1rem;
125
- }
126
- &.lg {
127
- width: 48px;
128
- height: 48px;
129
- font-size: 1.125rem;
130
- }
131
- &.xl {
132
- width: 56px;
133
- height: 56px;
134
- font-size: 1.25rem;
135
- }
136
-
137
- .avatar-image {
138
- width: 100%;
139
- border-radius: 50%;
140
- object-fit: cover;
141
- }
142
-
143
- .avatar-icon {
144
- font-size: 24px;
145
- }
146
- }
147
- }
148
- </style>