Skip to content

Commit 75eb1de

Browse files
committed
feat: add quote plugin and miragetank plugin to documentation
1 parent 34f0203 commit 75eb1de

30 files changed

+1025
-239
lines changed
56.1 KB
Loading
69.4 KB
Loading
201 KB
Loading

src/.vuepress/client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import QQChat from "./components/QQChat.vue";
33
import QQMessage from "./components/QQMessage.vue";
44
import QQVoice from "./components/QQVoice.vue";
55
import QQImage from "./components/QQImage.vue";
6+
import TimelineGallery from "./components/TimelineGallery.vue";
67

78
export default defineClientConfig({
89
enhance: ({ app }) => {
910
app.component("QQChat", QQChat);
1011
app.component("QQMessage", QQMessage);
1112
app.component("QQVoice", QQVoice);
1213
app.component("QQImage", QQImage);
14+
app.component("TimelineGallery", TimelineGallery);
1315
},
1416
});
1517

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
<template>
2+
<div class="timeline-item">
3+
<div class="timeline-marker">
4+
<div class="timeline-dot"></div>
5+
</div>
6+
<div class="timeline-content">
7+
<div class="timeline-date">{{ date }}</div>
8+
<div class="timeline-images" @mouseover="handleImageHover">
9+
<slot></slot>
10+
</div>
11+
</div>
12+
</div>
13+
</template>
14+
15+
<script>
16+
export default {
17+
mounted() {
18+
// 为所有图片添加描述浮层包装
19+
const images = this.$el.querySelectorAll('.timeline-images img');
20+
images.forEach(img => {
21+
if (!img.parentElement.classList.contains('img-wrapper')) {
22+
const wrapper = document.createElement('div');
23+
wrapper.className = 'img-wrapper';
24+
img.parentNode.insertBefore(wrapper, img);
25+
wrapper.appendChild(img);
26+
27+
const overlay = document.createElement('div');
28+
overlay.className = 'img-overlay';
29+
overlay.textContent = img.alt || '';
30+
wrapper.appendChild(overlay);
31+
}
32+
});
33+
},
34+
methods: {
35+
handleImageHover() {
36+
// 可以添加额外的交互逻辑
37+
}
38+
}
39+
}
40+
</script>
41+
42+
<script setup>
43+
defineProps({
44+
date: {
45+
type: String,
46+
required: true
47+
}
48+
})
49+
</script>
50+
51+
<style scoped>
52+
.timeline-item {
53+
display: flex;
54+
margin-bottom: 40px;
55+
position: relative;
56+
}
57+
58+
.timeline-marker {
59+
position: relative;
60+
margin-right: 30px;
61+
display: flex;
62+
flex-direction: column;
63+
align-items: center;
64+
}
65+
66+
.timeline-dot {
67+
width: 16px;
68+
height: 16px;
69+
background: linear-gradient(135deg, #f9bdeb 0%, #c5d8f8 100%);
70+
border-radius: 50%;
71+
box-shadow: 0 0 0 4px rgba(249, 189, 235, 0.2);
72+
position: relative;
73+
z-index: 2;
74+
transition: all 0.3s ease;
75+
animation: pulse 2s ease-in-out infinite;
76+
}
77+
78+
.timeline-dot::before {
79+
content: '';
80+
position: absolute;
81+
top: 16px;
82+
left: 50%;
83+
transform: translateX(-50%);
84+
width: 2px;
85+
height: 100px;
86+
background: linear-gradient(180deg,
87+
rgba(249, 189, 235, 0.3) 0%,
88+
rgba(197, 216, 248, 0.3) 50%,
89+
rgba(232, 213, 248, 0.3) 100%
90+
);
91+
z-index: -1;
92+
}
93+
94+
.timeline-item:hover .timeline-dot {
95+
transform: scale(1.3);
96+
box-shadow: 0 0 0 8px rgba(249, 189, 235, 0.4);
97+
animation: none;
98+
}
99+
100+
@keyframes pulse {
101+
0%, 100% {
102+
box-shadow: 0 0 0 4px rgba(249, 189, 235, 0.2);
103+
}
104+
50% {
105+
box-shadow: 0 0 0 8px rgba(249, 189, 235, 0.1);
106+
}
107+
}
108+
109+
.timeline-content {
110+
flex: 1;
111+
animation: fadeInUp 0.6s ease;
112+
}
113+
114+
.timeline-date {
115+
font-size: 18px;
116+
font-weight: 600;
117+
color: #f9bdeb;
118+
margin-bottom: 15px;
119+
display: inline-block;
120+
padding: 8px 16px;
121+
background: linear-gradient(135deg, rgba(249, 189, 235, 0.1) 0%, rgba(197, 216, 248, 0.1) 100%);
122+
border-radius: 20px;
123+
border-left: 3px solid #f9bdeb;
124+
}
125+
126+
/* 深色模式 - 日期 */
127+
html.dark .timeline-date {
128+
color: #fdd6f1;
129+
background: linear-gradient(135deg, rgba(249, 189, 235, 0.2) 0%, rgba(197, 216, 248, 0.2) 100%);
130+
border-left-color: #fdd6f1;
131+
}
132+
133+
.timeline-images {
134+
display: flex;
135+
flex-wrap: wrap;
136+
gap: 15px;
137+
padding: 20px;
138+
background: rgba(255, 255, 255, 0.5);
139+
border-radius: 15px;
140+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
141+
transition: all 0.3s ease;
142+
align-items: flex-start;
143+
}
144+
145+
/* 深色模式 - 图片容器 */
146+
html.dark .timeline-images {
147+
background: rgba(0, 0, 0, 0.2);
148+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
149+
}
150+
151+
.timeline-images:hover {
152+
transform: translateY(-3px);
153+
box-shadow: 0 6px 20px rgba(249, 189, 235, 0.2);
154+
}
155+
156+
html.dark .timeline-images:hover {
157+
box-shadow: 0 6px 20px rgba(249, 189, 235, 0.4);
158+
}
159+
160+
/* 图片包装器 */
161+
.timeline-images :deep(.img-wrapper) {
162+
position: relative;
163+
overflow: hidden;
164+
border-radius: 12px;
165+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
166+
transition: all 0.3s ease;
167+
flex-shrink: 0;
168+
}
169+
170+
html.dark .timeline-images :deep(.img-wrapper) {
171+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
172+
}
173+
174+
.timeline-images :deep(.img-wrapper:hover) {
175+
transform: translateY(-5px) scale(1.03);
176+
box-shadow: 0 6px 20px rgba(249, 189, 235, 0.4);
177+
z-index: 10;
178+
}
179+
180+
html.dark .timeline-images :deep(.img-wrapper:hover) {
181+
box-shadow: 0 6px 20px rgba(249, 189, 235, 0.6);
182+
}
183+
184+
.timeline-images :deep(img) {
185+
max-width: 100%;
186+
height: auto;
187+
display: block;
188+
transition: all 0.3s ease;
189+
}
190+
191+
.timeline-images :deep(.img-wrapper:hover img) {
192+
filter: brightness(0.9);
193+
}
194+
195+
/* 图片描述浮层 */
196+
.timeline-images :deep(.img-overlay) {
197+
position: absolute;
198+
bottom: 0;
199+
left: 0;
200+
right: 0;
201+
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
202+
color: white;
203+
padding: 15px 10px 10px;
204+
font-size: 14px;
205+
text-align: center;
206+
opacity: 0;
207+
transform: translateY(100%);
208+
transition: all 0.3s ease;
209+
}
210+
211+
.timeline-images :deep(.img-wrapper:hover .img-overlay) {
212+
opacity: 1;
213+
transform: translateY(0);
214+
}
215+
216+
@keyframes fadeInUp {
217+
from {
218+
opacity: 0;
219+
transform: translateY(20px);
220+
}
221+
to {
222+
opacity: 1;
223+
transform: translateY(0);
224+
}
225+
}
226+
227+
/* 移动端适配 */
228+
@media (max-width: 768px) {
229+
.timeline-item {
230+
margin-bottom: 30px;
231+
}
232+
233+
.timeline-marker {
234+
margin-right: 15px;
235+
}
236+
237+
.timeline-dot {
238+
width: 12px;
239+
height: 12px;
240+
box-shadow: 0 0 0 3px rgba(249, 189, 235, 0.2);
241+
}
242+
243+
.timeline-dot::before {
244+
top: 12px;
245+
height: 60px;
246+
}
247+
248+
.timeline-date {
249+
font-size: 15px;
250+
padding: 6px 12px;
251+
}
252+
253+
.timeline-images {
254+
padding: 12px;
255+
gap: 10px;
256+
justify-content: center;
257+
}
258+
259+
.timeline-images :deep(.img-overlay) {
260+
font-size: 12px;
261+
padding: 10px 8px 8px;
262+
}
263+
}
264+
265+
/* 小屏幕(手机竖屏)*/
266+
@media (max-width: 480px) {
267+
.timeline-item {
268+
margin-bottom: 25px;
269+
}
270+
271+
.timeline-marker {
272+
margin-right: 10px;
273+
}
274+
275+
.timeline-dot {
276+
width: 10px;
277+
height: 10px;
278+
}
279+
280+
.timeline-dot::before {
281+
top: 10px;
282+
height: 50px;
283+
}
284+
285+
.timeline-date {
286+
font-size: 14px;
287+
padding: 5px 10px;
288+
}
289+
290+
.timeline-images {
291+
padding: 10px;
292+
gap: 8px;
293+
justify-content: center;
294+
}
295+
296+
.timeline-images :deep(img) {
297+
max-width: 150px;
298+
}
299+
300+
.timeline-images :deep(.img-overlay) {
301+
font-size: 11px;
302+
padding: 8px 6px 6px;
303+
}
304+
305+
/* 移动端触摸优化 */
306+
.timeline-images :deep(.img-wrapper) {
307+
-webkit-tap-highlight-color: transparent;
308+
}
309+
310+
/* 移动端也显示描述(点击) */
311+
.timeline-images :deep(.img-wrapper:active .img-overlay) {
312+
opacity: 1;
313+
transform: translateY(0);
314+
}
315+
}
316+
</style>
317+

0 commit comments

Comments
 (0)