@coffic/cosy-ui 1.0.14 → 1.0.15
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 +1 -0
- package/dist/index-vue.ts +1 -0
- package/dist/src/components/apple-pad/applePadPropsBase.d.ts +31 -0
- package/dist/src/components/apple-pad/applePadPropsBase.js +1 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Blue - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Blue - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Purple - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Purple - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Space Gray - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Space Gray - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Stardust - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 11/" - M2 - Stardust - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Blue - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Blue - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Purple - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Purple - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Space Gray - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Space Gray - Portrait.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Stardust - Landscape.png +0 -0
- package/dist/src/components/apple-pad/assets/iPad Air 13/" - M2 - Stardust - Portrait.png +0 -0
- package/dist/src/components/apple-pad/constants.d.ts +36 -0
- package/dist/src/components/apple-pad/constants.js +43 -0
- package/dist/src-astro/apple-pad/ApplePad.astro +165 -0
- package/dist/src-astro/apple-pad/PadFrame.astro +23 -0
- package/dist/src-astro/apple-pad/StatusBarContent.astro +119 -0
- package/dist/src-astro/apple-pad/index.ts +5 -0
- package/dist/src-astro/apple-pad/props.ts +6 -0
- package/dist/src-vue/apple-pad/ApplePad.vue +117 -0
- package/dist/src-vue/apple-pad/PadFrame.vue +20 -0
- package/dist/src-vue/apple-pad/StatusBarContent.vue +153 -0
- package/dist/src-vue/apple-pad/index.ts +2 -0
- package/dist/src-vue/apple-pad/props.ts +6 -0
- package/package.json +1 -1
package/dist/index-astro.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./src/utils/url";
|
|
|
20
20
|
export * from "./src-astro/alert";
|
|
21
21
|
export * from "./src-astro/alert-dialog";
|
|
22
22
|
export * from "./src-astro/api-test";
|
|
23
|
+
export * from "./src-astro/apple-pad";
|
|
23
24
|
export * from "./src-astro/apple-phone";
|
|
24
25
|
export * from "./src-astro/article";
|
|
25
26
|
export * from "./src-astro/avatar";
|
package/dist/index-vue.ts
CHANGED
|
@@ -3,6 +3,7 @@ import "./app.css";
|
|
|
3
3
|
export * from "./src-vue/alert/index";
|
|
4
4
|
// 导出组件,按照字母排序
|
|
5
5
|
export * from "./src-vue/alert-dialog/index";
|
|
6
|
+
export * from "./src-vue/apple-pad/index";
|
|
6
7
|
export * from "./src-vue/apple-phone/index";
|
|
7
8
|
export * from "./src-vue/avatar/index";
|
|
8
9
|
export * from "./src-vue/badge/index";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BackgroundColor } from "../../../src/common/backgrounds";
|
|
2
|
+
/**
|
|
3
|
+
* ApplePad 组件的基础属性接口(与框架无关)
|
|
4
|
+
*/
|
|
5
|
+
export interface IApplePadPropsBase {
|
|
6
|
+
/**
|
|
7
|
+
* 窗口高度选项
|
|
8
|
+
* @default 'lg'
|
|
9
|
+
*/
|
|
10
|
+
height?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl";
|
|
11
|
+
/**
|
|
12
|
+
* 窗口标题
|
|
13
|
+
* @default ''
|
|
14
|
+
*/
|
|
15
|
+
title?: string;
|
|
16
|
+
/**
|
|
17
|
+
* 是否显示阴影效果
|
|
18
|
+
* @default true
|
|
19
|
+
*/
|
|
20
|
+
withShadow?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* 是否显示 iPad 边框
|
|
23
|
+
* @default true
|
|
24
|
+
*/
|
|
25
|
+
showFrame?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* 内容区域背景色
|
|
28
|
+
* @default undefined
|
|
29
|
+
*/
|
|
30
|
+
backgroundColor?: BackgroundColor;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApplePad 组件的常量定义
|
|
3
|
+
*
|
|
4
|
+
* 基于 iPad Air 11" M2 竖屏模式
|
|
5
|
+
* 边框图片: 1900 × 2620 px
|
|
6
|
+
* 设备屏幕: 1640 × 2360 点
|
|
7
|
+
*/
|
|
8
|
+
export declare const IPAD_FRAME_WIDTH = 1900;
|
|
9
|
+
export declare const IPAD_FRAME_HEIGHT = 2620;
|
|
10
|
+
export declare const IPAD_FRAME_STATUS_BAR_TOP = 155;
|
|
11
|
+
export declare const IPAD_FRAME_STATUS_BAR_HEIGHT = 70;
|
|
12
|
+
export declare const MAIN_CONTENT_WIDTH_ASPECT_RATIO: number;
|
|
13
|
+
export declare const MAIN_CONTENT_HEIGHT_ASPECT_RATIO: number;
|
|
14
|
+
export declare const IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO: number;
|
|
15
|
+
export declare const IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO: number;
|
|
16
|
+
export declare const HEIGHT_CLASSES: {
|
|
17
|
+
readonly sm: "cosy:h-[400px]";
|
|
18
|
+
readonly md: "cosy:h-[500px]";
|
|
19
|
+
readonly lg: "cosy:h-[600px]";
|
|
20
|
+
readonly xl: "cosy:h-[700px]";
|
|
21
|
+
readonly "2xl": "cosy:h-[800px]";
|
|
22
|
+
readonly "3xl": "cosy:h-[900px]";
|
|
23
|
+
readonly "4xl": "cosy:h-[1000px]";
|
|
24
|
+
readonly "5xl": "cosy:h-[1100px]";
|
|
25
|
+
};
|
|
26
|
+
export declare const HEIGHT_VALUES: {
|
|
27
|
+
readonly sm: 400;
|
|
28
|
+
readonly md: 500;
|
|
29
|
+
readonly lg: 600;
|
|
30
|
+
readonly xl: 700;
|
|
31
|
+
readonly "2xl": 800;
|
|
32
|
+
readonly "3xl": 900;
|
|
33
|
+
readonly "4xl": 1000;
|
|
34
|
+
readonly "5xl": 1100;
|
|
35
|
+
};
|
|
36
|
+
export declare const DEFAULT_HEIGHT: keyof typeof HEIGHT_VALUES;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApplePad 组件的常量定义
|
|
3
|
+
*
|
|
4
|
+
* 基于 iPad Air 11" M2 竖屏模式
|
|
5
|
+
* 边框图片: 1900 × 2620 px
|
|
6
|
+
* 设备屏幕: 1640 × 2360 点
|
|
7
|
+
*/
|
|
8
|
+
// iPad 边框图片尺寸
|
|
9
|
+
export const IPAD_FRAME_WIDTH = 1900;
|
|
10
|
+
export const IPAD_FRAME_HEIGHT = 2620;
|
|
11
|
+
// iPad 边框图片 - 状态栏离上边框的距离
|
|
12
|
+
export const IPAD_FRAME_STATUS_BAR_TOP = 155;
|
|
13
|
+
// iPad 边框图片 - 状态栏高度
|
|
14
|
+
export const IPAD_FRAME_STATUS_BAR_HEIGHT = 70;
|
|
15
|
+
// 比例计算
|
|
16
|
+
export const MAIN_CONTENT_WIDTH_ASPECT_RATIO = 1640 / IPAD_FRAME_WIDTH;
|
|
17
|
+
export const MAIN_CONTENT_HEIGHT_ASPECT_RATIO = 2360 / IPAD_FRAME_HEIGHT;
|
|
18
|
+
export const IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO = IPAD_FRAME_STATUS_BAR_HEIGHT / IPAD_FRAME_HEIGHT;
|
|
19
|
+
export const IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO = IPAD_FRAME_STATUS_BAR_TOP / IPAD_FRAME_HEIGHT;
|
|
20
|
+
// 预定义的高度选项(iPad 比 iPhone 大,默认值也更大)
|
|
21
|
+
export const HEIGHT_CLASSES = {
|
|
22
|
+
sm: "cosy:h-[400px]", // 400px
|
|
23
|
+
md: "cosy:h-[500px]", // 500px
|
|
24
|
+
lg: "cosy:h-[600px]", // 600px
|
|
25
|
+
xl: "cosy:h-[700px]", // 700px
|
|
26
|
+
"2xl": "cosy:h-[800px]", // 800px
|
|
27
|
+
"3xl": "cosy:h-[900px]", // 900px
|
|
28
|
+
"4xl": "cosy:h-[1000px]", // 1000px
|
|
29
|
+
"5xl": "cosy:h-[1100px]", // 1100px
|
|
30
|
+
};
|
|
31
|
+
// 高度值映射
|
|
32
|
+
export const HEIGHT_VALUES = {
|
|
33
|
+
sm: 400,
|
|
34
|
+
md: 500,
|
|
35
|
+
lg: 600,
|
|
36
|
+
xl: 700,
|
|
37
|
+
"2xl": 800,
|
|
38
|
+
"3xl": 900,
|
|
39
|
+
"4xl": 1000,
|
|
40
|
+
"5xl": 1100,
|
|
41
|
+
};
|
|
42
|
+
// 默认高度
|
|
43
|
+
export const DEFAULT_HEIGHT = "lg";
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component ApplePad
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* ApplePad 组件模拟 iPad 设备的外观,包含状态栏、时间显示和设备边框。
|
|
7
|
+
* 适用于创建平板应用界面原型或展示平板端设计效果。
|
|
8
|
+
*
|
|
9
|
+
* @usage
|
|
10
|
+
* 基本用法:
|
|
11
|
+
* ```astro
|
|
12
|
+
* <ApplePad title="我的应用">
|
|
13
|
+
* <div>应用内容</div>
|
|
14
|
+
* </ApplePad>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* 自定义高度和背景色:
|
|
18
|
+
* ```astro
|
|
19
|
+
* <ApplePad height="xl" backgroundColor="primary/10">
|
|
20
|
+
* <div>应用内容</div>
|
|
21
|
+
* </ApplePad>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* 不显示边框:
|
|
25
|
+
* ```astro
|
|
26
|
+
* <ApplePad showFrame={false}>
|
|
27
|
+
* <div>应用内容</div>
|
|
28
|
+
* </ApplePad>
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @props
|
|
32
|
+
* @prop {'sm'|'md'|'lg'|'xl'|'2xl'|'3xl'|'4xl'|'5xl'} [height='lg'] - 窗口高度选项
|
|
33
|
+
* - sm: 400px
|
|
34
|
+
* - md: 500px
|
|
35
|
+
* - lg: 600px - 默认值
|
|
36
|
+
* - xl: 700px
|
|
37
|
+
* - 2xl: 800px
|
|
38
|
+
* - 3xl: 900px
|
|
39
|
+
* - 4xl: 1000px
|
|
40
|
+
* - 5xl: 1100px
|
|
41
|
+
* @prop {String} [title=''] - 窗口标题
|
|
42
|
+
* @prop {Boolean} [withShadow=true] - 是否显示阴影效果
|
|
43
|
+
* @prop {Boolean} [showFrame=true] - 是否显示 iPad 边框
|
|
44
|
+
* @prop {BackgroundColor} [backgroundColor=''] - 内容区域背景色,等同于为其内部的 Container 设置背景色
|
|
45
|
+
*
|
|
46
|
+
* @slots
|
|
47
|
+
* @slot default - 主要内容区域
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import { cn } from '../../src/class';
|
|
51
|
+
import type { IApplePadPropsBase } from '../../src/components/apple-pad/applePadPropsBase';
|
|
52
|
+
import {
|
|
53
|
+
DEFAULT_HEIGHT,
|
|
54
|
+
HEIGHT_CLASSES,
|
|
55
|
+
HEIGHT_VALUES,
|
|
56
|
+
IPAD_FRAME_HEIGHT,
|
|
57
|
+
IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO,
|
|
58
|
+
IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO,
|
|
59
|
+
IPAD_FRAME_WIDTH,
|
|
60
|
+
MAIN_CONTENT_HEIGHT_ASPECT_RATIO,
|
|
61
|
+
MAIN_CONTENT_WIDTH_ASPECT_RATIO,
|
|
62
|
+
} from '../../src/components/apple-pad/constants';
|
|
63
|
+
import { AlertDialog } from '../alert-dialog';
|
|
64
|
+
import { Container } from '../container';
|
|
65
|
+
import PadFrame from './PadFrame.astro';
|
|
66
|
+
import StatusBarContent from './StatusBarContent.astro';
|
|
67
|
+
|
|
68
|
+
// Props 定义 - 使用共享接口
|
|
69
|
+
interface Props extends IApplePadPropsBase {}
|
|
70
|
+
|
|
71
|
+
const {
|
|
72
|
+
height = DEFAULT_HEIGHT,
|
|
73
|
+
showFrame = true,
|
|
74
|
+
backgroundColor = undefined,
|
|
75
|
+
} = Astro.props as Props;
|
|
76
|
+
|
|
77
|
+
// 计算当前高度的缩放比例
|
|
78
|
+
const currentHeight = HEIGHT_VALUES[height];
|
|
79
|
+
const scaleRatio = currentHeight / 600;
|
|
80
|
+
|
|
81
|
+
// 生成唯一的ID
|
|
82
|
+
const uniqueId = `apple-pad-${Math.random().toString(36).slice(2, 11)}`;
|
|
83
|
+
|
|
84
|
+
// 响应式数据
|
|
85
|
+
const alertMessage = '';
|
|
86
|
+
|
|
87
|
+
// 使用 classBuilder 构建各个部分的类名
|
|
88
|
+
const padContainerClass = cn()
|
|
89
|
+
.relative()
|
|
90
|
+
.add('not-prose', 'cosy:mx-auto', HEIGHT_CLASSES[height])
|
|
91
|
+
.build();
|
|
92
|
+
|
|
93
|
+
const statusBarClass = cn().absolute().w('full').add('cosy:z-50').build();
|
|
94
|
+
|
|
95
|
+
const contentAreaClass = cn()
|
|
96
|
+
.absolute()
|
|
97
|
+
.add('cosy:inset-0')
|
|
98
|
+
.h('full')
|
|
99
|
+
.flex('col')
|
|
100
|
+
.build();
|
|
101
|
+
|
|
102
|
+
const containerClass = cn()
|
|
103
|
+
.h('full')
|
|
104
|
+
.add('cosy:overflow-y-auto', 'cosy:overscroll-y-contain')
|
|
105
|
+
.build();
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
<div
|
|
109
|
+
class={padContainerClass}
|
|
110
|
+
style={`aspect-ratio: ${IPAD_FRAME_WIDTH}/${IPAD_FRAME_HEIGHT};`}
|
|
111
|
+
apple-pad>
|
|
112
|
+
<!-- iPad 边框 -->
|
|
113
|
+
{showFrame && <PadFrame />}
|
|
114
|
+
|
|
115
|
+
<!-- 顶部状态栏 -->
|
|
116
|
+
<div
|
|
117
|
+
class={statusBarClass}
|
|
118
|
+
style={`top: ${IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO * 100}%; height: ${IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO * 100}%; width: ${MAIN_CONTENT_WIDTH_ASPECT_RATIO * 100}%; left: 50%; transform: translate(-50%, 0); padding-left: 5%; padding-right: 5%;`}>
|
|
119
|
+
<!-- StatusBarContent 组件 -->
|
|
120
|
+
<StatusBarContent scaleRatio={scaleRatio} />
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- 内容区域 -->
|
|
124
|
+
<div
|
|
125
|
+
class={contentAreaClass}
|
|
126
|
+
style={`width: ${MAIN_CONTENT_WIDTH_ASPECT_RATIO * 100}%; height: ${MAIN_CONTENT_HEIGHT_ASPECT_RATIO * 100}%; left: 50%; top: 50%; transform: translate(-50%, -50%);`}>
|
|
127
|
+
<Container
|
|
128
|
+
rounded="lg"
|
|
129
|
+
height="full"
|
|
130
|
+
padding="none"
|
|
131
|
+
class={containerClass}
|
|
132
|
+
background={backgroundColor || 'accent/90'}>
|
|
133
|
+
<slot />
|
|
134
|
+
</Container>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<!-- iPad 边框(第二次渲染,盖住内容四角) -->
|
|
138
|
+
{showFrame && <PadFrame />}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<AlertDialog id={`${uniqueId}-alert`} message={alertMessage} />
|
|
142
|
+
|
|
143
|
+
<script>
|
|
144
|
+
// 全局函数,用于处理状态栏时间更新
|
|
145
|
+
function updateTime() {
|
|
146
|
+
const now = new Date();
|
|
147
|
+
const hours = now.getHours().toString().padStart(2, '0');
|
|
148
|
+
const minutes = now.getMinutes().toString().padStart(2, '0');
|
|
149
|
+
return `${hours}:${minutes}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 更新时间显示
|
|
153
|
+
function updateStatusBarTime() {
|
|
154
|
+
const timeElements = document.querySelectorAll('[data-time-text]');
|
|
155
|
+
timeElements.forEach((element) => {
|
|
156
|
+
(element as HTMLElement).textContent = updateTime();
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 初始化并设置定时器
|
|
161
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
162
|
+
updateStatusBarTime();
|
|
163
|
+
setInterval(updateStatusBarTime, 60000); // 每分钟更新一次
|
|
164
|
+
});
|
|
165
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component PadFrame
|
|
4
|
+
* @description ApplePad 组件的内部边框组件,用于显示 iPad 设备的边框
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { cn } from '../../src/class';
|
|
8
|
+
import ipadFrame from '../../src/components/apple-pad/assets/iPad Air 11" - M2 - Purple - Portrait.png';
|
|
9
|
+
import { Image } from '../image';
|
|
10
|
+
|
|
11
|
+
// 使用 class builder 构建类名
|
|
12
|
+
const frameClass = cn()
|
|
13
|
+
.add('cosy:max-w-full', 'cosy:max-h-full')
|
|
14
|
+
.absolute()
|
|
15
|
+
.add('cosy:top-0', 'cosy:left-0')
|
|
16
|
+
.add('cosy:z-10')
|
|
17
|
+
.add('cosy:pointer-events-none')
|
|
18
|
+
.build();
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<div class={frameClass}>
|
|
22
|
+
<Image src={ipadFrame} alt="iPad frame" />
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component StatusBarContent
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* StatusBarContent 组件显示 iPad 状态栏的内容,包括时间、信号、WiFi 和电池图标。
|
|
7
|
+
* 组件会自动更新时间显示,并支持根据设备大小进行缩放。
|
|
8
|
+
*
|
|
9
|
+
* @usage
|
|
10
|
+
* 基本用法:
|
|
11
|
+
* ```astro
|
|
12
|
+
* <StatusBarContent />
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* 带缩放比例:
|
|
16
|
+
* ```astro
|
|
17
|
+
* <StatusBarContent scaleRatio={1.5} />
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @props
|
|
21
|
+
* @prop {Number} [scaleRatio=1] - 缩放比例,用于根据设备大小调整文字和图标大小
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { cn } from '../../src/class';
|
|
25
|
+
import { IPhoneBatteryIcon, IPhoneSignalIcon, IPhoneWifiIcon } from '../icons';
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
scaleRatio?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { scaleRatio = 1 } = Astro.props as Props;
|
|
32
|
+
|
|
33
|
+
// 计算缩放后的字体大小
|
|
34
|
+
const scaledFontSize = `${14 * scaleRatio}px`;
|
|
35
|
+
|
|
36
|
+
// 计算缩放后的图标尺寸
|
|
37
|
+
const scaledIconSize = `${15 * scaleRatio}px`;
|
|
38
|
+
|
|
39
|
+
// 使用 classBuilder 构建各个部分的类名
|
|
40
|
+
const containerClass = cn()
|
|
41
|
+
.flex('row')
|
|
42
|
+
.items('center')
|
|
43
|
+
.h('full')
|
|
44
|
+
.justify('between')
|
|
45
|
+
.build();
|
|
46
|
+
|
|
47
|
+
const timeTextClass = cn().weight('medium').build();
|
|
48
|
+
|
|
49
|
+
const iconsContainerClass = cn()
|
|
50
|
+
.flex('row')
|
|
51
|
+
.items('center')
|
|
52
|
+
.gap(1)
|
|
53
|
+
.h('full')
|
|
54
|
+
.build();
|
|
55
|
+
|
|
56
|
+
const iconWrapperClass = cn()
|
|
57
|
+
.flex('row')
|
|
58
|
+
.items('center')
|
|
59
|
+
.justify('center')
|
|
60
|
+
.build();
|
|
61
|
+
|
|
62
|
+
const statusIconClass = cn().add('status-icon').build();
|
|
63
|
+
|
|
64
|
+
const batteryIconClass = cn().add('battery-icon').build();
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
<div class={containerClass}>
|
|
68
|
+
<!-- 左侧时间 -->
|
|
69
|
+
<span
|
|
70
|
+
class={timeTextClass}
|
|
71
|
+
data-time-text
|
|
72
|
+
style={`font-size: ${scaledFontSize}; line-height: 1; transition: font-size 0.2s ease;`}>
|
|
73
|
+
12:00
|
|
74
|
+
</span>
|
|
75
|
+
|
|
76
|
+
<!-- 右侧状态图标 -->
|
|
77
|
+
<div class={iconsContainerClass}>
|
|
78
|
+
<!-- 信号图标 -->
|
|
79
|
+
<div
|
|
80
|
+
class={iconWrapperClass}
|
|
81
|
+
style={`width: ${scaledIconSize}; height: ${scaledIconSize}; min-width: 0; min-height: 0;`}>
|
|
82
|
+
<IPhoneSignalIcon class={statusIconClass} />
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- WiFi图标 -->
|
|
86
|
+
<div
|
|
87
|
+
class={iconWrapperClass}
|
|
88
|
+
style={`width: ${scaledIconSize}; height: ${scaledIconSize}; min-width: 0; min-height: 0;`}>
|
|
89
|
+
<IPhoneWifiIcon class={statusIconClass} />
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<!-- 电池图标 -->
|
|
93
|
+
<div
|
|
94
|
+
class={iconWrapperClass}
|
|
95
|
+
style={`width: ${scaledIconSize}; height: ${scaledIconSize}; min-width: 0; min-height: 0;`}>
|
|
96
|
+
<IPhoneBatteryIcon class={batteryIconClass} />
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<style>
|
|
102
|
+
/* 确保图标渲染更平滑 */
|
|
103
|
+
svg {
|
|
104
|
+
shape-rendering: geometricPrecision;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* 状态图标通用样式 */
|
|
108
|
+
.status-icon,
|
|
109
|
+
.battery-icon {
|
|
110
|
+
color: #000000;
|
|
111
|
+
fill: currentColor;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.status-icon svg,
|
|
115
|
+
.battery-icon svg {
|
|
116
|
+
width: 100%;
|
|
117
|
+
height: 100%;
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from "vue";
|
|
3
|
+
import { AlertDialog, Container } from "../../index-vue";
|
|
4
|
+
import PadFrame from "./PadFrame.vue";
|
|
5
|
+
import StatusBarContent from "./StatusBarContent.vue";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @component ApplePad
|
|
9
|
+
* @description ApplePad 组件模拟 iPad 设备的外观,包含状态栏、时间显示和设备边框。
|
|
10
|
+
* 适用于创建平板应用界面原型或展示平板端设计效果。
|
|
11
|
+
* @props
|
|
12
|
+
* @prop {'sm'|'md'|'lg'|'xl'|'2xl'|'3xl'|'4xl'|'5xl'} [height='lg'] - 窗口高度选项
|
|
13
|
+
* - sm: 400px
|
|
14
|
+
* - md: 500px
|
|
15
|
+
* - lg: 600px - 默认值
|
|
16
|
+
* - xl: 700px
|
|
17
|
+
* - 2xl: 800px
|
|
18
|
+
* - 3xl: 900px
|
|
19
|
+
* - 4xl: 1000px
|
|
20
|
+
* - 5xl: 1100px
|
|
21
|
+
* @prop {String} [title=''] - 窗口标题
|
|
22
|
+
* @prop {Boolean} [withShadow=true] - 是否显示阴影效果
|
|
23
|
+
* @prop {Boolean} [showFrame=true] - 是否显示 iPad 边框
|
|
24
|
+
* @prop {BackgroundColor} [backgroundColor=''] - 内容区域背景色
|
|
25
|
+
* @slots
|
|
26
|
+
* @slot default - 主要内容区域
|
|
27
|
+
* @emits
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import type { IApplePadProps } from "./props";
|
|
31
|
+
|
|
32
|
+
interface Props extends IApplePadProps {}
|
|
33
|
+
|
|
34
|
+
// Props 定义
|
|
35
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
36
|
+
height: "lg",
|
|
37
|
+
title: "",
|
|
38
|
+
withShadow: true,
|
|
39
|
+
showFrame: true,
|
|
40
|
+
backgroundColor: undefined,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
import {
|
|
44
|
+
HEIGHT_CLASSES,
|
|
45
|
+
HEIGHT_VALUES,
|
|
46
|
+
IPAD_FRAME_HEIGHT,
|
|
47
|
+
IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO,
|
|
48
|
+
IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO,
|
|
49
|
+
IPAD_FRAME_WIDTH,
|
|
50
|
+
MAIN_CONTENT_HEIGHT_ASPECT_RATIO,
|
|
51
|
+
MAIN_CONTENT_WIDTH_ASPECT_RATIO,
|
|
52
|
+
} from "../../src/components/apple-pad/constants";
|
|
53
|
+
|
|
54
|
+
// 响应式数据
|
|
55
|
+
const showAlertDialog = ref(false);
|
|
56
|
+
const alertMessage = ref("");
|
|
57
|
+
|
|
58
|
+
// 计算当前高度的缩放比例
|
|
59
|
+
const getScaleRatio = () => {
|
|
60
|
+
const currentHeight = HEIGHT_VALUES[props.height];
|
|
61
|
+
return currentHeight / 600;
|
|
62
|
+
};
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<div
|
|
67
|
+
:class="['cosy:relative not-prose cosy:mx-auto', HEIGHT_CLASSES[height]]"
|
|
68
|
+
:style="{
|
|
69
|
+
aspectRatio: `${IPAD_FRAME_WIDTH}/${IPAD_FRAME_HEIGHT}`,
|
|
70
|
+
}"
|
|
71
|
+
apple-pad>
|
|
72
|
+
<!-- iPad 边框 -->
|
|
73
|
+
<PadFrame v-if="showFrame" />
|
|
74
|
+
|
|
75
|
+
<!-- 顶部状态栏 -->
|
|
76
|
+
<div
|
|
77
|
+
:style="{
|
|
78
|
+
position: 'absolute',
|
|
79
|
+
top: IPAD_FRAME_STATUS_BAR_TOP_ASPECT_RATIO * 100 + '%',
|
|
80
|
+
height: IPAD_FRAME_STATUS_BAR_HEIGHT_ASPECT_RATIO * 100 + '%',
|
|
81
|
+
width: MAIN_CONTENT_WIDTH_ASPECT_RATIO * 100 + '%',
|
|
82
|
+
left: '50%',
|
|
83
|
+
transform: 'translate(-50%, 0)',
|
|
84
|
+
paddingLeft: '5%',
|
|
85
|
+
paddingRight: '5%',
|
|
86
|
+
zIndex: 50,
|
|
87
|
+
}">
|
|
88
|
+
<StatusBarContent :scaleRatio="getScaleRatio()" />
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!-- 内容区域 -->
|
|
92
|
+
<div
|
|
93
|
+
class="cosy:inset-0 cosy:h-full cosy:flex cosy:flex-col"
|
|
94
|
+
:style="{
|
|
95
|
+
width: MAIN_CONTENT_WIDTH_ASPECT_RATIO * 100 + '%',
|
|
96
|
+
height: MAIN_CONTENT_HEIGHT_ASPECT_RATIO * 100 + '%',
|
|
97
|
+
left: '50%',
|
|
98
|
+
top: '50%',
|
|
99
|
+
transform: 'translate(-50%, -50%)',
|
|
100
|
+
position: 'absolute',
|
|
101
|
+
}">
|
|
102
|
+
<Container
|
|
103
|
+
rounded="lg"
|
|
104
|
+
height="full"
|
|
105
|
+
padding="none"
|
|
106
|
+
class="cosy:h-full cosy:overflow-y-auto cosy:overscroll-y-contain"
|
|
107
|
+
:background="backgroundColor || 'accent/90'">
|
|
108
|
+
<slot />
|
|
109
|
+
</Container>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- iPad 边框(第二次渲染,盖住内容四角) -->
|
|
113
|
+
<PadFrame v-if="showFrame" />
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<AlertDialog v-model="showAlertDialog" :message="alertMessage" />
|
|
117
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import ipadFrame from "../../src/components/apple-pad/assets/iPad Air 11\" - M2 - Purple - Portrait.png";
|
|
3
|
+
|
|
4
|
+
const ipadFrameSrc = (ipadFrame as any).src || ipadFrame;
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<div
|
|
9
|
+
style="
|
|
10
|
+
max-width: 100%;
|
|
11
|
+
max-height: 100%;
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 0;
|
|
14
|
+
left: 0;
|
|
15
|
+
z-index: 10;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
">
|
|
18
|
+
<img :src="ipadFrameSrc" alt="iPad frame" />
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|