@coffic/cosy-ui 0.8.27 → 0.8.29

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.
Files changed (28) hide show
  1. package/dist/app.css +1 -1
  2. package/dist/index-astro.ts +0 -1
  3. package/dist/index-collection.ts +85 -84
  4. package/dist/src-astro/code-container/CodeContainer.astro +4 -2
  5. package/dist/src-astro/entities/CourseDoc.ts +75 -74
  6. package/dist/src-astro/entities/SidebarItem.ts +67 -65
  7. package/dist/src-astro/footer/Footer.astro +9 -14
  8. package/dist/src-astro/footer/FooterCopyright.astro +29 -0
  9. package/dist/src-astro/footer/FooterSection.astro +3 -0
  10. package/dist/src-astro/layout-dashboard/DashboardLayout.astro +21 -2
  11. package/dist/src-astro/layout-dashboard/types.ts +2 -2
  12. package/dist/src-astro/{sidebar-nav → sidebar}/SidebarNav.astro +17 -0
  13. package/dist/src-astro/sidebar/index.ts +2 -9
  14. package/dist/src-astro/team-member/TeamMember.astro +36 -4
  15. package/dist/src-astro/team-member/index.ts +3 -26
  16. package/dist/src-astro/types/sidebar.ts +28 -24
  17. package/dist/src-vue/buttons/ButtonFolder.vue +98 -0
  18. package/dist/src-vue/buttons/ButtonRefresh.vue +163 -0
  19. package/dist/src-vue/buttons/index.ts +2 -0
  20. package/package.json +1 -1
  21. package/dist/src-astro/code-container/CodePanel.astro +0 -14
  22. package/dist/src-astro/sidebar/SidebarBasic.astro +0 -0
  23. package/dist/src-astro/sidebar-nav/SidebarNavBasic.astro +0 -32
  24. package/dist/src-astro/sidebar-nav/index.ts +0 -11
  25. package/dist/src-astro/team-member/TeamMemberBasic.astro +0 -25
  26. package/dist/src-astro/team-member/TeamMemberCustomStyle.astro +0 -26
  27. package/dist/src-astro/team-member/TeamMemberGroup.astro +0 -60
  28. package/dist/src-astro/team-member/TeamMemberWithSocial.astro +0 -30
@@ -159,8 +159,8 @@ export const mainBackgroundThemeMap: Record<MainBackgroundTheme, string> = {
159
159
  * @param theme 主内容区域背景主题
160
160
  * @returns 对应的样式类名
161
161
  */
162
- export function getMainBackgroundTheme(theme: MainBackgroundTheme = 'transparent'): string {
162
+ export function getMainBackgroundTheme(theme: MainBackgroundTheme = 'base-100'): string {
163
163
  return mainBackgroundThemeMap[theme];
164
164
  }
165
165
 
166
- export { getIconFromHref, getNavItemIcon, getUserMenuItemIcon } from './tools';
166
+ export { getIconFromHref, getNavItemIcon, getUserMenuItemIcon } from './tools';
@@ -75,6 +75,11 @@ const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
75
75
  debugClass,
76
76
  ]}>
77
77
  {item.text}
78
+ {item.badge !== undefined && item.badge !== null && (
79
+ <span class="cosy:badge cosy:badge-sm cosy:ml-2">
80
+ {item.badge}
81
+ </span>
82
+ )}
78
83
  </a>
79
84
  {item.items && (
80
85
  <ul class:list={[debugClass]}>
@@ -95,6 +100,12 @@ const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
95
100
  debugClass,
96
101
  ]}>
97
102
  {subitem.text}
103
+ {subitem.badge !== undefined &&
104
+ subitem.badge !== null && (
105
+ <span class="cosy:badge cosy:badge-xs cosy:ml-2">
106
+ {subitem.badge}
107
+ </span>
108
+ )}
98
109
  </a>
99
110
  {subitem.items && (
100
111
  <ul class:list={[debugClass]}>
@@ -115,6 +126,12 @@ const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
115
126
  debugClass,
116
127
  ]}>
117
128
  {subsubitem.text}
129
+ {subsubitem.badge !== undefined &&
130
+ subsubitem.badge !== null && (
131
+ <span class="cosy:badge cosy:badge-xs cosy:ml-2">
132
+ {subsubitem.badge}
133
+ </span>
134
+ )}
118
135
  </a>
119
136
  </li>
120
137
  );
@@ -1,11 +1,4 @@
1
1
  import Sidebar from './Sidebar.astro';
2
- import SidebarBasic from './SidebarBasic.astro';
3
- import BasicSourceCode from './SidebarBasic.astro?raw';
4
- import { extractSimpleExample } from '../../src/utils/component';
2
+ import SidebarNav from './SidebarNav.astro';
5
3
 
6
- export { Sidebar, SidebarBasic };
7
-
8
- // 导出示例源代码
9
- export const SidebarExampleCodes = {
10
- Basic: extractSimpleExample(BasicSourceCode, 'Sidebar'),
11
- };
4
+ export { Sidebar, SidebarNav };
@@ -19,7 +19,7 @@
19
19
  * <TeamMember
20
20
  * name="张三"
21
21
  * role="前端开发工程师"
22
- * avatar="/images/avatars/zhangsan.jpg"
22
+ * avatar="/images/avatars/jack.jpg"
23
23
  * bio="拥有5年前端开发经验,专注于React和Vue生态系统。"
24
24
  * />
25
25
  * ```
@@ -29,7 +29,7 @@
29
29
  * <TeamMember
30
30
  * name="李四"
31
31
  * role="UI设计师"
32
- * avatar="/images/avatars/lisi.jpg"
32
+ * avatar="/images/avatars/mary.jpg"
33
33
  * bio="专注于用户体验和界面设计,热爱创造直观易用的产品。"
34
34
  * socialLinks={[
35
35
  * { platform: 'github', url: 'https://github.com/lisi' },
@@ -80,6 +80,16 @@ export interface Props {
80
80
  * 自定义类名
81
81
  */
82
82
  class?: string;
83
+ /**
84
+ * 卡片阴影强度
85
+ * @default 'md'
86
+ */
87
+ shadow?: 'sm' | 'md' | 'lg' | 'xl';
88
+ /**
89
+ * 悬停时卡片阴影强度
90
+ * @default 'lg'
91
+ */
92
+ hoverShadow?: 'sm' | 'md' | 'lg' | 'xl';
83
93
  }
84
94
 
85
95
  const {
@@ -89,13 +99,35 @@ const {
89
99
  bio,
90
100
  socialLinks,
91
101
  class: className = '',
102
+ shadow = 'md',
103
+ hoverShadow = 'lg',
92
104
  } = Astro.props;
105
+
106
+ const shadowMap = {
107
+ sm: 'cosy:shadow-sm',
108
+ md: 'cosy:shadow-md',
109
+ lg: 'cosy:shadow-lg',
110
+ xl: 'cosy:shadow-xl',
111
+ };
112
+ const hoverShadowMap = {
113
+ sm: 'cosy:hover:shadow-sm',
114
+ md: 'cosy:hover:shadow-md',
115
+ lg: 'cosy:hover:shadow-lg',
116
+ xl: 'cosy:hover:shadow-xl',
117
+ };
118
+
119
+ const shadowClass = shadowMap[shadow] || shadowMap['md'];
120
+ const hoverShadowClass = hoverShadowMap[hoverShadow] || hoverShadowMap['lg'];
93
121
  ---
94
122
 
95
123
  <div
96
124
  class:list={[
97
- 'cosy:card cosy:bg-base-100 cosy:shadow-md cosy:hover:shadow-lg cosy:transition-shadow cosy:duration-300',
98
- className,
125
+ [
126
+ 'cosy:card cosy:bg-base-100 cosy:transition-shadow cosy:duration-300',
127
+ shadowClass,
128
+ hoverShadowClass,
129
+ className,
130
+ ],
99
131
  ]}>
100
132
  <figure class="cosy:flex cosy:justify-center cosy:p-4">
101
133
  <Image
@@ -1,30 +1,7 @@
1
1
  import TeamMember from './TeamMember.astro';
2
- import TeamMemberBasic from './TeamMemberBasic.astro';
3
- import TeamMemberWithSocial from './TeamMemberWithSocial.astro';
4
- import TeamMemberCustomStyle from './TeamMemberCustomStyle.astro';
5
- import TeamMemberGroup from './TeamMemberGroup.astro';
6
- import TeamMemebrs from './TeamMembers.astro';
7
-
8
- import BasicSourceCode from './TeamMemberBasic.astro?raw';
9
- import WithSocialSourceCode from './TeamMemberWithSocial.astro?raw';
10
- import CustomStyleSourceCode from './TeamMemberCustomStyle.astro?raw';
11
- import GroupSourceCode from './TeamMemberGroup.astro?raw';
12
-
13
- import { extractSimpleExample } from '../../src/utils/component';
2
+ import TeamMembers from './TeamMembers.astro';
14
3
 
15
4
  export {
16
- TeamMember,
17
- TeamMemberBasic,
18
- TeamMemberWithSocial,
19
- TeamMemberCustomStyle,
20
- TeamMemberGroup,
21
- TeamMemebrs,
22
- };
23
-
24
- // Export example codes
25
- export const TeamMemberExampleCodes = {
26
- Basic: extractSimpleExample(BasicSourceCode, 'TeamMember'),
27
- WithSocial: extractSimpleExample(WithSocialSourceCode, 'TeamMember'),
28
- CustomStyle: extractSimpleExample(CustomStyleSourceCode, 'TeamMember'),
29
- Group: extractSimpleExample(GroupSourceCode, 'TeamMember'),
5
+ TeamMember,
6
+ TeamMembers,
30
7
  };
@@ -2,35 +2,39 @@
2
2
  * 侧边栏项目
3
3
  */
4
4
  export interface ISidebarItem {
5
- href: string;
6
- text: string;
7
- items?: ISidebarItem[];
5
+ href: string;
6
+ text: string;
7
+ items?: ISidebarItem[];
8
+ /**
9
+ * 可选徽标内容
10
+ */
11
+ badge?: string | number;
8
12
  }
9
13
 
10
14
  /**
11
15
  * 侧边栏配置
12
16
  */
13
17
  export interface ISidebarProps {
14
- /**
15
- * 侧边栏项目
16
- */
17
- sidebarItems: ISidebarItem[];
18
+ /**
19
+ * 侧边栏项目
20
+ */
21
+ sidebarItems: ISidebarItem[];
18
22
 
19
- /**
20
- * 桌面端类名
21
- */
22
- class?: string;
23
+ /**
24
+ * 桌面端类名
25
+ */
26
+ class?: string;
23
27
 
24
- /**
25
- * 是否开启调试模式,显示边框
26
- * @default false
27
- */
28
- debug?: boolean;
28
+ /**
29
+ * 是否开启调试模式,显示边框
30
+ * @default false
31
+ */
32
+ debug?: boolean;
29
33
 
30
- /**
31
- * 侧边栏顶部外边距
32
- */
33
- marginTop?:
34
+ /**
35
+ * 侧边栏顶部外边距
36
+ */
37
+ marginTop?:
34
38
  | 'xs'
35
39
  | 'sm'
36
40
  | 'md'
@@ -42,10 +46,10 @@ export interface ISidebarProps {
42
46
  | '5xl'
43
47
  | string;
44
48
 
45
- /**
46
- * 侧边栏底部外边距
47
- */
48
- marginBottom?:
49
+ /**
50
+ * 侧边栏底部外边距
51
+ */
52
+ marginBottom?:
49
53
  | 'xs'
50
54
  | 'sm'
51
55
  | 'md'
@@ -0,0 +1,98 @@
1
+ <!--
2
+ ButtonFolder 组件
3
+
4
+ 一个专门用于文件夹操作的按钮组件,封装了 Button 组件,并添加了文件夹图标。
5
+
6
+ 使用示例:
7
+ ```vue
8
+ <ButtonFolder @click="openFolder" />
9
+ <ButtonFolder style="ghost" size="sm" @click="openFolder" tooltip="打开文件夹" />
10
+ ```
11
+
12
+ 属性:
13
+ - 继承 Button 组件的所有属性
14
+ - 默认使用 ghost 样式
15
+
16
+ 事件:
17
+ - click: 点击按钮时触发(disabled状态下不触发)
18
+ -->
19
+
20
+ <script setup lang="ts">
21
+ import { computed } from 'vue';
22
+ import { Button } from '@coffic/cosy-ui/vue';
23
+ import { RiFolderOpenLine } from '@remixicon/vue';
24
+
25
+ interface Props {
26
+ // 按钮颜色
27
+ color?:
28
+ | 'neutral'
29
+ | 'primary'
30
+ | 'secondary'
31
+ | 'accent'
32
+ | 'info'
33
+ | 'success'
34
+ | 'warning'
35
+ | 'error';
36
+ // 按钮样式
37
+ style?: 'outline' | 'dash' | 'soft' | 'ghost' | 'link';
38
+ // 按钮大小
39
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
40
+ // 按钮形状
41
+ shape?: 'square' | 'circle';
42
+ // 是否禁用
43
+ disabled?: boolean;
44
+ // 是否激活
45
+ active?: boolean;
46
+ // 提示文本
47
+ tooltip?: string;
48
+ }
49
+
50
+ const props = withDefaults(defineProps<Props>(), {
51
+ style: 'ghost',
52
+ size: 'md',
53
+ disabled: false,
54
+ active: false,
55
+ });
56
+
57
+ const emit = defineEmits<{
58
+ (e: 'click', event: MouseEvent): void;
59
+ }>();
60
+
61
+ // 处理点击事件
62
+ const handleClick = (event: MouseEvent) => {
63
+ // 如果按钮已经处于禁用状态,不触发事件
64
+ if (props.disabled) return;
65
+
66
+ // 触发点击事件
67
+ emit('click', event);
68
+ };
69
+
70
+ // 计算图标大小类名
71
+ const iconSizeClass = computed(() => {
72
+ if (props.size === 'xs' || props.size === 'sm') return 'cosy:w-4 cosy:h-4';
73
+ if (props.size === 'lg' || props.size === 'xl') return 'cosy:w-6 cosy:h-6';
74
+ return 'cosy:w-5 cosy:h-5'; // 默认中等大小
75
+ });
76
+ </script>
77
+
78
+ <template>
79
+ <div
80
+ class="cosy:relative cosy:inline-block"
81
+ :data-tip="tooltip"
82
+ :class="{ tooltip: tooltip }"
83
+ >
84
+ <Button
85
+ :color="color"
86
+ :style="style"
87
+ :shape="shape"
88
+ :disabled="disabled"
89
+ :active="active"
90
+ @click="handleClick"
91
+ >
92
+ <RiFolderOpenLine
93
+ :class="[iconSizeClass, 'cosy:transition-all cosy:duration-300']"
94
+ />
95
+ <slot></slot>
96
+ </Button>
97
+ </div>
98
+ </template>
@@ -0,0 +1,163 @@
1
+ <!--
2
+ ButtonRefresh 组件
3
+
4
+ 一个专门用于刷新操作的按钮组件,封装了 Button 组件,并添加了动画效果。
5
+ 当处于加载状态时,图标会旋转,提供视觉反馈。
6
+
7
+ 使用示例:
8
+ ```vue
9
+ <ButtonRefresh @click="refreshData" :loading="isLoading" />
10
+ <ButtonRefresh style="ghost" size="sm" @click="refreshData" />
11
+ ```
12
+
13
+ 属性:
14
+ - 继承 Button 组件的所有属性
15
+ - 默认使用 ghost 样式
16
+
17
+ 事件:
18
+ - click: 点击按钮时触发(disabled或loading状态下不触发)
19
+ -->
20
+
21
+ <script setup lang="ts">
22
+ import { computed, ref, watch } from 'vue';
23
+ import { Button } from '@coffic/cosy-ui/vue';
24
+ import { RiRefreshLine } from '@remixicon/vue';
25
+
26
+ interface Props {
27
+ // 按钮颜色
28
+ color?:
29
+ | 'neutral'
30
+ | 'primary'
31
+ | 'secondary'
32
+ | 'accent'
33
+ | 'info'
34
+ | 'success'
35
+ | 'warning'
36
+ | 'error';
37
+ // 按钮样式
38
+ style?: 'outline' | 'dash' | 'soft' | 'ghost' | 'link';
39
+ // 按钮大小
40
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
41
+ // 按钮形状
42
+ shape?: 'square' | 'circle';
43
+ // 是否显示加载状态
44
+ loading?: boolean;
45
+ // 是否禁用
46
+ disabled?: boolean;
47
+ // 是否激活
48
+ active?: boolean;
49
+ // 提示文本
50
+ tooltip?: string;
51
+ // 最小动画时间(毫秒)
52
+ minAnimationTime?: number;
53
+ }
54
+
55
+ const props = withDefaults(defineProps<Props>(), {
56
+ style: 'ghost',
57
+ size: 'md',
58
+ loading: false,
59
+ disabled: false,
60
+ active: false,
61
+ minAnimationTime: 800, // 默认最小动画时间为 800 毫秒
62
+ });
63
+
64
+ const emit = defineEmits<{
65
+ (e: 'click', event: MouseEvent): void;
66
+ }>();
67
+
68
+ // 处理点击事件
69
+ const handleClick = async (event: MouseEvent) => {
70
+ // 如果按钮已经处于加载或禁用状态,不触发事件
71
+ if (props.disabled || internalLoading.value) return;
72
+
73
+ // 触发点击事件
74
+ emit('click', event);
75
+ };
76
+
77
+ // 内部加载状态
78
+ const internalLoading = ref(false);
79
+
80
+ // 记录动画开始时间
81
+ const animationStartTime = ref(0);
82
+
83
+ // 监听外部加载状态
84
+ watch(
85
+ () => props.loading,
86
+ (newVal, oldVal) => {
87
+ if (newVal === true) {
88
+ // 开始加载,记录当前时间
89
+ animationStartTime.value = Date.now();
90
+ internalLoading.value = true;
91
+ } else if (oldVal === true && newVal === false) {
92
+ // 加载结束,计算已经经过的时间
93
+ const elapsedTime = Date.now() - animationStartTime.value;
94
+ const remainingTime = Math.max(0, props.minAnimationTime - elapsedTime);
95
+
96
+ if (remainingTime > 0) {
97
+ // 如果还没有达到最小动画时间,延迟关闭加载状态
98
+ setTimeout(() => {
99
+ internalLoading.value = false;
100
+ }, remainingTime);
101
+ } else {
102
+ // 已经超过最小动画时间,直接关闭
103
+ internalLoading.value = false;
104
+ }
105
+ }
106
+ },
107
+ { immediate: true }
108
+ );
109
+
110
+ // 计算内容类名
111
+ const contentClass = computed(() => {
112
+ return {
113
+ hidden: internalLoading.value,
114
+ };
115
+ });
116
+
117
+ // 计算图标大小类名
118
+ const iconSizeClass = computed(() => {
119
+ if (props.size === 'xs' || props.size === 'sm') return 'cosy:w-4 cosy:h-4';
120
+ if (props.size === 'lg' || props.size === 'xl') return 'cosy:w-6 cosy:h-6';
121
+ return 'cosy:w-5 cosy:h-5'; // 默认中等大小
122
+ });
123
+
124
+ // 计算加载器类名
125
+ const loadingClass = computed(() => {
126
+ return [
127
+ 'loading',
128
+ 'loading-spinner',
129
+ props.size === 'xs' || props.size === 'sm'
130
+ ? 'loading-xs'
131
+ : props.size === 'lg' || props.size === 'xl'
132
+ ? 'loading-lg'
133
+ : 'loading-md',
134
+ iconSizeClass.value, // 使用相同的大小类
135
+ { hidden: !internalLoading.value },
136
+ ];
137
+ });
138
+ </script>
139
+
140
+ <template>
141
+ <div
142
+ class="cosy:relative cosy:inline-block"
143
+ :data-tip="tooltip"
144
+ :class="{ tooltip: tooltip }"
145
+ >
146
+ <Button
147
+ :color="color"
148
+ :style="style"
149
+ :shape="shape"
150
+ :disabled="disabled || internalLoading"
151
+ :active="active"
152
+ @click="handleClick"
153
+ >
154
+ <span :class="loadingClass"></span>
155
+ <span :class="contentClass">
156
+ <RiRefreshLine
157
+ :class="[iconSizeClass, 'cosy:transition-all cosy:duration-300']"
158
+ />
159
+ <slot></slot>
160
+ </span>
161
+ </Button>
162
+ </div>
163
+ </template>
@@ -1 +1,3 @@
1
1
  export { default as Button } from './Button.vue';
2
+ export { default as ButtonFolder } from './ButtonFolder.vue';
3
+ export { default as ButtonRefresh } from './ButtonRefresh.vue';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffic/cosy-ui",
3
- "version": "0.8.27",
3
+ "version": "0.8.29",
4
4
  "description": "An astro component library",
5
5
  "author": {
6
6
  "name": "nookery",
@@ -1,14 +0,0 @@
1
- ---
2
- interface Props {
3
- code: string;
4
- }
5
- const { code = '' } = Astro.props;
6
- ---
7
-
8
- <div class="cosy:hidden cosy:code-example-panel" data-panel="code">
9
- <pre
10
- class="cosy:overflow-x-auto"
11
- style="margin:0">
12
- <code class="cosy:language-astro">{code}</code>
13
- </pre>
14
- </div>
File without changes
@@ -1,32 +0,0 @@
1
- ---
2
- import SidebarNav from './SidebarNav.astro';
3
- import type { ISidebarItem } from '../types/sidebar';
4
-
5
- const sidebarItems: ISidebarItem[] = [
6
- {
7
- text: '入门指南',
8
- href: '/docs/getting-started',
9
- items: [
10
- { href: '/docs/getting-started/installation', text: '安装' },
11
- { href: '/docs/getting-started/quick-start', text: '快速开始' },
12
- ],
13
- },
14
- {
15
- text: '基础组件',
16
- href: '/docs/components',
17
- items: [
18
- { href: '/docs/components/button', text: 'Button 按钮' },
19
- { href: '/docs/components/alert', text: 'Alert 提示' },
20
- { href: '/docs/components/card', text: 'Card 卡片' },
21
- ],
22
- },
23
- ];
24
- ---
25
-
26
- <div class="cosy:w-64 cosy:bg-base-100">
27
- <SidebarNav
28
- sidebarItems={sidebarItems}
29
- currentPath="/docs/getting-started/installation"
30
- debug={false}
31
- />
32
- </div>
@@ -1,11 +0,0 @@
1
- import SidebarNav from './SidebarNav.astro';
2
- import SidebarNavBasic from './SidebarNavBasic.astro';
3
- import BasicSourceCode from './SidebarNavBasic.astro?raw';
4
- import { extractSimpleExample } from '../../src/utils/component';
5
-
6
- export { SidebarNav, SidebarNavBasic };
7
-
8
- // 导出示例源代码
9
- export const SidebarNavExampleCodes = {
10
- Basic: extractSimpleExample(BasicSourceCode, 'SidebarNav'),
11
- };
@@ -1,25 +0,0 @@
1
- ---
2
- /**
3
- * @component TeamMember.Basic
4
- *
5
- * @description
6
- * 基础的团队成员展示组件示例,展示最简单的成员信息展示方式。
7
- */
8
- import '../../style.ts';
9
- import TeamMember from './TeamMember.astro';
10
- import { getExampleImage } from '../../src/utils/image.ts';
11
-
12
- const avatar = getExampleImage({
13
- width: 200,
14
- height: 200,
15
- provider: 'robohash',
16
- randomSeed: 'member1',
17
- });
18
- ---
19
-
20
- <TeamMember
21
- name="张三"
22
- role="产品设计师"
23
- avatar={avatar}
24
- bio="专注于用户体验设计,拥有5年产品设计经验"
25
- />
@@ -1,26 +0,0 @@
1
- ---
2
- /**
3
- * @component TeamMember.CustomStyle
4
- *
5
- * @description
6
- * 自定义样式的团队成员展示组件示例,展示如何使用class属性自定义样式。
7
- */
8
- import '../../style.ts';
9
- import TeamMember from './TeamMember.astro';
10
- import { getExampleImage } from '../../src/utils/image.ts';
11
-
12
- const avatar = getExampleImage({
13
- width: 200,
14
- height: 200,
15
- provider: 'robohash',
16
- randomSeed: 'member3',
17
- });
18
- ---
19
-
20
- <TeamMember
21
- name="王五"
22
- role="市场总监"
23
- avatar={avatar}
24
- bio="负责产品市场策略和品牌推广,拥有丰富的市场营销经验"
25
- class="cosy:bg-gradient-to-r cosy:from-purple-100 cosy:to-pink-100 cosy:shadow-lg cosy:w-72"
26
- />