@coffic/cosy-ui 0.9.84 → 0.9.85
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/src/components/avatar/avatarPropsBase.d.ts +19 -0
- package/dist/src/components/avatar/avatarPropsBase.d.ts.map +1 -0
- package/dist/src/components/avatar/avatarPropsBase.js +2 -0
- package/dist/src/components/avatar/avatarPropsBase.js.map +1 -0
- package/dist/src/components/avatar/avatarUtils.d.ts +35 -0
- package/dist/src/components/avatar/avatarUtils.d.ts.map +1 -0
- package/dist/src/components/avatar/avatarUtils.js +52 -0
- package/dist/src/components/avatar/avatarUtils.js.map +1 -0
- package/dist/src/components/avatar/index.d.ts +3 -0
- package/dist/src/components/avatar/index.d.ts.map +1 -0
- package/dist/src/components/avatar/index.js +2 -0
- package/dist/src/components/avatar/index.js.map +1 -0
- package/dist/src/components/card/cardPropsBase.d.ts +1 -1
- package/dist/src/components/card/cardPropsBase.d.ts.map +1 -1
- package/dist/src-astro/avatar/Avatar.astro +9 -35
- package/dist/src-astro/avatar/types.ts +7 -17
- package/dist/src-astro/card/Card.astro +6 -7
- package/dist/src-astro/card/props.ts +1 -1
- package/dist/src-vue/avatar/Avatar.vue +59 -82
- package/dist/src-vue/card/Card.vue +154 -148
- package/dist/src-vue/review/Review.vue +107 -112
- package/dist/src-vue/review/props.ts +9 -1
- package/package.json +88 -87
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar 组件的基础属性接口(与框架无关)
|
|
3
|
+
*/
|
|
4
|
+
export interface IAvatarPropsBase {
|
|
5
|
+
/**
|
|
6
|
+
* 用户名称
|
|
7
|
+
*/
|
|
8
|
+
userName?: string;
|
|
9
|
+
/**
|
|
10
|
+
* 用户头像URL
|
|
11
|
+
*/
|
|
12
|
+
avatar?: string;
|
|
13
|
+
/**
|
|
14
|
+
* 头像尺寸
|
|
15
|
+
* @default 'md'
|
|
16
|
+
*/
|
|
17
|
+
size?: "sm" | "md" | "lg" | "xl";
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=avatarPropsBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatarPropsBase.d.ts","sourceRoot":"","sources":["../../../../src/components/avatar/avatarPropsBase.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatarPropsBase.js","sourceRoot":"","sources":["../../../../src/components/avatar/avatarPropsBase.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar 组件的共用工具函数
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 尺寸映射类型
|
|
6
|
+
*/
|
|
7
|
+
export declare const avatarSizeClasses: {
|
|
8
|
+
readonly sm: "cosy:w-8 cosy:h-8 cosy:text-sm";
|
|
9
|
+
readonly md: "cosy:w-12 cosy:h-12 cosy:text-lg";
|
|
10
|
+
readonly lg: "cosy:w-16 cosy:h-16 cosy:text-xl";
|
|
11
|
+
readonly xl: "cosy:w-20 cosy:h-20 cosy:text-2xl";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* 头像背景色数组
|
|
15
|
+
*/
|
|
16
|
+
export declare const avatarColors: readonly ["cosy:bg-primary", "cosy:bg-secondary", "cosy:bg-accent", "cosy:bg-info", "cosy:bg-success", "cosy:bg-warning", "cosy:bg-error"];
|
|
17
|
+
/**
|
|
18
|
+
* 生成头像背景色
|
|
19
|
+
* @param userName 用户名称
|
|
20
|
+
* @returns 背景色类名
|
|
21
|
+
*/
|
|
22
|
+
export declare const getAvatarColor: (userName?: string) => string;
|
|
23
|
+
/**
|
|
24
|
+
* 获取用户名首字母(大写)
|
|
25
|
+
* @param userName 用户名称
|
|
26
|
+
* @returns 首字母或默认占位符
|
|
27
|
+
*/
|
|
28
|
+
export declare const getAvatarInitial: (userName?: string) => string;
|
|
29
|
+
/**
|
|
30
|
+
* 获取尺寸类名
|
|
31
|
+
* @param size 尺寸
|
|
32
|
+
* @returns 尺寸类名
|
|
33
|
+
*/
|
|
34
|
+
export declare const getAvatarSizeClass: (size?: keyof typeof avatarSizeClasses) => string;
|
|
35
|
+
//# sourceMappingURL=avatarUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatarUtils.d.ts","sourceRoot":"","sources":["../../../../src/components/avatar/avatarUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY,4IAQf,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,KAAG,MAIlD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,KAAG,MAEpD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAC9B,OAAM,MAAM,OAAO,iBAAwB,KACzC,MAEF,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Avatar 组件的共用工具函数
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 尺寸映射类型
|
|
6
|
+
*/
|
|
7
|
+
export const avatarSizeClasses = {
|
|
8
|
+
sm: "cosy:w-8 cosy:h-8 cosy:text-sm",
|
|
9
|
+
md: "cosy:w-12 cosy:h-12 cosy:text-lg",
|
|
10
|
+
lg: "cosy:w-16 cosy:h-16 cosy:text-xl",
|
|
11
|
+
xl: "cosy:w-20 cosy:h-20 cosy:text-2xl",
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* 头像背景色数组
|
|
15
|
+
*/
|
|
16
|
+
export const avatarColors = [
|
|
17
|
+
"cosy:bg-primary",
|
|
18
|
+
"cosy:bg-secondary",
|
|
19
|
+
"cosy:bg-accent",
|
|
20
|
+
"cosy:bg-info",
|
|
21
|
+
"cosy:bg-success",
|
|
22
|
+
"cosy:bg-warning",
|
|
23
|
+
"cosy:bg-error",
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* 生成头像背景色
|
|
27
|
+
* @param userName 用户名称
|
|
28
|
+
* @returns 背景色类名
|
|
29
|
+
*/
|
|
30
|
+
export const getAvatarColor = (userName) => {
|
|
31
|
+
if (!userName)
|
|
32
|
+
return avatarColors[0]; // 默认使用第一个颜色
|
|
33
|
+
const index = userName.charCodeAt(0) % avatarColors.length;
|
|
34
|
+
return avatarColors[index];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* 获取用户名首字母(大写)
|
|
38
|
+
* @param userName 用户名称
|
|
39
|
+
* @returns 首字母或默认占位符
|
|
40
|
+
*/
|
|
41
|
+
export const getAvatarInitial = (userName) => {
|
|
42
|
+
return userName ? userName.charAt(0).toUpperCase() : "?";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* 获取尺寸类名
|
|
46
|
+
* @param size 尺寸
|
|
47
|
+
* @returns 尺寸类名
|
|
48
|
+
*/
|
|
49
|
+
export const getAvatarSizeClass = (size = "md") => {
|
|
50
|
+
return avatarSizeClasses[size];
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=avatarUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatarUtils.js","sourceRoot":"","sources":["../../../../src/components/avatar/avatarUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAChC,EAAE,EAAE,gCAAgC;IACpC,EAAE,EAAE,kCAAkC;IACtC,EAAE,EAAE,kCAAkC;IACtC,EAAE,EAAE,mCAAmC;CAC9B,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC3B,iBAAiB;IACjB,mBAAmB;IACnB,gBAAgB;IAChB,cAAc;IACd,iBAAiB;IACjB,iBAAiB;IACjB,eAAe;CACN,CAAC;AAEX;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAiB,EAAU,EAAE;IAC3D,IAAI,CAAC,QAAQ;QAAE,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC;IAC3D,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAiB,EAAU,EAAE;IAC7D,OAAO,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;AAC1D,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,OAAuC,IAAI,EAClC,EAAE;IACX,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/avatar/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EACN,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/avatar/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GAClB,MAAM,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardPropsBase.d.ts","sourceRoot":"","sources":["../../../../src/components/card/cardPropsBase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"cardPropsBase.d.ts","sourceRoot":"","sources":["../../../../src/components/card/cardPropsBase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
2
|
/**
|
|
8
3
|
* @component Avatar
|
|
9
4
|
*
|
|
@@ -33,7 +28,7 @@
|
|
|
33
28
|
* ```
|
|
34
29
|
*
|
|
35
30
|
* @props
|
|
36
|
-
* @prop {string} userName - 用户名称
|
|
31
|
+
* @prop {string} [userName] - 用户名称
|
|
37
32
|
* @prop {string} [avatar] - 用户头像URL
|
|
38
33
|
* @prop {'sm'|'md'|'lg'|'xl'} [size='md'] - 头像尺寸
|
|
39
34
|
* @prop {string} [class] - 自定义类名
|
|
@@ -41,6 +36,11 @@
|
|
|
41
36
|
*/
|
|
42
37
|
|
|
43
38
|
import { cn } from '../../src/class';
|
|
39
|
+
import {
|
|
40
|
+
getAvatarColor,
|
|
41
|
+
getAvatarInitial,
|
|
42
|
+
getAvatarSizeClass,
|
|
43
|
+
} from '../../src/components/avatar/avatarUtils';
|
|
44
44
|
import type { AvatarProps } from './types';
|
|
45
45
|
|
|
46
46
|
type Props = AvatarProps;
|
|
@@ -54,33 +54,7 @@ const {
|
|
|
54
54
|
...rest
|
|
55
55
|
} = Astro.props;
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
const getSizeClasses = (size: 'sm' | 'md' | 'lg' | 'xl') => {
|
|
59
|
-
const sizeMap = {
|
|
60
|
-
sm: cn().add('cosy:w-8', 'cosy:h-8', 'cosy:text-sm').build(),
|
|
61
|
-
md: cn().add('cosy:w-12', 'cosy:h-12', 'cosy:text-lg').build(),
|
|
62
|
-
lg: cn().add('cosy:w-16', 'cosy:h-16', 'cosy:text-xl').build(),
|
|
63
|
-
xl: cn().add('cosy:w-20', 'cosy:h-20', 'cosy:text-2xl').build(),
|
|
64
|
-
};
|
|
65
|
-
return sizeMap[size];
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// 生成头像背景色 - 使用 class builder
|
|
69
|
-
const getAvatarColor = (userName: string) => {
|
|
70
|
-
const colors = [
|
|
71
|
-
cn().add('cosy:bg-primary').build(),
|
|
72
|
-
cn().add('cosy:bg-secondary').build(),
|
|
73
|
-
cn().add('cosy:bg-accent').build(),
|
|
74
|
-
cn().add('cosy:bg-info').build(),
|
|
75
|
-
cn().add('cosy:bg-success').build(),
|
|
76
|
-
cn().add('cosy:bg-warning').build(),
|
|
77
|
-
cn().add('cosy:bg-error').build(),
|
|
78
|
-
];
|
|
79
|
-
const index = userName.charCodeAt(0) % colors.length;
|
|
80
|
-
return colors[index];
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const sizeClass = getSizeClasses(size as 'sm' | 'md' | 'lg' | 'xl');
|
|
57
|
+
const sizeClass = getAvatarSizeClass(size as 'sm' | 'md' | 'lg' | 'xl');
|
|
84
58
|
|
|
85
59
|
// 使用 classBuilder 构建各个部分的类名
|
|
86
60
|
const avatarContainerClass = cn()
|
|
@@ -88,7 +62,7 @@ const avatarContainerClass = cn()
|
|
|
88
62
|
'cosy:avatar',
|
|
89
63
|
'cosy:rounded-full',
|
|
90
64
|
'cosy:overflow-hidden',
|
|
91
|
-
'cosy:
|
|
65
|
+
'cosy:shrink-0',
|
|
92
66
|
'cosy:bg-base-200',
|
|
93
67
|
)
|
|
94
68
|
.flex('row')
|
|
@@ -128,6 +102,6 @@ const avatarFallbackClass = cn()
|
|
|
128
102
|
<div
|
|
129
103
|
class={avatarFallbackClass}
|
|
130
104
|
style={avatar ? 'display: none;' : 'display: flex;'}>
|
|
131
|
-
{userName
|
|
105
|
+
{getAvatarInitial(userName)}
|
|
132
106
|
</div>
|
|
133
107
|
</div>
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
import type { HTMLAttributes } from "astro/types";
|
|
2
|
+
import type { IAvatarPropsBase } from "../../src/components/avatar/avatarPropsBase";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 用户头像URL
|
|
11
|
-
*/
|
|
12
|
-
avatar?: string;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 头像尺寸
|
|
16
|
-
* @default 'md'
|
|
17
|
-
*/
|
|
18
|
-
size?: "sm" | "md" | "lg" | "xl";
|
|
19
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Avatar 组件的 Astro 版本属性接口(继承基础接口并扩展 Astro 特定属性)
|
|
6
|
+
*/
|
|
7
|
+
export interface AvatarProps
|
|
8
|
+
extends IAvatarPropsBase,
|
|
9
|
+
Omit<HTMLAttributes<"div">, keyof IAvatarPropsBase> {
|
|
20
10
|
/**
|
|
21
11
|
* 自定义类名
|
|
22
12
|
*/
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
2
|
/**
|
|
6
3
|
* @component Card
|
|
7
4
|
*
|
|
@@ -203,15 +200,17 @@ const Tag = href ? 'a' : 'article';
|
|
|
203
200
|
{
|
|
204
201
|
imageUrl && (
|
|
205
202
|
<figure class={figureClass}>
|
|
206
|
-
<Image src={imageUrl} alt={title} class={imageClass} />
|
|
203
|
+
<Image src={imageUrl} alt={title || ''} class={imageClass} />
|
|
207
204
|
</figure>
|
|
208
205
|
)
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
<div class={cardBodyClass}>
|
|
212
|
-
|
|
213
|
-
{
|
|
214
|
-
|
|
209
|
+
{title && (
|
|
210
|
+
<h2 class={cardTitleClass}>
|
|
211
|
+
{title}
|
|
212
|
+
</h2>
|
|
213
|
+
)}
|
|
215
214
|
|
|
216
215
|
{subtitle && <p class={subtitleClass}>{subtitle}</p>}
|
|
217
216
|
|
|
@@ -9,7 +9,7 @@ import type { ImageSource } from "../image/types";
|
|
|
9
9
|
export interface ICardProps
|
|
10
10
|
extends ICardPropsBase,
|
|
11
11
|
Omit<IContainerProps, "class" | "backgroundImage" | "title">,
|
|
12
|
-
Omit<HTMLAttributes<"article">, "title"> {
|
|
12
|
+
Omit<HTMLAttributes<"article">, "title" | keyof ICardPropsBase> {
|
|
13
13
|
/**
|
|
14
14
|
* 自定义类名
|
|
15
15
|
*/
|
|
@@ -1,75 +1,55 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import type { IAvatarPropsBase } from '../../src/components/avatar/avatarPropsBase';
|
|
4
|
+
import {
|
|
5
|
+
avatarSizeClasses,
|
|
6
|
+
getAvatarColor,
|
|
7
|
+
getAvatarInitial,
|
|
8
|
+
} from '../../src/components/avatar/avatarUtils';
|
|
3
9
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @component Avatar
|
|
12
|
+
*
|
|
13
|
+
* @description
|
|
14
|
+
* Avatar 组件用于显示用户头像,支持真实头像和默认头像生成。
|
|
15
|
+
* 当没有提供头像URL或头像加载失败时,自动生成带用户首字母的彩色圆形头像。
|
|
16
|
+
*
|
|
17
|
+
* @usage
|
|
18
|
+
* 基本用法:
|
|
19
|
+
* ```vue
|
|
20
|
+
* <Avatar userName="张先生" />
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* 带真实头像:
|
|
24
|
+
* ```vue
|
|
25
|
+
* <Avatar userName="李女士" avatar="https://example.com/avatar.jpg" />
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* 不同尺寸:
|
|
29
|
+
* ```vue
|
|
30
|
+
* <Avatar userName="王先生" size="lg" />
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @props
|
|
34
|
+
* @prop {string} [userName] - 用户名称
|
|
35
|
+
* @prop {string} [avatar] - 用户头像URL
|
|
36
|
+
* @prop {'sm'|'md'|'lg'|'xl'} [size='md'] - 头像尺寸
|
|
37
|
+
* @prop {string} [class] - 自定义类名
|
|
38
|
+
* @prop {any} [class:list] - 类名列表
|
|
39
|
+
*/
|
|
34
40
|
|
|
35
|
-
export interface IAvatarProps {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class?: string;
|
|
40
|
-
"class:list"?: any;
|
|
41
|
-
}
|
|
41
|
+
export interface IAvatarProps extends IAvatarPropsBase {
|
|
42
|
+
class?: string;
|
|
43
|
+
'class:list'?: any;
|
|
44
|
+
}
|
|
42
45
|
|
|
43
|
-
const props = withDefaults(defineProps<IAvatarProps>(), {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
});
|
|
46
|
+
const props = withDefaults(defineProps<IAvatarProps>(), {
|
|
47
|
+
size: 'md',
|
|
48
|
+
class: '',
|
|
49
|
+
});
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
sm: "cosy:w-8 cosy:h-8 cosy:text-sm",
|
|
51
|
-
md: "cosy:w-12 cosy:h-12 cosy:text-lg",
|
|
52
|
-
lg: "cosy:w-16 cosy:h-16 cosy:text-xl",
|
|
53
|
-
xl: "cosy:w-20 cosy:h-20 cosy:text-2xl",
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// 生成头像背景色
|
|
57
|
-
const getAvatarColor = (userName: string) => {
|
|
58
|
-
const colors = [
|
|
59
|
-
"cosy:bg-primary",
|
|
60
|
-
"cosy:bg-secondary",
|
|
61
|
-
"cosy:bg-accent",
|
|
62
|
-
"cosy:bg-info",
|
|
63
|
-
"cosy:bg-success",
|
|
64
|
-
"cosy:bg-warning",
|
|
65
|
-
"cosy:bg-error",
|
|
66
|
-
];
|
|
67
|
-
const index = userName.charCodeAt(0) % colors.length;
|
|
68
|
-
return colors[index];
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const sizeClass = computed(() => sizeClasses[props.size]);
|
|
72
|
-
const avatarColor = computed(() => getAvatarColor(props.userName));
|
|
51
|
+
const sizeClass = computed(() => avatarSizeClasses[props.size || 'md']);
|
|
52
|
+
const avatarColor = computed(() => getAvatarColor(props.userName));
|
|
73
53
|
</script>
|
|
74
54
|
|
|
75
55
|
<template>
|
|
@@ -78,7 +58,7 @@ const avatarColor = computed(() => getAvatarColor(props.userName));
|
|
|
78
58
|
'cosy:avatar',
|
|
79
59
|
'cosy:rounded-full',
|
|
80
60
|
'cosy:overflow-hidden',
|
|
81
|
-
'cosy:
|
|
61
|
+
'cosy:shrink-0',
|
|
82
62
|
'cosy:bg-base-200',
|
|
83
63
|
'cosy:flex',
|
|
84
64
|
'cosy:items-center',
|
|
@@ -87,15 +67,13 @@ const avatarColor = computed(() => getAvatarColor(props.userName));
|
|
|
87
67
|
props.class,
|
|
88
68
|
props['class:list'],
|
|
89
69
|
]"
|
|
90
|
-
v-bind="$attrs"
|
|
91
|
-
>
|
|
70
|
+
v-bind="$attrs">
|
|
92
71
|
<img
|
|
93
72
|
v-if="avatar"
|
|
94
73
|
:src="avatar"
|
|
95
74
|
:alt="userName"
|
|
96
75
|
class="cosy:w-full cosy:h-full cosy:object-cover"
|
|
97
|
-
@error="handleImageError"
|
|
98
|
-
/>
|
|
76
|
+
@error="handleImageError" />
|
|
99
77
|
<!-- 默认头像 -->
|
|
100
78
|
<div
|
|
101
79
|
:class="[
|
|
@@ -103,19 +81,18 @@ const avatarColor = computed(() => getAvatarColor(props.userName));
|
|
|
103
81
|
avatarColor,
|
|
104
82
|
'cosy:text-white cosy:flex cosy:items-center cosy:justify-center cosy:font-semibold',
|
|
105
83
|
]"
|
|
106
|
-
:style="avatar ? 'display: none;' : 'display: flex;'"
|
|
107
|
-
|
|
108
|
-
{{ userName ? userName.charAt(0).toUpperCase() : '?' }}
|
|
84
|
+
:style="avatar ? 'display: none;' : 'display: flex;'">
|
|
85
|
+
{{ getAvatarInitial(userName) }}
|
|
109
86
|
</div>
|
|
110
87
|
</div>
|
|
111
88
|
</template>
|
|
112
89
|
|
|
113
90
|
<script lang="ts">
|
|
114
|
-
// 处理图片加载错误
|
|
115
|
-
const handleImageError = (event: Event) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
91
|
+
// 处理图片加载错误
|
|
92
|
+
const handleImageError = (event: Event) => {
|
|
93
|
+
const img = event.target as HTMLImageElement;
|
|
94
|
+
const nextElement = img.nextElementSibling as HTMLElement;
|
|
95
|
+
if (img) img.style.display = 'none';
|
|
96
|
+
if (nextElement) nextElement.style.display = 'flex';
|
|
97
|
+
};
|
|
121
98
|
</script>
|
|
@@ -1,160 +1,164 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from
|
|
3
|
-
import Container from
|
|
4
|
-
import { getCardCombinedClassesVue, getCardPaddingClassVue } from
|
|
5
|
-
import type { ICardProps } from
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import Container from '../container/Container.vue';
|
|
4
|
+
import { getCardCombinedClassesVue, getCardPaddingClassVue } from './class';
|
|
5
|
+
import type { ICardProps } from './props';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @component Card
|
|
9
|
+
* @description Vue 版本的 Card 组件,用于在页面中展示相关内容的容器,通常包含标题、描述和可选的图片
|
|
10
|
+
* @props {string} title - 卡片标题(必填)
|
|
11
|
+
* @props {string} [subtitle] - 卡片副标题或描述
|
|
12
|
+
* @props {string} [imageUrl] - 卡片顶部图片的URL
|
|
13
|
+
* @props {string} [href] - 如果提供,卡片将变成可点击的链接
|
|
14
|
+
* @props {boolean} [compact=false] - 是否使用紧凑模式
|
|
15
|
+
* @props {boolean} [muted=false] - 是否使用柔和色样式(未激活状态)
|
|
16
|
+
* @props {ShadowSize} [shadow=xl] - 阴影大小
|
|
17
|
+
* @props {string} [class] - 自定义CSS类,可用于覆盖默认样式
|
|
18
|
+
*/
|
|
19
19
|
|
|
20
|
-
defineOptions({
|
|
21
|
-
|
|
22
|
-
});
|
|
20
|
+
defineOptions({
|
|
21
|
+
name: 'Card',
|
|
22
|
+
});
|
|
23
23
|
|
|
24
|
-
const props = withDefaults(defineProps<ICardProps>(), {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
24
|
+
const props = withDefaults(defineProps<ICardProps>(), {
|
|
25
|
+
class: '',
|
|
26
|
+
compact: false,
|
|
27
|
+
muted: false,
|
|
28
|
+
shadow: 'xl',
|
|
29
|
+
});
|
|
30
30
|
|
|
31
|
-
// 从props中分离Container相关的属性和Card自身的属性
|
|
32
|
-
const containerProps = computed(() => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
31
|
+
// 从props中分离Container相关的属性和Card自身的属性
|
|
32
|
+
const containerProps = computed(() => {
|
|
33
|
+
const {
|
|
34
|
+
// Container属性
|
|
35
|
+
aspectRatio,
|
|
36
|
+
centered,
|
|
37
|
+
contentCentered,
|
|
38
|
+
flex,
|
|
39
|
+
fit,
|
|
40
|
+
gap,
|
|
41
|
+
height,
|
|
42
|
+
items,
|
|
43
|
+
justify,
|
|
44
|
+
margin,
|
|
45
|
+
muted,
|
|
46
|
+
padding,
|
|
47
|
+
py,
|
|
48
|
+
pt,
|
|
49
|
+
pb,
|
|
50
|
+
px,
|
|
51
|
+
pl,
|
|
52
|
+
pr,
|
|
53
|
+
width,
|
|
54
|
+
rounded,
|
|
55
|
+
background,
|
|
56
|
+
border,
|
|
57
|
+
borderColor,
|
|
58
|
+
shadow,
|
|
59
|
+
// Card属性
|
|
60
|
+
class: className,
|
|
61
|
+
compact,
|
|
62
|
+
href,
|
|
63
|
+
imageUrl,
|
|
64
|
+
subtitle,
|
|
65
|
+
title,
|
|
66
|
+
...rest
|
|
67
|
+
} = props;
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
69
|
+
return {
|
|
70
|
+
aspectRatio,
|
|
71
|
+
centered,
|
|
72
|
+
contentCentered,
|
|
73
|
+
flex,
|
|
74
|
+
fit,
|
|
75
|
+
gap,
|
|
76
|
+
height,
|
|
77
|
+
items,
|
|
78
|
+
justify,
|
|
79
|
+
margin,
|
|
80
|
+
muted,
|
|
81
|
+
padding,
|
|
82
|
+
py,
|
|
83
|
+
pt,
|
|
84
|
+
pb,
|
|
85
|
+
px,
|
|
86
|
+
pl,
|
|
87
|
+
pr,
|
|
88
|
+
width,
|
|
89
|
+
rounded,
|
|
90
|
+
background,
|
|
91
|
+
border,
|
|
92
|
+
borderColor,
|
|
93
|
+
shadow,
|
|
94
|
+
class: className,
|
|
95
|
+
...rest,
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
98
|
|
|
99
|
-
// Card自身的属性
|
|
100
|
-
const cardProps = computed(() => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
99
|
+
// Card自身的属性
|
|
100
|
+
const cardProps = computed(() => {
|
|
101
|
+
const {
|
|
102
|
+
// Container属性
|
|
103
|
+
aspectRatio,
|
|
104
|
+
centered,
|
|
105
|
+
contentCentered,
|
|
106
|
+
flex,
|
|
107
|
+
fit,
|
|
108
|
+
gap,
|
|
109
|
+
height,
|
|
110
|
+
items,
|
|
111
|
+
justify,
|
|
112
|
+
margin,
|
|
113
|
+
muted,
|
|
114
|
+
padding,
|
|
115
|
+
py,
|
|
116
|
+
pt,
|
|
117
|
+
pb,
|
|
118
|
+
px,
|
|
119
|
+
pl,
|
|
120
|
+
pr,
|
|
121
|
+
width,
|
|
122
|
+
rounded,
|
|
123
|
+
background,
|
|
124
|
+
border,
|
|
125
|
+
borderColor,
|
|
126
|
+
shadow,
|
|
127
|
+
// Card属性
|
|
128
|
+
class: className,
|
|
129
|
+
compact,
|
|
130
|
+
href,
|
|
131
|
+
imageUrl,
|
|
132
|
+
subtitle,
|
|
133
|
+
title,
|
|
134
|
+
...rest
|
|
135
|
+
} = props;
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
137
|
+
return {
|
|
138
|
+
class: className,
|
|
139
|
+
compact,
|
|
140
|
+
href,
|
|
141
|
+
imageUrl,
|
|
142
|
+
subtitle,
|
|
143
|
+
title,
|
|
144
|
+
...rest,
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
147
|
|
|
148
|
-
// 使用共用的工具函数计算组合类名(不包括Container的类名)
|
|
149
|
-
const cardClasses = computed(() =>
|
|
148
|
+
// 使用共用的工具函数计算组合类名(不包括Container的类名)
|
|
149
|
+
const cardClasses = computed(() =>
|
|
150
|
+
getCardCombinedClassesVue(cardProps.value)
|
|
151
|
+
);
|
|
150
152
|
|
|
151
|
-
// 内容区域的padding类
|
|
152
|
-
const contentPadding = computed(() =>
|
|
153
|
-
|
|
154
|
-
);
|
|
153
|
+
// 内容区域的padding类
|
|
154
|
+
const contentPadding = computed(() =>
|
|
155
|
+
getCardPaddingClassVue(cardProps.value.compact)
|
|
156
|
+
);
|
|
155
157
|
|
|
156
|
-
// 链接的目标属性
|
|
157
|
-
const linkTarget = computed(() =>
|
|
158
|
+
// 链接的目标属性
|
|
159
|
+
const linkTarget = computed(() =>
|
|
160
|
+
cardProps.value.href ? '_self' : undefined
|
|
161
|
+
);
|
|
158
162
|
</script>
|
|
159
163
|
|
|
160
164
|
<template>
|
|
@@ -168,12 +172,14 @@ const linkTarget = computed(() => (cardProps.value.href ? "_self" : undefined));
|
|
|
168
172
|
<figure class="not-prose cosy:m-0 cosy:p-0">
|
|
169
173
|
<img
|
|
170
174
|
:src="cardProps.imageUrl"
|
|
171
|
-
:alt="cardProps.title"
|
|
175
|
+
:alt="cardProps.title || ''"
|
|
172
176
|
class="cosy:w-full cosy:h-48 cosy:object-cover cosy:rounded-t-lg" />
|
|
173
177
|
</figure>
|
|
174
178
|
</template>
|
|
175
179
|
<div :class="['cosy:card-body', contentPadding]">
|
|
176
|
-
<h2
|
|
180
|
+
<h2
|
|
181
|
+
v-if="cardProps.title"
|
|
182
|
+
class="cosy:card-title cosy:text-xl cosy:font-bold">
|
|
177
183
|
{{ cardProps.title }}
|
|
178
184
|
</h2>
|
|
179
185
|
<p
|
|
@@ -1,85 +1,80 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from
|
|
3
|
-
import Avatar from
|
|
4
|
-
import Badge from
|
|
5
|
-
import Card from
|
|
6
|
-
import SmartIcon from
|
|
7
|
-
import Text from
|
|
8
|
-
import type { IReviewProps } from
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import Avatar from '../avatar/Avatar.vue';
|
|
4
|
+
import Badge from '../badge/Badge.vue';
|
|
5
|
+
import Card from '../card/Card.vue';
|
|
6
|
+
import SmartIcon from '../smart-icon/SmartIcon.vue';
|
|
7
|
+
import Text from '../text/Text.vue';
|
|
8
|
+
import type { IReviewProps } from './props';
|
|
9
9
|
|
|
10
|
-
interface Props extends /* @vue-ignore */ IReviewProps {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
10
|
+
interface Props extends /* @vue-ignore */ IReviewProps {
|
|
11
|
+
class?: string;
|
|
12
|
+
'class:list'?: any;
|
|
13
|
+
}
|
|
14
14
|
|
|
15
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
15
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
+
verified: false,
|
|
17
|
+
class: '',
|
|
18
|
+
});
|
|
19
19
|
|
|
20
|
-
// 从props中分离Card相关的属性和Review自身的属性
|
|
21
|
-
const {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
title,
|
|
57
|
-
imageUrl,
|
|
58
|
-
href,
|
|
59
|
-
compact,
|
|
60
|
-
} = props;
|
|
20
|
+
// 从props中分离Card相关的属性和Review自身的属性
|
|
21
|
+
const {
|
|
22
|
+
userName,
|
|
23
|
+
rating,
|
|
24
|
+
comment,
|
|
25
|
+
date,
|
|
26
|
+
verified,
|
|
27
|
+
avatar,
|
|
28
|
+
class: className,
|
|
29
|
+
'class:list': classList,
|
|
30
|
+
// Card属性
|
|
31
|
+
aspectRatio,
|
|
32
|
+
centered,
|
|
33
|
+
contentCentered,
|
|
34
|
+
flex,
|
|
35
|
+
fit,
|
|
36
|
+
gap,
|
|
37
|
+
height,
|
|
38
|
+
items,
|
|
39
|
+
justify,
|
|
40
|
+
margin,
|
|
41
|
+
muted,
|
|
42
|
+
padding,
|
|
43
|
+
py,
|
|
44
|
+
pt,
|
|
45
|
+
pb,
|
|
46
|
+
px,
|
|
47
|
+
pl,
|
|
48
|
+
pr,
|
|
49
|
+
shadow,
|
|
50
|
+
width,
|
|
51
|
+
rounded,
|
|
52
|
+
background,
|
|
53
|
+
border,
|
|
54
|
+
borderColor,
|
|
55
|
+
} = props;
|
|
61
56
|
|
|
62
|
-
// 生成星级评分
|
|
63
|
-
const starArray = computed(() => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
});
|
|
57
|
+
// 生成星级评分
|
|
58
|
+
const starArray = computed(() => {
|
|
59
|
+
return Array.from({ length: 5 }, (_, i) => ({
|
|
60
|
+
filled: i < Math.floor(props.rating),
|
|
61
|
+
half: i === Math.floor(props.rating) && props.rating % 1 !== 0,
|
|
62
|
+
}));
|
|
63
|
+
});
|
|
69
64
|
|
|
70
|
-
// 格式化日期
|
|
71
|
-
const formattedDate = computed(() => {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
});
|
|
65
|
+
// 格式化日期
|
|
66
|
+
const formattedDate = computed(() => {
|
|
67
|
+
if (!props.date) return '';
|
|
68
|
+
try {
|
|
69
|
+
return new Date(props.date).toLocaleDateString('zh-CN', {
|
|
70
|
+
year: 'numeric',
|
|
71
|
+
month: '2-digit',
|
|
72
|
+
day: '2-digit',
|
|
73
|
+
});
|
|
74
|
+
} catch {
|
|
75
|
+
return props.date;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
83
78
|
</script>
|
|
84
79
|
|
|
85
80
|
<template>
|
|
@@ -109,49 +104,49 @@ const formattedDate = computed(() => {
|
|
|
109
104
|
border,
|
|
110
105
|
borderColor,
|
|
111
106
|
shadow,
|
|
112
|
-
subtitle,
|
|
113
|
-
title: userName, // 将 userName 作为 title 传递给 Card 组件
|
|
114
|
-
imageUrl,
|
|
115
|
-
href,
|
|
116
|
-
compact,
|
|
117
107
|
}"
|
|
118
|
-
:class="className"
|
|
108
|
+
:class="[className, 'cosy:review', 'cosy:p-6']"
|
|
119
109
|
:class:list="classList">
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
class="cosy:flex-shrink-0" />
|
|
110
|
+
<!-- 用户信息 -->
|
|
111
|
+
<div class="cosy:flex cosy:items-center cosy:gap-3 cosy:mb-3">
|
|
112
|
+
<!-- 用户头像 -->
|
|
113
|
+
<Avatar :userName="userName" :avatar="avatar" size="md" />
|
|
114
|
+
|
|
115
|
+
<!-- 用户名称和认证状态 -->
|
|
127
116
|
<div class="cosy:flex-1">
|
|
128
|
-
<div class="cosy:flex cosy:items-center cosy:
|
|
129
|
-
<Text
|
|
117
|
+
<div class="cosy:flex cosy:items-center cosy:gap-2 cosy:mb-1">
|
|
118
|
+
<Text class="cosy:font-medium cosy:text-base-content">
|
|
130
119
|
{{ userName }}
|
|
131
120
|
</Text>
|
|
132
|
-
<Badge v-if="verified" variant="success" size="sm">
|
|
133
|
-
<SmartIcon name="check-circle" class="cosy:w-4 cosy:h-4" />
|
|
134
|
-
已认证
|
|
135
|
-
</Badge>
|
|
136
|
-
</div>
|
|
137
|
-
<div class="cosy:flex cosy:items-center cosy:mt-1">
|
|
138
|
-
<div class="cosy:flex cosy:space-x-1">
|
|
139
|
-
<SmartIcon
|
|
140
|
-
v-for="(star, index) in starArray"
|
|
141
|
-
:key="index"
|
|
142
|
-
:name="
|
|
143
|
-
star.filled ? 'star-filled' : star.half ? 'star-half' : 'star'
|
|
144
|
-
"
|
|
145
|
-
class="cosy:w-5 cosy:h-5 cosy:text-yellow-400" />
|
|
146
|
-
</div>
|
|
147
|
-
<Text variant="small" class="cosy:ml-2 cosy:text-gray-500">
|
|
148
|
-
{{ formattedDate }}
|
|
149
|
-
</Text>
|
|
121
|
+
<Badge v-if="verified" variant="success" size="sm"> 已认证 </Badge>
|
|
150
122
|
</div>
|
|
151
|
-
<Text variant="p" class="cosy:mt-3">
|
|
152
|
-
{{ comment }}
|
|
153
|
-
</Text>
|
|
154
123
|
</div>
|
|
155
124
|
</div>
|
|
125
|
+
|
|
126
|
+
<!-- 评分 -->
|
|
127
|
+
<div class="cosy:flex cosy:items-center cosy:gap-1 cosy:mb-3">
|
|
128
|
+
<SmartIcon
|
|
129
|
+
v-for="(star, index) in starArray"
|
|
130
|
+
:key="index"
|
|
131
|
+
keyword="star"
|
|
132
|
+
size="16px"
|
|
133
|
+
:class="
|
|
134
|
+
star.filled || star.half ? 'cosy:text-warning' : 'cosy:text-base-300'
|
|
135
|
+
" />
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<!-- 评论内容 -->
|
|
139
|
+
<div class="cosy:mb-3">
|
|
140
|
+
<Text class="cosy:text-base-content/80 cosy:leading-relaxed">
|
|
141
|
+
{{ comment }}
|
|
142
|
+
</Text>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<!-- 评价日期 -->
|
|
146
|
+
<div v-if="date">
|
|
147
|
+
<Text size="sm" class="cosy:text-base-content/50">
|
|
148
|
+
{{ formattedDate }}
|
|
149
|
+
</Text>
|
|
150
|
+
</div>
|
|
156
151
|
</Card>
|
|
157
152
|
</template>
|
|
@@ -10,7 +10,15 @@ import type { ICardProps } from "../card/props";
|
|
|
10
10
|
*/
|
|
11
11
|
export interface IReviewProps
|
|
12
12
|
extends IReviewPropsBase,
|
|
13
|
-
Omit<
|
|
13
|
+
Omit<
|
|
14
|
+
ICardProps,
|
|
15
|
+
| keyof IReviewPropsBase
|
|
16
|
+
| "title"
|
|
17
|
+
| "subtitle"
|
|
18
|
+
| "imageUrl"
|
|
19
|
+
| "href"
|
|
20
|
+
| "compact"
|
|
21
|
+
> {
|
|
14
22
|
/**
|
|
15
23
|
* 自定义类名
|
|
16
24
|
*/
|
package/package.json
CHANGED
|
@@ -1,89 +1,90 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
2
|
+
"name": "@coffic/cosy-ui",
|
|
3
|
+
"version": "0.9.85",
|
|
4
|
+
"description": "An astro component library",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "nookery",
|
|
7
|
+
"url": "https://github.com/nookery"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"url": "https://github.com/CosyZone/cosy-ui"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"astro-integration",
|
|
15
|
+
"astro-component",
|
|
16
|
+
"withastro",
|
|
17
|
+
"astro",
|
|
18
|
+
"cosy-ui"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://ui.coffic.cn/en",
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": [
|
|
25
|
+
"*.css",
|
|
26
|
+
"style.ts",
|
|
27
|
+
"dist/style.ts"
|
|
28
|
+
],
|
|
29
|
+
"main": "./dist/index-astro.ts",
|
|
30
|
+
"module": "./dist/index-astro.ts",
|
|
31
|
+
"types": "./dist/index-astro.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"import": "./dist/index-astro.ts",
|
|
35
|
+
"types": "./dist/index-astro.ts"
|
|
36
|
+
},
|
|
37
|
+
"./vue": {
|
|
38
|
+
"import": "./dist/index-vue.ts",
|
|
39
|
+
"types": "./dist/index-vue.ts"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"index.ts"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsx scripts/build.ts",
|
|
48
|
+
"build:prod": "tsx scripts/build.ts --no-sourcemap",
|
|
49
|
+
"check": "astro check"
|
|
50
|
+
},
|
|
51
|
+
"type": "module",
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"astro": "^5.1.3",
|
|
54
|
+
"vue": "^3.0.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"astro": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"vue": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@remixicon/vue": "^4.7.0",
|
|
66
|
+
"astro-integration-kit": "^0.19.1",
|
|
67
|
+
"fs-extra": "^11.3.2",
|
|
68
|
+
"html-to-image": "^1.11.13",
|
|
69
|
+
"shiki": "^3.14.0",
|
|
70
|
+
"typescript": "^5.9.3"
|
|
71
|
+
},
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"@astrojs/check": "^0.9.5",
|
|
74
|
+
"@astrojs/mdx": "^4.3.9",
|
|
75
|
+
"@astrojs/ts-plugin": "^1.10.5",
|
|
76
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
77
|
+
"@tailwindcss/vite": "^4.1.16",
|
|
78
|
+
"@tsconfig/node22": "^22.0.2",
|
|
79
|
+
"@types/fs-extra": "^11.0.4",
|
|
80
|
+
"@types/node": "^24.9.2",
|
|
81
|
+
"astro": "^5.15.2",
|
|
82
|
+
"daisyui": "^5.3.10",
|
|
83
|
+
"globals": "^16.4.0",
|
|
84
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
85
|
+
"sharp": "^0.34.4",
|
|
86
|
+
"tailwindcss": "^4.1.16",
|
|
87
|
+
"tsx": "^4.20.6",
|
|
88
|
+
"vite": "^7.1.12"
|
|
89
|
+
}
|
|
89
90
|
}
|