@coffic/cosy-ui 0.8.24 → 0.8.25
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-astro/list/ListItem.astro +64 -38
- package/dist/src-astro/list/ListItemBreath.astro +60 -0
- package/dist/src-astro/list/ListItemGlow.astro +65 -0
- package/dist/src-astro/list/ListItemIconLeft.astro +53 -0
- package/dist/src-astro/list/ListItemIconRight.astro +53 -0
- package/dist/src-astro/list/ListItemPulse.astro +61 -0
- package/dist/src-astro/list/ListItemRing.astro +59 -0
- package/dist/src-astro/list/index.ts +7 -1
- package/dist/src-vue/alert/Alert.vue +1 -1
- package/dist/src-vue/alert-dialog/Multilang.vue +1 -1
- package/dist/src-vue/buttons/Button.vue +20 -14
- package/dist/src-vue/container/Container.vue +1 -1
- package/dist/src-vue/iPhone/StatusBarContent.vue +88 -76
- package/dist/src-vue/iPhone/iPhoneWindow.vue +149 -129
- package/dist/src-vue/list/ListItem.vue +77 -32
- package/dist/src-vue/list/ListItemBreath.vue +70 -0
- package/dist/src-vue/list/ListItemGlow.vue +75 -0
- package/dist/src-vue/list/ListItemIconLeft.vue +63 -0
- package/dist/src-vue/list/ListItemIconRight.vue +63 -0
- package/dist/src-vue/list/ListItemPulse.vue +71 -0
- package/dist/src-vue/list/ListItemRing.vue +71 -0
- package/dist/src-vue/mac-window/MacWindow.vue +160 -139
- package/package.json +1 -1
@@ -0,0 +1,75 @@
|
|
1
|
+
<template>
|
2
|
+
<li
|
3
|
+
:class="[
|
4
|
+
'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
|
5
|
+
loading && !duration ? 'glow-anim' : '',
|
6
|
+
]"
|
7
|
+
@click="$emit('click')"
|
8
|
+
>
|
9
|
+
<div v-if="loading">
|
10
|
+
<template v-if="duration">
|
11
|
+
<div
|
12
|
+
class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
|
13
|
+
:style="{ animationDuration: duration + 'ms' }"
|
14
|
+
></div>
|
15
|
+
</template>
|
16
|
+
</div>
|
17
|
+
<div
|
18
|
+
class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3"
|
19
|
+
>
|
20
|
+
<slot />
|
21
|
+
</div>
|
22
|
+
</li>
|
23
|
+
</template>
|
24
|
+
|
25
|
+
<script setup lang="ts">
|
26
|
+
withDefaults(
|
27
|
+
defineProps<{
|
28
|
+
loading?: boolean;
|
29
|
+
duration?: number;
|
30
|
+
}>(),
|
31
|
+
{
|
32
|
+
loading: false,
|
33
|
+
duration: undefined,
|
34
|
+
}
|
35
|
+
);
|
36
|
+
|
37
|
+
defineEmits(['click']);
|
38
|
+
</script>
|
39
|
+
|
40
|
+
<style scoped>
|
41
|
+
/* 发光边框动画 */
|
42
|
+
@keyframes glow {
|
43
|
+
0%,
|
44
|
+
100% {
|
45
|
+
border: 1px solid rgb(139 92 246 / 0.3);
|
46
|
+
box-shadow: 0 0 5px rgb(139 92 246 / 0.3);
|
47
|
+
}
|
48
|
+
50% {
|
49
|
+
border: 1px solid rgb(139 92 246 / 0.8);
|
50
|
+
box-shadow:
|
51
|
+
0 0 20px rgb(139 92 246 / 0.6),
|
52
|
+
0 0 30px rgb(139 92 246 / 0.4),
|
53
|
+
inset 0 0 10px rgb(139 92 246 / 0.2);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
.glow-anim {
|
57
|
+
animation: glow 2s ease-in-out infinite;
|
58
|
+
border: 1px solid rgb(139 92 246 / 0.3); /* 确保有初始边框 */
|
59
|
+
}
|
60
|
+
|
61
|
+
/* 进度条动画 */
|
62
|
+
.loading-bar {
|
63
|
+
width: 0%;
|
64
|
+
height: 100%;
|
65
|
+
animation: loading-bar-anim linear forwards;
|
66
|
+
}
|
67
|
+
@keyframes loading-bar-anim {
|
68
|
+
0% {
|
69
|
+
width: 0%;
|
70
|
+
}
|
71
|
+
100% {
|
72
|
+
width: 100%;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
</style>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<template>
|
2
|
+
<li
|
3
|
+
class="cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden"
|
4
|
+
@click="$emit('click')"
|
5
|
+
>
|
6
|
+
<div v-if="loading">
|
7
|
+
<template v-if="duration">
|
8
|
+
<div
|
9
|
+
class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
|
10
|
+
:style="{ animationDuration: duration + 'ms' }"
|
11
|
+
></div>
|
12
|
+
</template>
|
13
|
+
</div>
|
14
|
+
<div
|
15
|
+
class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3"
|
16
|
+
>
|
17
|
+
<!-- 前置 loading 图标 -->
|
18
|
+
<div
|
19
|
+
v-if="loading && !duration"
|
20
|
+
class="cosy:flex-shrink-0 cosy:transform-none"
|
21
|
+
style="transform: none !important"
|
22
|
+
>
|
23
|
+
<div
|
24
|
+
class="cosy:loading cosy:loading-spinner cosy:loading-sm cosy:text-accent"
|
25
|
+
></div>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<slot />
|
29
|
+
</div>
|
30
|
+
</li>
|
31
|
+
</template>
|
32
|
+
|
33
|
+
<script setup lang="ts">
|
34
|
+
withDefaults(
|
35
|
+
defineProps<{
|
36
|
+
loading?: boolean;
|
37
|
+
duration?: number;
|
38
|
+
}>(),
|
39
|
+
{
|
40
|
+
loading: false,
|
41
|
+
duration: undefined,
|
42
|
+
}
|
43
|
+
);
|
44
|
+
|
45
|
+
defineEmits(['click']);
|
46
|
+
</script>
|
47
|
+
|
48
|
+
<style scoped>
|
49
|
+
/* 进度条动画 */
|
50
|
+
.loading-bar {
|
51
|
+
width: 0%;
|
52
|
+
height: 100%;
|
53
|
+
animation: loading-bar-anim linear forwards;
|
54
|
+
}
|
55
|
+
@keyframes loading-bar-anim {
|
56
|
+
0% {
|
57
|
+
width: 0%;
|
58
|
+
}
|
59
|
+
100% {
|
60
|
+
width: 100%;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
</style>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<template>
|
2
|
+
<li
|
3
|
+
class="cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden"
|
4
|
+
@click="$emit('click')"
|
5
|
+
>
|
6
|
+
<div v-if="loading">
|
7
|
+
<template v-if="duration">
|
8
|
+
<div
|
9
|
+
class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
|
10
|
+
:style="{ animationDuration: duration + 'ms' }"
|
11
|
+
></div>
|
12
|
+
</template>
|
13
|
+
</div>
|
14
|
+
<div
|
15
|
+
class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3"
|
16
|
+
>
|
17
|
+
<slot />
|
18
|
+
|
19
|
+
<!-- 后置 loading 图标 -->
|
20
|
+
<div
|
21
|
+
v-if="loading && !duration"
|
22
|
+
class="cosy:flex-shrink-0 cosy:ml-auto cosy:transform-none"
|
23
|
+
style="transform: none !important"
|
24
|
+
>
|
25
|
+
<div
|
26
|
+
class="cosy:loading cosy:loading-dots cosy:loading-sm cosy:text-accent"
|
27
|
+
></div>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</li>
|
31
|
+
</template>
|
32
|
+
|
33
|
+
<script setup lang="ts">
|
34
|
+
withDefaults(
|
35
|
+
defineProps<{
|
36
|
+
loading?: boolean;
|
37
|
+
duration?: number;
|
38
|
+
}>(),
|
39
|
+
{
|
40
|
+
loading: false,
|
41
|
+
duration: undefined,
|
42
|
+
}
|
43
|
+
);
|
44
|
+
|
45
|
+
defineEmits(['click']);
|
46
|
+
</script>
|
47
|
+
|
48
|
+
<style scoped>
|
49
|
+
/* 进度条动画 */
|
50
|
+
.loading-bar {
|
51
|
+
width: 0%;
|
52
|
+
height: 100%;
|
53
|
+
animation: loading-bar-anim linear forwards;
|
54
|
+
}
|
55
|
+
@keyframes loading-bar-anim {
|
56
|
+
0% {
|
57
|
+
width: 0%;
|
58
|
+
}
|
59
|
+
100% {
|
60
|
+
width: 100%;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
</style>
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<template>
|
2
|
+
<li
|
3
|
+
:class="[
|
4
|
+
'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
|
5
|
+
loading && !duration ? 'pulse-anim' : '',
|
6
|
+
]"
|
7
|
+
@click="$emit('click')"
|
8
|
+
>
|
9
|
+
<div v-if="loading">
|
10
|
+
<template v-if="duration">
|
11
|
+
<div
|
12
|
+
class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
|
13
|
+
:style="{ animationDuration: duration + 'ms' }"
|
14
|
+
></div>
|
15
|
+
</template>
|
16
|
+
</div>
|
17
|
+
<div
|
18
|
+
class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3"
|
19
|
+
>
|
20
|
+
<slot />
|
21
|
+
</div>
|
22
|
+
</li>
|
23
|
+
</template>
|
24
|
+
|
25
|
+
<script setup lang="ts">
|
26
|
+
withDefaults(
|
27
|
+
defineProps<{
|
28
|
+
loading?: boolean;
|
29
|
+
duration?: number;
|
30
|
+
}>(),
|
31
|
+
{
|
32
|
+
loading: false,
|
33
|
+
duration: undefined,
|
34
|
+
}
|
35
|
+
);
|
36
|
+
|
37
|
+
defineEmits(['click']);
|
38
|
+
</script>
|
39
|
+
|
40
|
+
<style scoped>
|
41
|
+
/* 整体脉冲动画 */
|
42
|
+
@keyframes pulse-scale {
|
43
|
+
0%,
|
44
|
+
100% {
|
45
|
+
transform: scale(1);
|
46
|
+
opacity: 1;
|
47
|
+
}
|
48
|
+
50% {
|
49
|
+
transform: scale(1.01);
|
50
|
+
opacity: 0.9;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
.pulse-anim {
|
54
|
+
animation: pulse-scale 1.5s ease-in-out infinite;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* 进度条动画 */
|
58
|
+
.loading-bar {
|
59
|
+
width: 0%;
|
60
|
+
height: 100%;
|
61
|
+
animation: loading-bar-anim linear forwards;
|
62
|
+
}
|
63
|
+
@keyframes loading-bar-anim {
|
64
|
+
0% {
|
65
|
+
width: 0%;
|
66
|
+
}
|
67
|
+
100% {
|
68
|
+
width: 100%;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
</style>
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<template>
|
2
|
+
<li
|
3
|
+
:class="[
|
4
|
+
'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
|
5
|
+
loading && !duration
|
6
|
+
? 'cosy:ring-2 cosy:ring-accent ring-pulse-anim'
|
7
|
+
: '',
|
8
|
+
]"
|
9
|
+
@click="$emit('click')"
|
10
|
+
>
|
11
|
+
<div v-if="loading">
|
12
|
+
<template v-if="duration">
|
13
|
+
<div
|
14
|
+
class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
|
15
|
+
:style="{ animationDuration: duration + 'ms' }"
|
16
|
+
></div>
|
17
|
+
</template>
|
18
|
+
</div>
|
19
|
+
<div
|
20
|
+
class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3"
|
21
|
+
>
|
22
|
+
<slot />
|
23
|
+
</div>
|
24
|
+
</li>
|
25
|
+
</template>
|
26
|
+
|
27
|
+
<script setup lang="ts">
|
28
|
+
withDefaults(
|
29
|
+
defineProps<{
|
30
|
+
loading?: boolean;
|
31
|
+
duration?: number;
|
32
|
+
}>(),
|
33
|
+
{
|
34
|
+
loading: false,
|
35
|
+
duration: undefined,
|
36
|
+
}
|
37
|
+
);
|
38
|
+
|
39
|
+
defineEmits(['click']);
|
40
|
+
</script>
|
41
|
+
|
42
|
+
<style scoped>
|
43
|
+
/* Ring 外环脉冲动画 */
|
44
|
+
@keyframes ring-pulse {
|
45
|
+
0%,
|
46
|
+
100% {
|
47
|
+
transform: scale(1);
|
48
|
+
}
|
49
|
+
50% {
|
50
|
+
transform: scale(1.02);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
.ring-pulse-anim {
|
54
|
+
animation: ring-pulse 1.5s ease-in-out infinite;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* 进度条动画 */
|
58
|
+
.loading-bar {
|
59
|
+
width: 0%;
|
60
|
+
height: 100%;
|
61
|
+
animation: loading-bar-anim linear forwards;
|
62
|
+
}
|
63
|
+
@keyframes loading-bar-anim {
|
64
|
+
0% {
|
65
|
+
width: 0%;
|
66
|
+
}
|
67
|
+
100% {
|
68
|
+
width: 100%;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
</style>
|
@@ -95,168 +95,189 @@ const activeTab = ref('外观');
|
|
95
95
|
-->
|
96
96
|
|
97
97
|
<script lang="ts">
|
98
|
-
import '../../style
|
98
|
+
import '../../style';
|
99
99
|
import AlertDialog from '../alert-dialog/AlertDialog.vue';
|
100
100
|
import { ref, defineComponent, type PropType } from 'vue';
|
101
101
|
|
102
102
|
export default defineComponent({
|
103
|
-
|
104
|
-
|
105
|
-
|
103
|
+
name: 'MacWindow',
|
104
|
+
components: {
|
105
|
+
AlertDialog,
|
106
|
+
},
|
107
|
+
props: {
|
108
|
+
height: {
|
109
|
+
type: String,
|
110
|
+
default: 'h-96',
|
106
111
|
},
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
default: 'h-96',
|
111
|
-
},
|
112
|
-
title: {
|
113
|
-
type: String,
|
114
|
-
default: '',
|
115
|
-
},
|
116
|
-
withShadow: {
|
117
|
-
type: Boolean,
|
118
|
-
default: true,
|
119
|
-
},
|
120
|
-
tabs: {
|
121
|
-
type: Array as PropType<string[]>,
|
122
|
-
default: () => [],
|
123
|
-
},
|
124
|
-
defaultTab: {
|
125
|
-
type: String,
|
126
|
-
default: '',
|
127
|
-
},
|
128
|
-
onCloseWindow: {
|
129
|
-
type: Function,
|
130
|
-
default: null,
|
131
|
-
},
|
132
|
-
onMinimizeWindow: {
|
133
|
-
type: Function,
|
134
|
-
default: null,
|
135
|
-
},
|
136
|
-
onMaximizeWindow: {
|
137
|
-
type: Function,
|
138
|
-
default: null,
|
139
|
-
},
|
140
|
-
onTabClick: {
|
141
|
-
type: Function,
|
142
|
-
default: null,
|
143
|
-
},
|
112
|
+
title: {
|
113
|
+
type: String,
|
114
|
+
default: '',
|
144
115
|
},
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
116
|
+
withShadow: {
|
117
|
+
type: Boolean,
|
118
|
+
default: true,
|
119
|
+
},
|
120
|
+
tabs: {
|
121
|
+
type: Array as PropType<string[]>,
|
122
|
+
default: () => [],
|
123
|
+
},
|
124
|
+
defaultTab: {
|
125
|
+
type: String,
|
126
|
+
default: '',
|
127
|
+
},
|
128
|
+
onCloseWindow: {
|
129
|
+
type: Function,
|
130
|
+
default: null,
|
131
|
+
},
|
132
|
+
onMinimizeWindow: {
|
133
|
+
type: Function,
|
134
|
+
default: null,
|
135
|
+
},
|
136
|
+
onMaximizeWindow: {
|
137
|
+
type: Function,
|
138
|
+
default: null,
|
139
|
+
},
|
140
|
+
onTabClick: {
|
141
|
+
type: Function,
|
142
|
+
default: null,
|
143
|
+
},
|
144
|
+
},
|
145
|
+
setup(props) {
|
146
|
+
const showAlertDialog = ref(false);
|
147
|
+
const alertMessage = ref('');
|
148
|
+
const activeTab = ref(props.defaultTab);
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
// 如果没有设置默认标签或默认标签不在tabs中,则选择第一个标签
|
151
|
+
if (
|
152
|
+
(!activeTab.value || !props.tabs.includes(activeTab.value)) &&
|
153
|
+
props.tabs.length > 0
|
154
|
+
) {
|
155
|
+
activeTab.value = props.tabs[0] as string;
|
156
|
+
}
|
157
157
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
158
|
+
const handleCloseWindow = () => {
|
159
|
+
alertMessage.value = '关闭APP窗口(这是演示,不会真实操作)';
|
160
|
+
showAlertDialog.value = true;
|
161
|
+
if (props.onCloseWindow) {
|
162
|
+
props.onCloseWindow();
|
163
|
+
}
|
164
|
+
};
|
165
165
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
166
|
+
const handleMinimizeWindow = () => {
|
167
|
+
alertMessage.value = '最小化窗口(这是演示,不会真实操作)';
|
168
|
+
showAlertDialog.value = true;
|
169
|
+
if (props.onMinimizeWindow) {
|
170
|
+
props.onMinimizeWindow();
|
171
|
+
}
|
172
|
+
};
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
174
|
+
const handleMaximizeWindow = () => {
|
175
|
+
alertMessage.value = '最大化窗口(这是演示,不会真实操作)';
|
176
|
+
showAlertDialog.value = true;
|
177
|
+
if (props.onMaximizeWindow) {
|
178
|
+
props.onMaximizeWindow();
|
179
|
+
}
|
180
|
+
};
|
181
181
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
182
|
+
const handleTabClick = (tab: string) => {
|
183
|
+
activeTab.value = tab;
|
184
|
+
if (props.onTabClick) {
|
185
|
+
props.onTabClick(tab);
|
186
|
+
}
|
187
|
+
};
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
189
|
+
return {
|
190
|
+
showAlertDialog,
|
191
|
+
alertMessage,
|
192
|
+
activeTab,
|
193
|
+
handleCloseWindow,
|
194
|
+
handleMinimizeWindow,
|
195
|
+
handleMaximizeWindow,
|
196
|
+
handleTabClick,
|
197
|
+
};
|
198
|
+
},
|
199
199
|
});
|
200
200
|
</script>
|
201
201
|
|
202
202
|
<template>
|
203
|
-
|
204
|
-
|
205
|
-
|
203
|
+
<div
|
204
|
+
class="cosy:flex cosy:max-w-5xl cosy:mx-auto cosy:bg-base-100 cosy:relative cosy:rounded-2xl cosy:overflow-hidden"
|
205
|
+
:class="[height, withShadow ? 'cosy:shadow-lg' : '']"
|
206
|
+
>
|
207
|
+
<!-- 窗口控制按钮 -->
|
208
|
+
<div
|
209
|
+
class="cosy:absolute cosy:top-0 cosy:left-0 cosy:right-0 cosy:flex cosy:items-center cosy:h-12 cosy:px-4 cosy:bg-base-200 cosy:border-b cosy:border-base-300"
|
210
|
+
>
|
211
|
+
<div class="cosy:flex cosy:items-center cosy:space-x-2">
|
206
212
|
<div
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
'cosy:px-3 cosy:py-1 cosy:text-sm cosy:rounded-md cosy:transition-colors',
|
225
|
-
activeTab === tab
|
226
|
-
? 'cosy:bg-base-100 cosy:text-base-content cosy:shadow'
|
227
|
-
: 'cosy:text-base-content/70 hover:cosy:text-base-content',
|
228
|
-
]" @click="handleTabClick(tab)">
|
229
|
-
{{ tab }}
|
230
|
-
</button>
|
231
|
-
</div>
|
232
|
-
</div>
|
213
|
+
class="cosy:w-3 cosy:h-3 cosy:rounded-full cosy:bg-error cosy:cursor-pointer hover:cosy:opacity-80 cosy:transition-opacity"
|
214
|
+
@click="handleCloseWindow"
|
215
|
+
/>
|
216
|
+
<div
|
217
|
+
class="cosy:w-3 cosy:h-3 cosy:rounded-full cosy:bg-warning cosy:cursor-pointer hover:cosy:opacity-80 cosy:transition-opacity"
|
218
|
+
@click="handleMinimizeWindow"
|
219
|
+
/>
|
220
|
+
<div
|
221
|
+
class="cosy:w-3 cosy:h-3 cosy:rounded-full cosy:bg-success cosy:cursor-pointer hover:cosy:opacity-80 cosy:transition-opacity"
|
222
|
+
@click="handleMaximizeWindow"
|
223
|
+
/>
|
224
|
+
</div>
|
225
|
+
<div
|
226
|
+
class="cosy:ml-6 cosy:text-sm cosy:font-medium cosy:text-base-content"
|
227
|
+
>
|
228
|
+
{{ title }}
|
229
|
+
</div>
|
233
230
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
231
|
+
<!-- 标签选择器 -->
|
232
|
+
<div
|
233
|
+
v-if="tabs?.length"
|
234
|
+
class="cosy:flex-1 cosy:flex cosy:justify-center"
|
235
|
+
>
|
236
|
+
<div class="cosy:inline-flex cosy:rounded-lg cosy:bg-base-300 cosy:p-1">
|
237
|
+
<button
|
238
|
+
v-for="(tab, index) in tabs"
|
239
|
+
:key="index"
|
240
|
+
:class="[
|
241
|
+
'cosy:px-3 cosy:py-1 cosy:text-sm cosy:rounded-md cosy:transition-colors',
|
242
|
+
activeTab === tab
|
243
|
+
? 'cosy:bg-base-100 cosy:text-base-content cosy:shadow'
|
244
|
+
: 'cosy:text-base-content/70 hover:cosy:text-base-content',
|
245
|
+
]"
|
246
|
+
@click="handleTabClick(tab)"
|
247
|
+
>
|
248
|
+
{{ tab }}
|
249
|
+
</button>
|
238
250
|
</div>
|
251
|
+
</div>
|
252
|
+
|
253
|
+
<!-- 工具栏插槽 -->
|
254
|
+
<div class="cosy:ml-auto cosy:flex cosy:items-center cosy:space-x-2">
|
255
|
+
<slot name="toolbar"></slot>
|
256
|
+
</div>
|
257
|
+
</div>
|
239
258
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
259
|
+
<!-- 主要内容区域 -->
|
260
|
+
<div class="cosy:flex-1 cosy:flex cosy:flex-col cosy:pt-12 cosy:h-full">
|
261
|
+
<div class="cosy:flex cosy:flex-1 cosy:h-full cosy:overflow-hidden">
|
262
|
+
<!-- 左侧栏插槽 -->
|
263
|
+
<slot name="sidebar" />
|
245
264
|
|
246
|
-
|
247
|
-
|
248
|
-
|
265
|
+
<!-- 主内容插槽 -->
|
266
|
+
<slot />
|
267
|
+
</div>
|
249
268
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
269
|
+
<!-- 底部状态栏 -->
|
270
|
+
<div
|
271
|
+
v-if="$slots.status"
|
272
|
+
class="cosy:h-6 cosy:bg-base-200/95 cosy:border-t cosy:border-base-300 cosy:flex cosy:items-center cosy:justify-end cosy:px-4 cosy:text-sm"
|
273
|
+
>
|
274
|
+
<div class="cosy:flex cosy:items-center cosy:space-x-2">
|
275
|
+
<slot name="status"></slot>
|
257
276
|
</div>
|
277
|
+
</div>
|
258
278
|
</div>
|
279
|
+
</div>
|
259
280
|
|
260
|
-
|
261
|
-
|
281
|
+
<!-- AlertDialog 组件 -->
|
282
|
+
<AlertDialog v-model="showAlertDialog" :message="alertMessage" />
|
262
283
|
</template>
|