Skip to content

Commit 0fafff2

Browse files
committed
chore(components): add BoxCube component and fix errors in Box and Links components
1 parent 294921c commit 0fafff2

File tree

5 files changed

+255
-112
lines changed

5 files changed

+255
-112
lines changed

.vitepress/theme/components/Box.vue

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
<template>
22
<div class="box-container">
3-
<a v-for="(item, index) in items" :key="index" :href="item.l" class="box" target="_blank">
3+
<a
4+
v-for="(item, index) in items"
5+
:key="index"
6+
:href="item.link"
7+
:name="item.name"
8+
:title="item.name"
9+
class="box"
10+
target="_blank"
11+
>
412
<div class="box-content">
5-
<span v-if="item.ct" class="ct">{{ item.ct }}</span>
6-
<span v-if="isImage(item.i)" class="icon-container">
7-
<img :src="item.i" alt="icon" class="i" />
13+
<span v-if="item.tag" class="tag">{{ item.tag }}</span>
14+
<span v-if="isImage(item.icon)" class="icon-container">
15+
<img :src="item.icon" alt="icon" class="icon-container" />
816
</span>
9-
<span v-else class="icon-container">
10-
<i :class="item.i + ' fa-2xl'" :style="{ color: item.color }"></i>
17+
<span v-else class="icon">
18+
<i :class="item.icon + ' fa-2xl'" :style="{ color: item.color }"></i>
1119
</span>
12-
<img v-if="item.light" :src="item.light" alt="icon" class="i light-only" />
13-
<img v-if="item.dark" :src="item.dark" alt="icon" class="i dark-only" />
14-
<p class="t">{{ item.t }}</p>
20+
<img v-if="item.light" :src="item.light" alt="icon" class="icon-container light-only" />
21+
<img v-if="item.dark" :src="item.dark" alt="icon" class="icon-container dark-only" />
22+
<p class="name">{{ item.name }}</p>
1523
</div>
1624
</a>
1725
</div>
@@ -25,13 +33,12 @@ export default {
2533
type: Array,
2634
required: true,
2735
validator: (items) => {
28-
// 验证每个项是否有必须的属性
2936
return items.every(
3037
(item) =>
31-
item.hasOwnProperty('l') &&
32-
item.hasOwnProperty('i') &&
33-
item.hasOwnProperty('t') &&
34-
item.hasOwnProperty('ct') &&
38+
item.hasOwnProperty('link') &&
39+
item.hasOwnProperty('icon') &&
40+
item.hasOwnProperty('name') &&
41+
(item.hasOwnProperty('tag') || true) &&
3542
(item.hasOwnProperty('light') || item.hasOwnProperty('dark'))
3643
)
3744
}
@@ -65,16 +72,16 @@ export default {
6572
position: relative;
6673
border: 1px solid var(--vp-c-bg-soft);
6774
background-color: var(--vp-c-bg-alt);
68-
padding: 12px 24px;
69-
border-radius: 8px;
70-
height: 60px;
71-
width: 210px;
75+
padding: 0.8rem 1.6rem;
76+
border-radius: 0.8rem;
77+
width: 12.25rem;
78+
height: 3.5rem;
7279
display: flex;
80+
text-decoration: none !important;
7381
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
7482
7583
&:hover {
7684
border-color: var(--vp-c-brand-1);
77-
// background-color: var(--vp-c-brand-soft);
7885
}
7986
8087
@media (max-width: 1024px) {
@@ -89,7 +96,7 @@ export default {
8996
}
9097
9198
.box-content {
92-
font-size: 14px;
99+
font-size: 0.9rem;
93100
line-height: 1;
94101
letter-spacing: -0.02em;
95102
display: flex;
@@ -99,38 +106,37 @@ export default {
99106
white-space: nowrap;
100107
}
101108
102-
.ct {
109+
.tag {
103110
position: absolute;
104111
top: 0;
105112
right: 0;
106113
background-color: var(--vp-c-brand-3);
107114
color: var(--vp-c-brand-text);
108-
font-size: 10px;
109-
padding: 4px 8px;
110-
border-top-right-radius: 8px;
111-
border-bottom-left-radius: 4px;
115+
font-size: 0.5rem;
116+
padding: 0.25rem 0.5rem;
117+
border-top-right-radius: 0.7rem;
118+
border-bottom-left-radius: 0.7rem;
112119
z-index: 1;
113120
}
114-
115-
.i {
116-
margin-right: 8px;
121+
.icon-container {
117122
height: 2em;
118-
width: auto;
119123
display: flex;
120124
justify-content: center;
121125
align-items: center;
122-
border-radius: 6px;
123126
}
124127
125-
.icon-container {
126-
// display: flex;
127-
// justify-content: center;
128-
// align-items: center;
129-
margin-right: 8px;
128+
.icon {
129+
display: inline-block;
130+
height: 2em;
131+
justify-content: center;
132+
align-items: center;
133+
margin-top: 1rem;
134+
color: var(--vp-c-text-1);
130135
}
131136
132-
.t {
133-
font-size: 14px;
137+
.name {
138+
margin-left: 1rem;
139+
font-size: 0.8rem;
134140
line-height: 1;
135141
letter-spacing: -0.02em;
136142
display: flex;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<template>
2+
<div class="container">
3+
<a
4+
v-for="(item, index) in items"
5+
:key="item.name + index"
6+
class="link"
7+
:href="item.link"
8+
:name="item.name"
9+
:title="item.name"
10+
target="_blank"
11+
>
12+
<span v-if="isImage(item.icon)">
13+
<img :src="item.icon" alt="icon" class="img" />
14+
</span>
15+
<span v-else class="icon">
16+
<i :class="item.icon + ' fa-2xl'" :style="{ color: item.color }"></i>
17+
</span>
18+
<img v-if="item.light" :src="item.light" alt="icon" class="img light-only" />
19+
<img v-if="item.dark" :src="item.dark" alt="icon" class="img dark-only" />
20+
<span class="name">{{ item.name }}</span>
21+
<span class="secondary">{{ item.secondary }}</span>
22+
</a>
23+
</div>
24+
</template>
25+
26+
<script>
27+
export default {
28+
name: 'BoxCube',
29+
props: {
30+
items: {
31+
type: Array,
32+
required: true,
33+
validator: (items) => {
34+
// 验证每个项是否有必须的属性
35+
return items.every(
36+
(item) =>
37+
item.hasOwnProperty('icon') &&
38+
item.hasOwnProperty('name') &&
39+
item.hasOwnProperty('link') &&
40+
item.hasOwnProperty('target') &&
41+
item.hasOwnProperty('secondary') &&
42+
item.hasOwnProperty('color') &&
43+
(item.hasOwnProperty('light') || item.hasOwnProperty('dark'))
44+
)
45+
}
46+
}
47+
},
48+
methods: {
49+
isImage(url) {
50+
return typeof url === 'string' && /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/.test(url)
51+
}
52+
}
53+
}
54+
</script>
55+
56+
<style lang="scss" scoped>
57+
:root:not(.dark) .dark-only {
58+
display: none;
59+
}
60+
61+
:root:is(.dark) .light-only {
62+
display: none;
63+
}
64+
65+
.container {
66+
display: flex;
67+
flex-wrap: wrap;
68+
gap: 20px;
69+
}
70+
71+
.link {
72+
margin-top: 1rem;
73+
width: 7.5rem;
74+
height: 7.5rem;
75+
// color: inherit;
76+
// text-decoration: none;
77+
border: 1px solid var(--vp-c-bg-soft);
78+
background-color: var(--vp-c-bg-alt);
79+
border-radius: 0.8rem;
80+
display: flex;
81+
align-items: center;
82+
justify-content: center;
83+
position: relative;
84+
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
85+
86+
&:hover {
87+
border-color: var(--vp-c-brand-1);
88+
// .icon,
89+
.name {
90+
color: var(--vp-c-brand-1);
91+
}
92+
}
93+
}
94+
95+
.icon {
96+
margin-top: -1rem;
97+
color: var(--vp-c-text-1);
98+
}
99+
100+
.img {
101+
width: 2rem;
102+
margin-top: -1rem;
103+
}
104+
105+
.name {
106+
position: absolute;
107+
font-size: 0.8rem;
108+
bottom: 1.25rem;
109+
color: var(--vp-c-text-1);
110+
}
111+
112+
.secondary {
113+
position: absolute;
114+
font-size: 0.75rem;
115+
bottom: 0.15rem;
116+
color: var(--vp-c-text-3);
117+
}
118+
</style>

0 commit comments

Comments
 (0)