@coffic/cosy-ui 0.9.40 → 0.9.41
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/app.css +1 -1
- package/dist/index-astro.ts +18 -13
- package/dist/src-astro/avatar/Avatar.astro +118 -0
- package/dist/src-astro/avatar/index.ts +2 -0
- package/dist/src-astro/avatar/types.ts +29 -0
- package/dist/src-astro/contact/Contact.astro +155 -172
- package/dist/src-astro/container/Container.astro +16 -0
- package/dist/src-astro/features/FeatureCard.astro +63 -0
- package/dist/src-astro/features/FeatureShowcase.astro +164 -0
- package/dist/src-astro/features/index.ts +3 -0
- package/dist/src-astro/heading/Heading.astro +56 -8
- package/dist/src-astro/icons/AppStoreIcon.astro +1 -1
- package/dist/src-astro/mac-window/MacWindow.astro +9 -4
- package/dist/src-astro/products/ProductShowcase.astro +159 -0
- package/dist/src-astro/products/ProductShowcaseItem.astro +216 -0
- package/dist/src-astro/products/index.ts +4 -0
- package/dist/src-astro/review/Review.astro +159 -0
- package/dist/src-astro/review/Reviews.astro +162 -0
- package/dist/src-astro/review/index.ts +3 -0
- package/dist/src-astro/review/types.ts +127 -0
- package/dist/src-astro/stats-display/StatsDisplay.astro +201 -0
- package/dist/src-astro/stats-display/index.ts +10 -0
- package/dist/src-astro/stats-display/types.ts +79 -0
- package/dist/src-astro/text/Text.astro +4 -1
- package/dist/src-vue/container/Container.vue +64 -62
- package/dist/src-vue/container/types.ts +3 -3
- package/dist/src-vue/heading/Heading.vue +64 -10
- package/dist/src-vue/heading/types.ts +9 -0
- package/dist/src-vue/mac-window/MacWindow.vue +164 -212
- package/package.json +1 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component StatsDisplay
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* StatsDisplay 组件用于展示统计数据,采用极简设计风格。
|
|
7
|
+
* 适合在首页、关于我们页面或产品介绍页面中展示关键数据指标。
|
|
8
|
+
* 支持多种布局模式和自定义样式。
|
|
9
|
+
*
|
|
10
|
+
* StatsDisplay component for showcasing statistical data with minimalist design.
|
|
11
|
+
* Perfect for displaying key metrics on homepages, about pages, or product introduction pages.
|
|
12
|
+
* Supports multiple layout modes and custom styling options.
|
|
13
|
+
*
|
|
14
|
+
* @design
|
|
15
|
+
* 设计理念 / Design Principles:
|
|
16
|
+
* 1. 极简美学 - 大数字、细字重、简洁布局 / Minimalist Aesthetics - Large numbers, thin font weights, clean layouts
|
|
17
|
+
* 2. 视觉层次 - 通过字体大小和颜色建立清晰层次 / Visual Hierarchy - Clear hierarchy through font sizes and colors
|
|
18
|
+
* 3. 响应式设计 - 自适应不同屏幕尺寸 / Responsive Design - Adapts to different screen sizes
|
|
19
|
+
* 4. 可定制性 - 支持多种样式和布局选项 / Customizability - Multiple styling and layout options
|
|
20
|
+
*
|
|
21
|
+
* @usage
|
|
22
|
+
* 基本用法 / Basic Usage:
|
|
23
|
+
* ```astro
|
|
24
|
+
* <StatsDisplay
|
|
25
|
+
* stats={[
|
|
26
|
+
* { value: "10+", label: "年经验" },
|
|
27
|
+
* { value: "500+", label: "客户" },
|
|
28
|
+
* { value: "1000+", label: "项目" }
|
|
29
|
+
* ]}
|
|
30
|
+
* />
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* 自定义样式 / Custom Styling:
|
|
34
|
+
* ```astro
|
|
35
|
+
* <StatsDisplay
|
|
36
|
+
* stats={[
|
|
37
|
+
* { value: "10M+", label: "用户", color: "blue" },
|
|
38
|
+
* { value: "20+", label: "奖项", color: "success" }
|
|
39
|
+
* ]}
|
|
40
|
+
* valueSize="4xl"
|
|
41
|
+
* valueColor="primary"
|
|
42
|
+
* labelColor="gray"
|
|
43
|
+
* />
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* 预设颜色使用 / Using Preset Colors:
|
|
47
|
+
* ```astro
|
|
48
|
+
* <StatsDisplay
|
|
49
|
+
* stats={[
|
|
50
|
+
* { value: "99%", label: "满意度", color: "success" },
|
|
51
|
+
* { value: "24/7", label: "支持", color: "info" }
|
|
52
|
+
* ]}
|
|
53
|
+
* valueColor="primary"
|
|
54
|
+
* labelColor="secondary"
|
|
55
|
+
* />
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* 紧凑模式 / Compact Mode:
|
|
59
|
+
* ```astro
|
|
60
|
+
* <StatsDisplay
|
|
61
|
+
* stats={stats}
|
|
62
|
+
* compact
|
|
63
|
+
* columns={2}
|
|
64
|
+
* />
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @props
|
|
68
|
+
* @param {Array<{value: string, label: string, color?: string|PresetColor}>} stats - 统计数据数组 / Statistical data array
|
|
69
|
+
* @param {string} [class] - 自定义CSS类 / Custom CSS class
|
|
70
|
+
* @param {boolean} [compact] - 是否使用紧凑模式 / Whether to use compact mode
|
|
71
|
+
* @param {number} [columns] - 列数(响应式)/ Number of columns (responsive)
|
|
72
|
+
* @param {string} [valueSize] - 数值字体大小 / Font size for values
|
|
73
|
+
* @param {string|PresetColor} [valueColor] - 数值颜色(支持预设颜色)/ Color for values (supports preset colors)
|
|
74
|
+
* @param {string|PresetColor} [labelColor] - 标签颜色(支持预设颜色)/ Color for labels (supports preset colors)
|
|
75
|
+
* @param {string} [valueWeight] - 数值字重 / Font weight for values
|
|
76
|
+
* @param {string} [labelWeight] - 标签字重 / Font weight for labels
|
|
77
|
+
* @param {string} [gap] - 项目间距 / Spacing between items
|
|
78
|
+
* @param {string} [align] - 对齐方式 / Alignment option
|
|
79
|
+
*
|
|
80
|
+
* @presetColors
|
|
81
|
+
* 预设颜色选项 / Preset color options:
|
|
82
|
+
* - primary: 主色调 (#3b82f6)
|
|
83
|
+
* - secondary: 次要色调 (#6b7280)
|
|
84
|
+
* - success: 成功色 (#10b981)
|
|
85
|
+
* - warning: 警告色 (#f59e0b)
|
|
86
|
+
* - error: 错误色 (#ef4444)
|
|
87
|
+
* - info: 信息色 (#06b6d4)
|
|
88
|
+
* - blue: 蓝色 (#3b82f6)
|
|
89
|
+
* - green: 绿色 (#10b981)
|
|
90
|
+
* - yellow: 黄色 (#f59e0b)
|
|
91
|
+
* - red: 红色 (#ef4444)
|
|
92
|
+
* - purple: 紫色 (#8b5cf6)
|
|
93
|
+
* - pink: 粉色 (#ec4899)
|
|
94
|
+
* - indigo: 靛蓝 (#6366f1)
|
|
95
|
+
* - gray: 灰色 (#6b7280)
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
import '../../style.ts';
|
|
99
|
+
import Text from '../text/Text.astro';
|
|
100
|
+
import type { PresetColor, StatItem } from './types';
|
|
101
|
+
|
|
102
|
+
// 预设颜色映射 / Preset color mapping
|
|
103
|
+
const PRESET_COLORS: Record<PresetColor, string> = {
|
|
104
|
+
primary: '#3b82f6',
|
|
105
|
+
secondary: '#6b7280',
|
|
106
|
+
success: '#10b981',
|
|
107
|
+
warning: '#f59e0b',
|
|
108
|
+
error: '#ef4444',
|
|
109
|
+
info: '#06b6d4',
|
|
110
|
+
blue: '#3b82f6',
|
|
111
|
+
green: '#10b981',
|
|
112
|
+
yellow: '#f59e0b',
|
|
113
|
+
red: '#ef4444',
|
|
114
|
+
purple: '#8b5cf6',
|
|
115
|
+
pink: '#ec4899',
|
|
116
|
+
indigo: '#6366f1',
|
|
117
|
+
gray: '#6b7280',
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// 颜色解析函数 / Color resolution function
|
|
121
|
+
const resolveColor = (
|
|
122
|
+
color: string | PresetColor | undefined,
|
|
123
|
+
defaultColor: string
|
|
124
|
+
): string => {
|
|
125
|
+
if (!color) return defaultColor;
|
|
126
|
+
return PRESET_COLORS[color as PresetColor] || color;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const {
|
|
130
|
+
stats = [],
|
|
131
|
+
class: className = '',
|
|
132
|
+
compact = false,
|
|
133
|
+
columns = 4,
|
|
134
|
+
valueSize = '3xl',
|
|
135
|
+
valueColor = 'primary',
|
|
136
|
+
labelColor = 'gray',
|
|
137
|
+
valueWeight = 'thin',
|
|
138
|
+
labelWeight = 'light',
|
|
139
|
+
gap = 'lg',
|
|
140
|
+
align = 'center',
|
|
141
|
+
} = Astro.props;
|
|
142
|
+
|
|
143
|
+
// 构建容器样式类
|
|
144
|
+
const containerClasses = [
|
|
145
|
+
'cosy:grid',
|
|
146
|
+
`cosy:grid-cols-${columns}`,
|
|
147
|
+
`cosy:gap-${gap}`,
|
|
148
|
+
`cosy:text-${align}`,
|
|
149
|
+
compact ? 'cosy:gap-md' : '',
|
|
150
|
+
className,
|
|
151
|
+
]
|
|
152
|
+
.filter(Boolean)
|
|
153
|
+
.join(' ');
|
|
154
|
+
|
|
155
|
+
// 构建数值样式
|
|
156
|
+
const getValueStyle = (item: StatItem) => {
|
|
157
|
+
return [
|
|
158
|
+
`cosy:text-${valueSize}`,
|
|
159
|
+
`cosy:font-${valueWeight}`,
|
|
160
|
+
'cosy:mb-2',
|
|
161
|
+
'cosy:leading-none',
|
|
162
|
+
].join(' ');
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// 构建标签样式
|
|
166
|
+
const getLabelStyle = () =>
|
|
167
|
+
[`cosy:text-${labelWeight}`, 'cosy:leading-relaxed'].join(' ');
|
|
168
|
+
|
|
169
|
+
// 获取数值颜色样式
|
|
170
|
+
const getValueColorStyle = (item: StatItem): string => {
|
|
171
|
+
const customColor = item.color
|
|
172
|
+
? resolveColor(item.color, '#3b82f6')
|
|
173
|
+
: resolveColor(valueColor, '#3b82f6');
|
|
174
|
+
return `color: ${customColor};`;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// 获取标签颜色样式
|
|
178
|
+
const getLabelColorStyle = (item: StatItem): string => {
|
|
179
|
+
// 如果单个项目有自定义颜色,优先使用项目颜色
|
|
180
|
+
// 否则使用全局 labelColor 设置
|
|
181
|
+
const customColor = item.color
|
|
182
|
+
? resolveColor(item.color, '#6b7280')
|
|
183
|
+
: resolveColor(labelColor, '#6b7280');
|
|
184
|
+
return `color: ${customColor};`;
|
|
185
|
+
};
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
<div class={containerClasses}>
|
|
189
|
+
{
|
|
190
|
+
stats.map((stat: StatItem) => (
|
|
191
|
+
<div class="cosy:flex cosy:flex-col cosy:items-center">
|
|
192
|
+
<div class={getValueStyle(stat)} style={getValueColorStyle(stat)}>
|
|
193
|
+
{stat.value}
|
|
194
|
+
</div>
|
|
195
|
+
<Text class={getLabelStyle()} style={getLabelColorStyle(stat)}>
|
|
196
|
+
{stat.label}
|
|
197
|
+
</Text>
|
|
198
|
+
</div>
|
|
199
|
+
))
|
|
200
|
+
}
|
|
201
|
+
</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview StatsDisplay 组件类型定义
|
|
3
|
+
* Type definitions for StatsDisplay component
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** 预设颜色类型 / Preset color types */
|
|
7
|
+
export type PresetColor =
|
|
8
|
+
| 'primary'
|
|
9
|
+
| 'secondary'
|
|
10
|
+
| 'success'
|
|
11
|
+
| 'warning'
|
|
12
|
+
| 'error'
|
|
13
|
+
| 'info'
|
|
14
|
+
| 'blue'
|
|
15
|
+
| 'green'
|
|
16
|
+
| 'yellow'
|
|
17
|
+
| 'red'
|
|
18
|
+
| 'purple'
|
|
19
|
+
| 'pink'
|
|
20
|
+
| 'indigo'
|
|
21
|
+
| 'gray';
|
|
22
|
+
|
|
23
|
+
/** 字体大小类型 / Font size types */
|
|
24
|
+
export type FontSize =
|
|
25
|
+
| 'xs'
|
|
26
|
+
| 'sm'
|
|
27
|
+
| 'base'
|
|
28
|
+
| 'lg'
|
|
29
|
+
| 'xl'
|
|
30
|
+
| '2xl'
|
|
31
|
+
| '3xl'
|
|
32
|
+
| '4xl'
|
|
33
|
+
| '5xl'
|
|
34
|
+
| '6xl';
|
|
35
|
+
|
|
36
|
+
/** 字重类型 / Font weight types */
|
|
37
|
+
export type FontWeight = 'thin' | 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
|
|
38
|
+
|
|
39
|
+
/** 间距类型 / Spacing types */
|
|
40
|
+
export type Spacing = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
|
|
41
|
+
|
|
42
|
+
/** 对齐方式类型 / Alignment types */
|
|
43
|
+
export type Alignment = 'left' | 'center' | 'right';
|
|
44
|
+
|
|
45
|
+
/** 统计项接口 / Stat item interface */
|
|
46
|
+
export interface StatItem {
|
|
47
|
+
/** 数值 / Numeric value */
|
|
48
|
+
value: string;
|
|
49
|
+
/** 标签 / Description label */
|
|
50
|
+
label: string;
|
|
51
|
+
/** 自定义颜色(可选)/ Custom color (optional) */
|
|
52
|
+
color?: string | PresetColor;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** StatsDisplay 组件属性接口 / StatsDisplay component props interface */
|
|
56
|
+
export interface StatsDisplayProps {
|
|
57
|
+
/** 统计数据数组 / Statistical data array */
|
|
58
|
+
stats: StatItem[];
|
|
59
|
+
/** 自定义CSS类 / Custom CSS class */
|
|
60
|
+
class?: string;
|
|
61
|
+
/** 是否使用紧凑模式 / Whether to use compact mode */
|
|
62
|
+
compact?: boolean;
|
|
63
|
+
/** 列数(响应式)/ Number of columns (responsive) */
|
|
64
|
+
columns?: number;
|
|
65
|
+
/** 数值字体大小 / Font size for values */
|
|
66
|
+
valueSize?: FontSize;
|
|
67
|
+
/** 数值颜色 / Color for values */
|
|
68
|
+
valueColor?: string | PresetColor;
|
|
69
|
+
/** 标签颜色 / Color for labels */
|
|
70
|
+
labelColor?: string | PresetColor;
|
|
71
|
+
/** 数值字重 / Font weight for values */
|
|
72
|
+
valueWeight?: FontWeight;
|
|
73
|
+
/** 标签字重 / Font weight for labels */
|
|
74
|
+
labelWeight?: FontWeight;
|
|
75
|
+
/** 项目间距 / Spacing between items */
|
|
76
|
+
gap?: Spacing;
|
|
77
|
+
/** 对齐方式 / Alignment option */
|
|
78
|
+
align?: Alignment;
|
|
79
|
+
}
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
* @prop {boolean} [underline=false] - 是否添加下划线
|
|
87
87
|
* @prop {boolean} [truncate=false] - 是否截断文本并显示省略号
|
|
88
88
|
* @prop {string} [class] - 自定义 CSS 类名
|
|
89
|
+
* @prop {string} [style] - 自定义内联样式
|
|
89
90
|
*
|
|
90
91
|
* @slots
|
|
91
92
|
* @slot default - 文本内容
|
|
@@ -107,6 +108,7 @@ export interface Props {
|
|
|
107
108
|
underline?: boolean;
|
|
108
109
|
truncate?: boolean;
|
|
109
110
|
class?: string;
|
|
111
|
+
style?: string;
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
const {
|
|
@@ -119,6 +121,7 @@ const {
|
|
|
119
121
|
underline = false,
|
|
120
122
|
truncate = false,
|
|
121
123
|
class: className = '',
|
|
124
|
+
style = '',
|
|
122
125
|
} = Astro.props;
|
|
123
126
|
|
|
124
127
|
// 根据大小设置样式
|
|
@@ -169,7 +172,7 @@ const truncateClass = truncate ? 'cosy:truncate' : '';
|
|
|
169
172
|
const combinedClass = `text ${sizeClass} ${weightClass} ${colorClass} ${alignClass} ${italicClass} ${underlineClass} ${truncateClass} ${className}`;
|
|
170
173
|
---
|
|
171
174
|
|
|
172
|
-
<Element class={combinedClass}>
|
|
175
|
+
<Element class={combinedClass} style={style}>
|
|
173
176
|
<slot />
|
|
174
177
|
</Element>
|
|
175
178
|
|
|
@@ -20,98 +20,100 @@ import { allBackgroundClasses } from './backgrounds';
|
|
|
20
20
|
* @props {string} [background] - 预设的语义化背景色,使用 Tailwind v4 语法(如 bg-primary/50)
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
interface Props extends IContainerProps {
|
|
23
|
+
interface Props extends IContainerProps {}
|
|
24
24
|
|
|
25
25
|
const props = withDefaults(defineProps<Props>(), {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class: '',
|
|
26
|
+
padding: 'md',
|
|
27
|
+
centered: true,
|
|
28
|
+
border: false,
|
|
29
|
+
gap: 'none',
|
|
30
|
+
rounded: 'none',
|
|
31
|
+
class: '',
|
|
33
32
|
});
|
|
34
33
|
|
|
35
34
|
// 静态类名映射
|
|
36
35
|
const sizeClasses = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
none: '',
|
|
37
|
+
xs: 'cosy:max-w-xs',
|
|
38
|
+
sm: 'cosy:max-w-sm',
|
|
39
|
+
md: 'cosy:max-w-2xl',
|
|
40
|
+
lg: 'cosy:max-w-4xl',
|
|
41
|
+
xl: 'cosy:max-w-6xl',
|
|
42
|
+
full: 'cosy:w-full',
|
|
43
43
|
} as const;
|
|
44
44
|
|
|
45
45
|
const paddingClasses = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
none: 'cosy:p-0',
|
|
47
|
+
sm: 'cosy:p-2',
|
|
48
|
+
md: 'cosy:p-4',
|
|
49
|
+
lg: 'cosy:p-6',
|
|
50
|
+
xl: 'cosy:p-8',
|
|
51
51
|
} as const;
|
|
52
52
|
|
|
53
53
|
const roundedClasses = {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
none: '',
|
|
55
|
+
sm: 'cosy:rounded-sm',
|
|
56
|
+
md: 'cosy:rounded-md',
|
|
57
|
+
lg: 'cosy:rounded-lg',
|
|
58
|
+
xl: 'cosy:rounded-xl',
|
|
59
|
+
full: 'cosy:rounded-full',
|
|
60
60
|
} as const;
|
|
61
61
|
|
|
62
62
|
const flexClasses = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
row: 'cosy:flex cosy:flex-row',
|
|
64
|
+
col: 'cosy:flex cosy:flex-col',
|
|
65
|
+
'row-reverse': 'cosy:flex cosy:flex-row-reverse',
|
|
66
|
+
'col-reverse': 'cosy:flex cosy:flex-col-reverse',
|
|
67
67
|
} as const;
|
|
68
68
|
|
|
69
69
|
const gapClasses = {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
none: 'cosy:gap-0',
|
|
71
|
+
xs: 'cosy:gap-1',
|
|
72
|
+
sm: 'cosy:gap-2',
|
|
73
|
+
md: 'cosy:gap-4',
|
|
74
|
+
lg: 'cosy:gap-6',
|
|
75
|
+
xl: 'cosy:gap-8',
|
|
76
76
|
} as const;
|
|
77
77
|
|
|
78
78
|
const itemsClasses = {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
start: 'cosy:items-start',
|
|
80
|
+
end: 'cosy:items-end',
|
|
81
|
+
center: 'cosy:items-center',
|
|
82
|
+
baseline: 'cosy:items-baseline',
|
|
83
|
+
stretch: 'cosy:items-stretch',
|
|
84
84
|
} as const;
|
|
85
85
|
|
|
86
86
|
const justifyClasses = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
start: 'cosy:justify-start',
|
|
88
|
+
end: 'cosy:justify-end',
|
|
89
|
+
center: 'cosy:justify-center',
|
|
90
|
+
between: 'cosy:justify-between',
|
|
91
|
+
around: 'cosy:justify-around',
|
|
92
|
+
evenly: 'cosy:justify-evenly',
|
|
93
93
|
} as const;
|
|
94
94
|
|
|
95
95
|
// 构建CSS类名
|
|
96
|
+
const resolvedSize = computed(() => props.width ?? 'md');
|
|
97
|
+
|
|
96
98
|
const containerClasses = computed(() => [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
'cosy:w-full',
|
|
100
|
+
props.centered ? 'cosy:mx-auto' : '',
|
|
101
|
+
sizeClasses[resolvedSize.value],
|
|
102
|
+
paddingClasses[props.padding],
|
|
103
|
+
roundedClasses[props.rounded],
|
|
104
|
+
props.border ? 'cosy:border' : '',
|
|
105
|
+
props.flex ? flexClasses[props.flex] : '',
|
|
106
|
+
props.flex ? gapClasses[props.gap] : '',
|
|
107
|
+
props.items && props.flex ? itemsClasses[props.items] : '',
|
|
108
|
+
props.justify && props.flex ? justifyClasses[props.justify] : '',
|
|
109
|
+
// 处理背景色 - 使用预定义的完整类名
|
|
110
|
+
props.background ? allBackgroundClasses[props.background] : '',
|
|
111
|
+
props.class,
|
|
110
112
|
]);
|
|
111
113
|
</script>
|
|
112
114
|
|
|
113
115
|
<template>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
<section :class="containerClasses" container>
|
|
117
|
+
<slot />
|
|
118
|
+
</section>
|
|
117
119
|
</template>
|
|
@@ -49,10 +49,10 @@ export interface IContainerProps {
|
|
|
49
49
|
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
52
|
+
* (推荐)容器宽度(与 Astro 版本保持一致)
|
|
53
|
+
* 与 size 等价;如同时传入,优先使用 width
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
width?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* 圆角大小
|
|
@@ -23,11 +23,13 @@ import type { IHeadingProps } from './types';
|
|
|
23
23
|
* 1. 层次清晰 - 通过不同级别的标题建立内容的视觉层次结构
|
|
24
24
|
* 2. 一致性 - 确保整个应用中标题样式的一致性
|
|
25
25
|
* 3. 可定制性 - 支持多种配置选项,适应不同场景需求
|
|
26
|
-
* 4.
|
|
27
|
-
* 5.
|
|
26
|
+
* 4. 字体控制 - 提供精细的字体粗细控制,满足不同设计需求
|
|
27
|
+
* 5. 无障碍性 - 遵循语义化HTML标准,确保屏幕阅读器可以正确解析内容结构
|
|
28
|
+
* 6. 链接支持 - 标题可以作为链接使用,提供更好的导航体验
|
|
28
29
|
*
|
|
29
30
|
* 视觉特点:
|
|
30
31
|
* - 字体大小和粗细随级别变化
|
|
32
|
+
* - 支持自定义字体粗细(thin 到 black 共8个级别)
|
|
31
33
|
* - 可选的下划线或底部边框
|
|
32
34
|
* - 可定制的颜色和间距
|
|
33
35
|
* - 响应式设计,在不同屏幕尺寸下保持良好的可读性
|
|
@@ -76,6 +78,18 @@ import type { IHeadingProps } from './types';
|
|
|
76
78
|
* <Heading :level="3" background="primary" color="white">主要背景色标题</Heading>
|
|
77
79
|
* ```
|
|
78
80
|
*
|
|
81
|
+
* 字体粗细支持:
|
|
82
|
+
* ```vue
|
|
83
|
+
* <Heading :level="2" weight="thin">细体标题</Heading>
|
|
84
|
+
* <Heading :level="2" weight="light">轻体标题</Heading>
|
|
85
|
+
* <Heading :level="2" weight="normal">正常标题</Heading>
|
|
86
|
+
* <Heading :level="2" weight="medium">中等标题</Heading>
|
|
87
|
+
* <Heading :level="2" weight="semibold">半粗体标题</Heading>
|
|
88
|
+
* <Heading :level="2" weight="bold">粗体标题</Heading>
|
|
89
|
+
* <Heading :level="2" weight="extrabold">特粗体标题</Heading>
|
|
90
|
+
* <Heading :level="2" weight="black">超粗体标题</Heading>
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
79
93
|
* @props
|
|
80
94
|
* @prop {'left'|'center'|'right'} [align='left'] - 文本对齐方式
|
|
81
95
|
* @prop {boolean} [anchor=false] - 是否显示锚点链接图标
|
|
@@ -89,6 +103,7 @@ import type { IHeadingProps } from './types';
|
|
|
89
103
|
* @prop {'none'|'sm'|'md'|'lg'|'xl'} [margin='md'] - 上下外边距大小
|
|
90
104
|
* @prop {'none'|'sm'|'md'|'lg'|'xl'} [padding='none'] - 内边距大小(仅在设置背景色时生效)
|
|
91
105
|
* @prop {boolean} [underline=false] - 是否显示下划线
|
|
106
|
+
* @prop {'thin'|'light'|'normal'|'medium'|'semibold'|'bold'|'extrabold'|'black'} [weight] - 字体粗细,不指定时根据标题级别使用默认粗细(h1: bold, h2-h3: semibold, h4-h6: medium)
|
|
92
107
|
*
|
|
93
108
|
* @slots
|
|
94
109
|
* @slot default - 标题内容
|
|
@@ -115,21 +130,60 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
115
130
|
margin: 'md',
|
|
116
131
|
padding: 'none',
|
|
117
132
|
underline: false,
|
|
133
|
+
weight: undefined,
|
|
118
134
|
});
|
|
119
135
|
|
|
120
|
-
//
|
|
121
|
-
const
|
|
136
|
+
// 字体粗细映射
|
|
137
|
+
const weightClassMap = {
|
|
138
|
+
thin: 'cosy:font-thin',
|
|
139
|
+
light: 'cosy:font-light',
|
|
140
|
+
normal: 'cosy:font-normal',
|
|
141
|
+
medium: 'cosy:font-medium',
|
|
142
|
+
semibold: 'cosy:font-semibold',
|
|
143
|
+
bold: 'cosy:font-bold',
|
|
144
|
+
extrabold: 'cosy:font-extrabold',
|
|
145
|
+
black: 'cosy:font-black',
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// 根据级别设置基础样式(不包含字体粗细)
|
|
149
|
+
const baseHeadingClass = computed(() => {
|
|
122
150
|
const levelMap = {
|
|
123
|
-
1: 'cosy:text-4xl
|
|
124
|
-
2: 'cosy:text-3xl
|
|
125
|
-
3: 'cosy:text-2xl
|
|
126
|
-
4: 'cosy:text-xl
|
|
127
|
-
5: 'cosy:text-lg
|
|
128
|
-
6: 'cosy:text-base
|
|
151
|
+
1: 'cosy:text-4xl',
|
|
152
|
+
2: 'cosy:text-3xl',
|
|
153
|
+
3: 'cosy:text-2xl',
|
|
154
|
+
4: 'cosy:text-xl',
|
|
155
|
+
5: 'cosy:text-lg',
|
|
156
|
+
6: 'cosy:text-base',
|
|
129
157
|
};
|
|
130
158
|
return levelMap[props.level as keyof typeof levelMap] || levelMap[2];
|
|
131
159
|
});
|
|
132
160
|
|
|
161
|
+
// 默认字体粗细(当未指定 weight 时使用)
|
|
162
|
+
const defaultWeightClass = computed(() => {
|
|
163
|
+
const defaultMap = {
|
|
164
|
+
1: 'cosy:font-bold',
|
|
165
|
+
2: 'cosy:font-semibold',
|
|
166
|
+
3: 'cosy:font-semibold',
|
|
167
|
+
4: 'cosy:font-medium',
|
|
168
|
+
5: 'cosy:font-medium',
|
|
169
|
+
6: 'cosy:font-medium',
|
|
170
|
+
};
|
|
171
|
+
return defaultMap[props.level as keyof typeof defaultMap] || defaultMap[2];
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// 字体粗细样式
|
|
175
|
+
const weightClass = computed(() => {
|
|
176
|
+
if (props.weight && props.weight in weightClassMap) {
|
|
177
|
+
return weightClassMap[props.weight as keyof typeof weightClassMap];
|
|
178
|
+
}
|
|
179
|
+
return defaultWeightClass.value;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// 组合标题样式类
|
|
183
|
+
const headingClass = computed(() => {
|
|
184
|
+
return `${baseHeadingClass.value} ${weightClass.value}`;
|
|
185
|
+
});
|
|
186
|
+
|
|
133
187
|
const colorClass = computed(() => {
|
|
134
188
|
const colorMap = {
|
|
135
189
|
default: '',
|
|
@@ -22,5 +22,14 @@ export interface IHeadingProps {
|
|
|
22
22
|
margin?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
|
23
23
|
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
|
24
24
|
underline?: boolean;
|
|
25
|
+
weight?:
|
|
26
|
+
| 'thin'
|
|
27
|
+
| 'light'
|
|
28
|
+
| 'normal'
|
|
29
|
+
| 'medium'
|
|
30
|
+
| 'semibold'
|
|
31
|
+
| 'bold'
|
|
32
|
+
| 'extrabold'
|
|
33
|
+
| 'black';
|
|
25
34
|
}
|
|
26
35
|
|