@coffic/cosy-ui 0.9.68 → 0.9.71
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/src/components/button/buttonPropsBase.ts +1 -1
- package/dist/src/components/button/class-all.ts +21 -1
- package/dist/src/components/container/validate-sizing.ts +3 -4
- package/dist/src/components/link/class-all.ts +1 -3
- package/dist/src/components/link/linkPropsBase.ts +2 -0
- package/dist/src/utils/language.ts +2 -2
- package/dist/src/utils/link.ts +13 -13
- package/dist/src-astro/alert/Alert.astro +0 -3
- package/dist/src-astro/contact/Contact.astro +1 -1
- package/dist/src-astro/grid/Grid.astro +1 -1
- package/dist/src-astro/header/Header.astro +1 -1
- package/dist/src-astro/header/HeaderCenter.astro +1 -1
- package/dist/src-astro/header/MobileNav.astro +1 -1
- package/dist/src-astro/layout-basic/BaseLayout.astro +2 -2
- package/dist/src-astro/layout-dashboard/DashboardLayout.astro +1 -1
- package/dist/src-astro/link/types.ts +2 -4
- package/dist/src-vue/apple-phone/ApplePhone.vue +151 -133
- package/dist/src-vue/button/Button.vue +1 -0
- package/dist/src-vue/button/class.ts +21 -1
- package/dist/src-vue/image-display/ImageGrid.vue +1 -3
- package/dist/src-vue/image-display/ImageItem.vue +1 -3
- package/dist/src-vue/image-display/ImagePreview.vue +1 -3
- package/dist/src-vue/image-display/types.ts +1 -3
- package/dist/src-vue/key-catcher/KeyCatcher.vue +1 -1
- package/dist/src-vue/link/Link.vue +2 -0
- package/dist/src-vue/review/Review.vue +13 -3
- package/dist/src-vue/review/Reviews.vue +69 -0
- package/dist/src-vue/review/index.ts +5 -1
- package/dist/src-vue/review/props.ts +1 -10
- package/dist/src-vue/status-bar/StatusBarItem.vue +1 -3
- package/dist/src-vue/utils/link.ts +14 -14
- package/package.json +2 -17
|
@@ -6,6 +6,23 @@ import { getButtonShapeClass } from "./class-shape";
|
|
|
6
6
|
import { getButtonModifierClasses } from "./class-modifiers";
|
|
7
7
|
import { getButtonGradientClass } from "./class-gradient";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* 将可能的对象形式的 class 转换为字符串
|
|
11
|
+
* @param className 类名,可以是字符串或对象
|
|
12
|
+
* @returns 字符串形式的类名
|
|
13
|
+
*/
|
|
14
|
+
function normalizeClass(className: string | object | undefined): string {
|
|
15
|
+
if (!className) return "";
|
|
16
|
+
if (typeof className === "string") return className;
|
|
17
|
+
if (typeof className === "object") {
|
|
18
|
+
return Object.entries(className)
|
|
19
|
+
.filter(([, value]) => value)
|
|
20
|
+
.map(([key]) => key)
|
|
21
|
+
.join(" ");
|
|
22
|
+
}
|
|
23
|
+
return "";
|
|
24
|
+
}
|
|
25
|
+
|
|
9
26
|
/**
|
|
10
27
|
* 计算 Button 组件的组合类名(用于基础接口)
|
|
11
28
|
* @param props Button 组件的基础 props
|
|
@@ -22,6 +39,9 @@ export function getBaseButtonClasses(props: IButtonPropsBase): string[] {
|
|
|
22
39
|
class: className = "",
|
|
23
40
|
} = props;
|
|
24
41
|
|
|
42
|
+
// 规范化 class 属性
|
|
43
|
+
const normalizedClass = normalizeClass(className);
|
|
44
|
+
|
|
25
45
|
// 构建基础类名
|
|
26
46
|
const baseClasses = getButtonBaseClasses();
|
|
27
47
|
|
|
@@ -48,7 +68,7 @@ export function getBaseButtonClasses(props: IButtonPropsBase): string[] {
|
|
|
48
68
|
shapeClass,
|
|
49
69
|
...modifierClasses,
|
|
50
70
|
gradientClass,
|
|
51
|
-
|
|
71
|
+
normalizedClass,
|
|
52
72
|
];
|
|
53
73
|
|
|
54
74
|
return classes;
|
|
@@ -8,16 +8,15 @@ export function validateSizing(props: Record<string, unknown>): string[] {
|
|
|
8
8
|
|
|
9
9
|
// 检查属性是否被显式设置(不为 undefined 且不为默认值)
|
|
10
10
|
const isAspectRatioSet =
|
|
11
|
-
Object.
|
|
12
|
-
props.aspectRatio !== undefined;
|
|
11
|
+
Object.hasOwn(props, "aspectRatio") && props.aspectRatio !== undefined;
|
|
13
12
|
|
|
14
13
|
const isHeightSet =
|
|
15
|
-
Object.
|
|
14
|
+
Object.hasOwn(props, "height") &&
|
|
16
15
|
props.height !== undefined &&
|
|
17
16
|
props.height !== "none";
|
|
18
17
|
|
|
19
18
|
const isWidthSet =
|
|
20
|
-
Object.
|
|
19
|
+
Object.hasOwn(props, "width") &&
|
|
21
20
|
props.width !== undefined &&
|
|
22
21
|
props.width !== "none";
|
|
23
22
|
|
|
@@ -34,13 +34,11 @@ export function getBaseLinkClasses(props: ILinkPropsBase): string[] {
|
|
|
34
34
|
active = false,
|
|
35
35
|
navigationType,
|
|
36
36
|
icon,
|
|
37
|
-
hoverImage,
|
|
38
|
-
hoverImageAlt,
|
|
39
37
|
...rest
|
|
40
38
|
} = props;
|
|
41
39
|
|
|
42
40
|
// 构建基础类名
|
|
43
|
-
const baseClasses = getLinkBaseClasses(block, icon, hoverImage);
|
|
41
|
+
const baseClasses = getLinkBaseClasses(block, icon, rest["hoverImage"]);
|
|
44
42
|
|
|
45
43
|
// 构建变体类名
|
|
46
44
|
const variantClasses = getLinkVariantClasses(
|
|
@@ -34,13 +34,13 @@ export class LanguageUtil {
|
|
|
34
34
|
return astroLang;
|
|
35
35
|
}
|
|
36
36
|
// 尝试从URL中获取语言
|
|
37
|
-
const urlLang =
|
|
37
|
+
const urlLang = LanguageUtil.getLanguageFromURL(astro.url.pathname);
|
|
38
38
|
if (urlLang) {
|
|
39
39
|
return urlLang;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// 尝试从浏览器设置中获取语言
|
|
43
|
-
const browserLang =
|
|
43
|
+
const browserLang = LanguageUtil.getLanguageFromBrowser();
|
|
44
44
|
if (browserLang) {
|
|
45
45
|
return browserLang;
|
|
46
46
|
}
|
package/dist/src/utils/link.ts
CHANGED
|
@@ -32,7 +32,7 @@ export class LinkUtil {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
static getHomeLink(lang: string): string {
|
|
35
|
-
return `${
|
|
35
|
+
return `${LinkUtil.getBaseUrl()}/${lang}`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
static getLessonsLink(lang: string): string {
|
|
@@ -62,10 +62,10 @@ export class LinkUtil {
|
|
|
62
62
|
|
|
63
63
|
static getLessonLink(lang: string, lessonId: string): string {
|
|
64
64
|
if (lessonId.endsWith(lang)) {
|
|
65
|
-
return `${
|
|
65
|
+
return `${LinkUtil.getBaseUrl()}${lang}/lessons/${lessonId.replace(`${lang}`, "")}`;
|
|
66
66
|
} else {
|
|
67
67
|
const idWithoutLang = lessonId.replace(`${lang}/`, "");
|
|
68
|
-
return `${
|
|
68
|
+
return `${LinkUtil.getBaseUrl()}${lang}/lessons/${idWithoutLang}`;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -97,43 +97,43 @@ export class LinkUtil {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
static getMetaLink(lang: string, slug: string): string {
|
|
100
|
-
return `/${
|
|
100
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/meta/${slug}`;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
static getSigninLink(lang: string): string {
|
|
104
|
-
return `/${
|
|
104
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/signin`;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
static getAuthCallbackCookieLink(lang: string): string {
|
|
108
|
-
return `/${
|
|
108
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/auth/callback_cookie`;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
static getAuthCallbackTokenLink(lang: string): string {
|
|
112
|
-
return `/${
|
|
112
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/auth/callback_token`;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
static getAuthAccountLink(lang: string): string {
|
|
116
|
-
return `/${
|
|
116
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/auth/account`;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
static getDashboardUrl(lang: string): string {
|
|
120
|
-
return `/${
|
|
120
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/auth/dashboard`;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
static getAuthErrorLink(lang: string): string {
|
|
124
|
-
return `/${
|
|
124
|
+
return `/${LinkUtil.normalizeLanguage(lang)}/auth/error`;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
static getPrivacyLink(lang: string): string {
|
|
128
|
-
return
|
|
128
|
+
return LinkUtil.getMetaLink(lang, "privacy");
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
static getTermsLink(lang: string): string {
|
|
132
|
-
return
|
|
132
|
+
return LinkUtil.getMetaLink(lang, "terms");
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
static getAboutLink(lang: string): string {
|
|
136
|
-
return
|
|
136
|
+
return LinkUtil.getMetaLink(lang, "about");
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
@@ -73,7 +73,6 @@ import {
|
|
|
73
73
|
ErrorIcon,
|
|
74
74
|
CloseIcon,
|
|
75
75
|
} from "../../index-astro";
|
|
76
|
-
import { marginClasses, type MarginSize } from "../../src/common/margin";
|
|
77
76
|
|
|
78
77
|
// 根据类型设置图标组件
|
|
79
78
|
const getIconComponent = (type: string) => {
|
|
@@ -95,8 +94,6 @@ const {
|
|
|
95
94
|
class: className = "",
|
|
96
95
|
closable = true,
|
|
97
96
|
showIcon = true,
|
|
98
|
-
variant = "solid",
|
|
99
|
-
marginY,
|
|
100
97
|
} = props;
|
|
101
98
|
|
|
102
99
|
// 获取图标组件
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
import "../../style.ts";
|
|
109
109
|
import Card from "../card/Card.astro";
|
|
110
110
|
import Link from "../link/Link.astro";
|
|
111
|
-
import {
|
|
111
|
+
import type { BackgroundColor } from "../../src/common/backgrounds";
|
|
112
112
|
import {
|
|
113
113
|
FacebookIcon,
|
|
114
114
|
GithubIcon,
|
|
@@ -104,7 +104,7 @@ const linkHeightClass =
|
|
|
104
104
|
linkHeightClasses[height as keyof typeof linkHeightClasses];
|
|
105
105
|
|
|
106
106
|
// 检查 i18n 是否启用,通过 Astro.currentLocale 来判断
|
|
107
|
-
|
|
107
|
+
const isI18nEnabled = Astro.currentLocale !== undefined;
|
|
108
108
|
|
|
109
109
|
const currentPath = Astro.url.pathname;
|
|
110
110
|
const activeLink = LinkUtil.getActiveLink(
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* - linkHeightClass - 链接高度类名
|
|
25
25
|
* - gap - 导航项之间的间距,可选值:0, 1, 2, 3, 4, 6, 8, 10, 12,默认 2
|
|
26
26
|
*/
|
|
27
|
-
import {
|
|
27
|
+
import type { INavItem } from "../../index-astro";
|
|
28
28
|
import NavItems from "./NavItems.astro";
|
|
29
29
|
|
|
30
30
|
export interface Props {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
62
|
import "../../style.ts";
|
|
63
|
-
import {
|
|
63
|
+
import type { IMetaProps } from "../../src/common/meta";
|
|
64
64
|
import {
|
|
65
65
|
getBackgroundClass,
|
|
66
66
|
type BackgroundColor,
|
|
@@ -101,7 +101,7 @@ const {
|
|
|
101
101
|
|
|
102
102
|
// 处理类名
|
|
103
103
|
const backgroundClass = getBackgroundClass(background as BackgroundColor);
|
|
104
|
-
|
|
104
|
+
const bodyClasses = [backgroundClass].filter(Boolean).join(" ");
|
|
105
105
|
---
|
|
106
106
|
|
|
107
107
|
<BaseLayoutHtml
|
|
@@ -129,7 +129,7 @@ import DashboardSidebar from "./DashboardSidebar.astro";
|
|
|
129
129
|
import DashboardTopNavbar from "./DashboardTopNavbar.astro";
|
|
130
130
|
import { ToastContainer, ConfirmDialog } from "../../index-astro";
|
|
131
131
|
import "../../style.ts";
|
|
132
|
-
import {
|
|
132
|
+
import type { NavItem, SidebarSize, UserMenuItem } from "./types";
|
|
133
133
|
|
|
134
134
|
export interface Props {
|
|
135
135
|
/**
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { HTMLAttributes } from "astro/types";
|
|
2
2
|
|
|
3
|
-
// 定义链接尺寸类型
|
|
4
3
|
export type LinkSize = "sm" | "md" | "lg";
|
|
5
4
|
|
|
6
|
-
// 定义链接变体类型
|
|
7
5
|
export type LinkVariant =
|
|
8
6
|
| "default"
|
|
9
7
|
| "primary"
|
|
@@ -15,14 +13,12 @@ export type LinkVariant =
|
|
|
15
13
|
| "navigation"
|
|
16
14
|
| "github";
|
|
17
15
|
|
|
18
|
-
// 定义链接动画类型
|
|
19
16
|
export type LinkAnimation =
|
|
20
17
|
| "none"
|
|
21
18
|
| "hover-lift"
|
|
22
19
|
| "hover-glow"
|
|
23
20
|
| "hover-scale";
|
|
24
21
|
|
|
25
|
-
// 定义图标类型(排除需要特殊属性的组件)
|
|
26
22
|
export type LinkIconName =
|
|
27
23
|
| "AlertTriangle"
|
|
28
24
|
| "AppStoreIcon"
|
|
@@ -103,4 +99,6 @@ export interface LinkProps extends HTMLAttributes<"a"> {
|
|
|
103
99
|
active?: boolean;
|
|
104
100
|
navigationType?: "previous" | "next";
|
|
105
101
|
icon?: LinkIconName;
|
|
102
|
+
hoverImage?: string;
|
|
103
|
+
hoverImageAlt?: string;
|
|
106
104
|
}
|
|
@@ -1,152 +1,170 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import { AlertDialog, Container } from
|
|
4
|
-
import { ref } from
|
|
5
|
-
import type { BackgroundColor } from
|
|
6
|
-
import iphoneFrame from
|
|
7
|
-
import StatusBarContent from
|
|
2
|
+
import '../../style';
|
|
3
|
+
import { AlertDialog, Container } from '../../index-vue';
|
|
4
|
+
import { ref } from 'vue';
|
|
5
|
+
import type { BackgroundColor } from '../../src/common/backgrounds';
|
|
6
|
+
import iphoneFrame from './assets/iPhone 14 Pro - Deep Purple - Portrait.png';
|
|
7
|
+
import StatusBarContent from './StatusBarContent.vue';
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
9
|
+
/**
|
|
10
|
+
* @component ApplePhone
|
|
11
|
+
* @description ApplePhone 组件模拟 iPhone 设备的外观,包含状态栏、时间显示和设备边框。
|
|
12
|
+
* 适用于创建移动应用界面原型或展示移动端设计效果。
|
|
13
|
+
* @props
|
|
14
|
+
* @prop {'sm'|'md'|'lg'|'xl'|'2xl'|'3xl'|'4xl'|'5xl'} [height='lg'] - 窗口高度选项
|
|
15
|
+
* - sm: 256px (h-64)
|
|
16
|
+
* - md: 320px (h-80)
|
|
17
|
+
* - lg: 384px (h-96) - 默认值
|
|
18
|
+
* - xl: 480px
|
|
19
|
+
* - 2xl: 560px
|
|
20
|
+
* - 3xl: 640px
|
|
21
|
+
* - 4xl: 720px
|
|
22
|
+
* - 5xl: 800px
|
|
23
|
+
* @prop {String} [title=''] - 窗口标题
|
|
24
|
+
* @prop {Boolean} [withShadow=true] - 是否显示阴影效果
|
|
25
|
+
* @prop {Boolean} [showFrame=true] - 是否显示 iPhone 边框
|
|
26
|
+
* @prop {BackgroundColor} [backgroundColor=''] - 内容区域背景色,等同于为其内部的 Container 设置背景色
|
|
27
|
+
* @slots
|
|
28
|
+
* @slot default - 主要内容区域
|
|
29
|
+
* @emits
|
|
30
|
+
*/
|
|
31
31
|
|
|
32
|
-
// 类型定义
|
|
33
|
-
type HeightOption =
|
|
32
|
+
// 类型定义
|
|
33
|
+
type HeightOption = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl';
|
|
34
34
|
|
|
35
|
-
interface Props {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
35
|
+
interface Props {
|
|
36
|
+
height?: HeightOption;
|
|
37
|
+
title?: string;
|
|
38
|
+
withShadow?: boolean;
|
|
39
|
+
showFrame?: boolean;
|
|
40
|
+
backgroundColor?: BackgroundColor;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
// Props 定义
|
|
44
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
43
|
+
// Props 定义
|
|
44
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
45
|
+
height: 'lg',
|
|
46
|
+
title: '',
|
|
47
|
+
withShadow: true,
|
|
48
|
+
showFrame: true,
|
|
49
|
+
backgroundColor: undefined,
|
|
50
|
+
});
|
|
51
51
|
|
|
52
|
-
// iPhone边框图片-宽度
|
|
53
|
-
const iphoneFrameWidth = 1339;
|
|
54
|
-
// iPhone边框图片-高度
|
|
55
|
-
const iphoneFrameHeight = 2716;
|
|
56
|
-
// iPhone边框图片-状态栏离上边框的距离
|
|
57
|
-
const iphoneFrameStatusBarTop = 115;
|
|
58
|
-
// iPhone边框图片-状态栏高度
|
|
59
|
-
const iphoneFrameStatusBarHeight = 110;
|
|
52
|
+
// iPhone边框图片-宽度
|
|
53
|
+
const iphoneFrameWidth = 1339;
|
|
54
|
+
// iPhone边框图片-高度
|
|
55
|
+
const iphoneFrameHeight = 2716;
|
|
56
|
+
// iPhone边框图片-状态栏离上边框的距离
|
|
57
|
+
const iphoneFrameStatusBarTop = 115;
|
|
58
|
+
// iPhone边框图片-状态栏高度
|
|
59
|
+
const iphoneFrameStatusBarHeight = 110;
|
|
60
60
|
|
|
61
|
-
// 比例-总宽度
|
|
62
|
-
const mainContentWidthAspectRatio = 1179 / iphoneFrameWidth;
|
|
63
|
-
// 比例-总高度
|
|
64
|
-
const mainContentHeightAspectRatio = 2556 / iphoneFrameHeight;
|
|
65
|
-
// 比例-状态栏高度
|
|
66
|
-
const iphoneFrameStatusBarHeightAspectRatio =
|
|
67
|
-
|
|
68
|
-
// 比例-状态栏离上边框的距离
|
|
69
|
-
const iphoneFrameStatusBarTopAspectRatio =
|
|
70
|
-
|
|
61
|
+
// 比例-总宽度
|
|
62
|
+
const mainContentWidthAspectRatio = 1179 / iphoneFrameWidth;
|
|
63
|
+
// 比例-总高度
|
|
64
|
+
const mainContentHeightAspectRatio = 2556 / iphoneFrameHeight;
|
|
65
|
+
// 比例-状态栏高度
|
|
66
|
+
const iphoneFrameStatusBarHeightAspectRatio =
|
|
67
|
+
iphoneFrameStatusBarHeight / iphoneFrameHeight;
|
|
68
|
+
// 比例-状态栏离上边框的距离
|
|
69
|
+
const iphoneFrameStatusBarTopAspectRatio =
|
|
70
|
+
iphoneFrameStatusBarTop / iphoneFrameHeight;
|
|
71
71
|
|
|
72
|
-
// 预定义的高度选项
|
|
73
|
-
const heightClasses: Record<HeightOption, string> = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
};
|
|
72
|
+
// 预定义的高度选项
|
|
73
|
+
const heightClasses: Record<HeightOption, string> = {
|
|
74
|
+
sm: 'cosy:h-64', // 256px
|
|
75
|
+
md: 'cosy:h-80', // 320px
|
|
76
|
+
lg: 'cosy:h-96', // 384px
|
|
77
|
+
xl: 'cosy:h-[480px]', // 480px
|
|
78
|
+
'2xl': 'cosy:h-[560px]', // 560px
|
|
79
|
+
'3xl': 'cosy:h-[640px]', // 640px
|
|
80
|
+
'4xl': 'cosy:h-[720px]', // 720px
|
|
81
|
+
'5xl': 'cosy:h-[800px]', // 800px
|
|
82
|
+
};
|
|
83
83
|
|
|
84
|
-
// 响应式数据
|
|
85
|
-
const showAlertDialog = ref(false);
|
|
86
|
-
const alertMessage = ref(
|
|
84
|
+
// 响应式数据
|
|
85
|
+
const showAlertDialog = ref(false);
|
|
86
|
+
const alertMessage = ref('');
|
|
87
87
|
|
|
88
|
-
// 计算当前高度的缩放比例
|
|
89
|
-
const getScaleRatio = () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
};
|
|
88
|
+
// 计算当前高度的缩放比例
|
|
89
|
+
const getScaleRatio = () => {
|
|
90
|
+
const heightValues = {
|
|
91
|
+
sm: 256,
|
|
92
|
+
md: 320,
|
|
93
|
+
lg: 384,
|
|
94
|
+
xl: 480,
|
|
95
|
+
'2xl': 560,
|
|
96
|
+
'3xl': 640,
|
|
97
|
+
'4xl': 720,
|
|
98
|
+
'5xl': 800,
|
|
99
|
+
};
|
|
100
|
+
const currentHeight = heightValues[props.height];
|
|
101
|
+
// 基于特定高度计算缩放比例
|
|
102
|
+
return currentHeight / 500;
|
|
103
|
+
};
|
|
104
104
|
|
|
105
|
-
// 计算属性
|
|
106
|
-
const iphoneFrameSrc = (iphoneFrame as any).src || iphoneFrame;
|
|
105
|
+
// 计算属性
|
|
106
|
+
const iphoneFrameSrc = (iphoneFrame as any).src || iphoneFrame;
|
|
107
107
|
</script>
|
|
108
108
|
|
|
109
109
|
<template>
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
<div
|
|
111
|
+
:class="['cosy:relative not-prose cosy:mx-auto', heightClasses[height]]"
|
|
112
|
+
:style="{
|
|
113
|
+
aspectRatio: `${iphoneFrameWidth}/${iphoneFrameHeight}`,
|
|
114
|
+
}"
|
|
115
|
+
apple-phone>
|
|
116
|
+
<!-- iPhone 边框 -->
|
|
117
|
+
<img
|
|
118
|
+
v-if="showFrame"
|
|
119
|
+
style="
|
|
120
|
+
max-width: 100%;
|
|
121
|
+
max-height: 100%;
|
|
122
|
+
position: absolute;
|
|
123
|
+
top: 0;
|
|
124
|
+
left: 0;
|
|
125
|
+
z-index: 100;
|
|
126
|
+
"
|
|
127
|
+
:src="iphoneFrameSrc"
|
|
128
|
+
alt="iPhone frame" />
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
<!-- 顶部状态栏 -->
|
|
131
|
+
<div
|
|
132
|
+
:style="{
|
|
133
|
+
position: 'absolute',
|
|
134
|
+
top: iphoneFrameStatusBarTopAspectRatio * 100 + '%',
|
|
135
|
+
height: iphoneFrameStatusBarHeightAspectRatio * 100 + '%',
|
|
136
|
+
width: mainContentWidthAspectRatio * 100 + '%',
|
|
137
|
+
left: '50%',
|
|
138
|
+
transform: 'translate(-50%, 0)',
|
|
139
|
+
paddingLeft: '5%',
|
|
140
|
+
paddingRight: '5%',
|
|
141
|
+
zIndex: 50,
|
|
142
|
+
}">
|
|
143
|
+
<StatusBarContent :scaleRatio="getScaleRatio()" />
|
|
144
|
+
</div>
|
|
132
145
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
<!-- 内容区域 -->
|
|
147
|
+
<div
|
|
148
|
+
class="cosy:inset-0 cosy:h-full"
|
|
149
|
+
:style="{
|
|
150
|
+
width: mainContentWidthAspectRatio * 100 + '%',
|
|
151
|
+
height: mainContentHeightAspectRatio * 100 + '%',
|
|
152
|
+
// 水平居中
|
|
153
|
+
left: '50%',
|
|
154
|
+
// 垂直居中
|
|
155
|
+
top: '50%',
|
|
156
|
+
transform: 'translate(-50%, -50%)',
|
|
157
|
+
position: 'absolute',
|
|
158
|
+
zIndex: 20,
|
|
159
|
+
}">
|
|
160
|
+
<Container
|
|
161
|
+
rounded="lg"
|
|
162
|
+
style="height: 100%"
|
|
163
|
+
:background="backgroundColor || 'accent/90'">
|
|
164
|
+
<slot />
|
|
165
|
+
</Container>
|
|
149
166
|
</div>
|
|
167
|
+
</div>
|
|
150
168
|
|
|
151
|
-
|
|
169
|
+
<AlertDialog v-model="showAlertDialog" :message="alertMessage" />
|
|
152
170
|
</template>
|
|
@@ -18,6 +18,7 @@ import { getButtonCombinedClassesVue } from "./class";
|
|
|
18
18
|
* @props {string} [href] - 链接地址,设置后按钮变为链接形式
|
|
19
19
|
* @props {string} [target] - 链接目标,支持 _self、_blank、_parent、_top
|
|
20
20
|
* @props {Function} [onClick] - 点击事件处理函数
|
|
21
|
+
* @props {string|object} [class] - 自定义 CSS 类名,支持字符串或对象形式
|
|
21
22
|
*/
|
|
22
23
|
|
|
23
24
|
const props = withDefaults(defineProps<IButtonProps>(), {
|