@yangyongtao/gaea 1.1.10 → 1.1.11

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.
@@ -0,0 +1,208 @@
1
+ <!-- 组件名:SwiperSecAnimation.vue(无需修改引用) -->
2
+ <template>
3
+ <div class="swiper-sec-animation">
4
+ <!-- 左箭头按钮(上一页) -->
5
+ <button class="control-btn left" @click="handlePrev" :disabled="!loop && currentIndex === 0" aria-label="上一页">
6
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
7
+ stroke-linecap="round" stroke-linejoin="round">
8
+ <path d="M15 18l-6-6 6-6" />
9
+ </svg>
10
+ </button>
11
+
12
+ <!-- 中间滑块区域 -->
13
+ <div class="slider-wrap">
14
+ <div class="slider-track" @click="handleTrackClick">
15
+ <div class="slider-thumb" :style="{ left: `${thumbLeft}%`, width: `${thumbWidth}%` }" @mousedown="startDrag" aria-label="拖动切换索引">
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <!-- 右箭头按钮(下一页) -->
21
+ <button class="control-btn right" @click="handleNext" :disabled="!loop && currentIndex === total - 1"
22
+ aria-label="下一页">
23
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
24
+ stroke-linecap="round" stroke-linejoin="round">
25
+ <path d="M9 6l6 6-6 6" />
26
+ </svg>
27
+ </button>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+ import { ref, watch, computed } from 'vue';
33
+
34
+ // Props 保持不变
35
+ const props = defineProps({
36
+ total: {
37
+ type: Number,
38
+ required: true,
39
+ default: 6
40
+ },
41
+ initialIndex: {
42
+ type: Number,
43
+ default: 2
44
+ },
45
+ loop: {
46
+ type: Boolean,
47
+ default: true
48
+ }
49
+ });
50
+
51
+ // 响应式状态
52
+ const currentIndex = ref(props.initialIndex);
53
+ const isDragging = ref(false);
54
+
55
+ // 核心修改:滑块宽度动态适配total(100% / total)
56
+ const thumbWidth = computed(() => {
57
+ // 最小宽度8%(避免total太大时滑块过窄),最大宽度33%(total=3时刚好1/3)
58
+ const minWidth = 8;
59
+ const maxWidth = 33.33;
60
+ const calcWidth = 100 / props.total;
61
+ return Math.min(Math.max(calcWidth, minWidth), maxWidth);
62
+ });
63
+
64
+ // 滑块最大左移距离(100% - 滑块宽度,避免超出轨道)
65
+ const maxLeft = computed(() => 100 - thumbWidth.value);
66
+
67
+ // 滑块位置计算(基于动态宽度和maxLeft)
68
+ const thumbLeft = computed(() => {
69
+ if (props.total === 1) return 0;
70
+ // 索引比例 → 滑块位置
71
+ return (currentIndex.value / (props.total - 1)) * maxLeft.value;
72
+ });
73
+
74
+ // 上一页(不变)
75
+ function handlePrev() {
76
+ if (!props.loop && currentIndex.value === 0) return;
77
+ currentIndex.value = currentIndex.value === 0
78
+ ? props.total - 1
79
+ : currentIndex.value - 1;
80
+ emit('index-change', currentIndex.value);
81
+ }
82
+
83
+ // 下一页(不变)
84
+ function handleNext() {
85
+ if (!props.loop && currentIndex.value === props.total - 1) return;
86
+ currentIndex.value = currentIndex.value === props.total - 1
87
+ ? 0
88
+ : currentIndex.value + 1;
89
+ emit('index-change', currentIndex.value);
90
+ }
91
+
92
+ // 拖动滑块(适配动态宽度)
93
+ function startDrag() {
94
+ isDragging.value = true;
95
+ const track = document.querySelector('.slider-track');
96
+ const trackRect = track.getBoundingClientRect();
97
+
98
+ const onDrag = (e) => {
99
+ if (!isDragging.value) return;
100
+ const clientX = e.type.includes('touch') ? e.touches[0].clientX : e.clientX;
101
+ // 计算拖动位置百分比(适配动态maxLeft)
102
+ const dragPercent = Math.max(0, Math.min(1, (clientX - trackRect.left) / trackRect.width)) * maxLeft.value;
103
+ currentIndex.value = Math.round((dragPercent / maxLeft.value) * (props.total - 1));
104
+ };
105
+
106
+ const endDrag = () => {
107
+ isDragging.value = false;
108
+ document.removeEventListener('mousemove', onDrag);
109
+ document.removeEventListener('mouseup', endDrag);
110
+ emit('index-change', currentIndex.value);
111
+ };
112
+
113
+ document.addEventListener('mousemove', onDrag);
114
+ document.addEventListener('mouseup', endDrag);
115
+ }
116
+
117
+ // 点击轨道跳转(适配动态宽度)
118
+ function handleTrackClick(e) {
119
+ if (isDragging.value) return;
120
+ const track = e.currentTarget;
121
+ const trackRect = track.getBoundingClientRect();
122
+ // 计算点击位置对应的索引(适配动态maxLeft)
123
+ const clickPercent = Math.max(0, Math.min(1, (e.clientX - trackRect.left) / trackRect.width)) * maxLeft.value;
124
+ currentIndex.value = Math.round((clickPercent / maxLeft.value) * (props.total - 1));
125
+ emit('index-change', currentIndex.value);
126
+ }
127
+
128
+ // 发射事件(不变)
129
+ const emit = defineEmits(['index-change']);
130
+ </script>
131
+
132
+ <style scoped>
133
+ /* 容器样式(不变) */
134
+ .swiper-sec-animation {
135
+ display: flex;
136
+ align-items: center;
137
+ gap: 12px;
138
+ padding: 10px;
139
+ width: 40%;
140
+ min-width: 300px;
141
+ box-sizing: border-box;
142
+ }
143
+
144
+ /* 蓝色主题按钮样式(不变) */
145
+ .control-btn {
146
+ width: 30px;
147
+ height: 30px;
148
+ border: none;
149
+ border-radius: 50%;
150
+ background: #1890ff;
151
+ color: white;
152
+ cursor: pointer;
153
+ flex-shrink: 0;
154
+ display: flex;
155
+ align-items: center;
156
+ justify-content: center;
157
+ transition: all 0.2s ease;
158
+ padding: 0;
159
+ }
160
+
161
+ .control-btn:hover:not(:disabled) {
162
+ background: #096dd9;
163
+ transform: scale(1.05);
164
+ }
165
+
166
+ .control-btn:disabled {
167
+ background: #e6f7ff;
168
+ color: #8cc5ff;
169
+ cursor: not-allowed;
170
+ transform: none;
171
+ }
172
+
173
+ /* 中间滑块容器(不变) */
174
+ .slider-wrap {
175
+ flex: 1;
176
+ height: 40px;
177
+ display: flex;
178
+ align-items: center;
179
+ }
180
+
181
+ /* 蓝色主题轨道(不变) */
182
+ .slider-track {
183
+ width: 100%;
184
+ height: 0.5rem;
185
+ background: rgba(230, 247, 255, 0.5);
186
+ border-radius: 8px;
187
+ position: relative;
188
+ cursor: pointer;
189
+ }
190
+
191
+ /* 蓝色主题滑块(仅移除固定宽度,由JS动态计算) */
192
+ .slider-thumb {
193
+ position: absolute;
194
+ top: 0;
195
+ left: 0;
196
+ height: 100%;
197
+ background: #1890ff;
198
+ border-radius: 8px;
199
+ cursor: grab;
200
+ transition: left 0.2s ease, background 0.2s ease;
201
+ z-index: 2;
202
+ }
203
+
204
+ .slider-thumb:active {
205
+ cursor: grabbing;
206
+ background: #096dd9;
207
+ }
208
+ </style>
@@ -26,6 +26,9 @@ const MIME = {
26
26
  '.png': 'image/png',
27
27
  '.jpg': 'image/jpeg',
28
28
  '.res': 'application/octet-stream',
29
+ '.gltf': 'model/gltf+json',
30
+ '.glb': 'model/gltf-binary',
31
+ '.bin': 'application/octet-stream',
29
32
  };
30
33
 
31
34
  const COEP_HEADERS = {
@@ -48,13 +51,13 @@ export default function gaeaVitePlugin() {
48
51
  server.middlewares.stack.unshift({
49
52
  route: '',
50
53
  handle: function gaeaServe(req, res, next) {
51
- const url = req.url.split('?')[0];
54
+ const url = decodeURIComponent(req.url.split('?')[0]);
52
55
 
53
56
  const gaeaTopFiles = [
54
57
  'Gaea.js', 'Gaea.wasm', 'Gaea.pck', 'Gaea.worker.js',
55
58
  'Gaea.audio.worklet.js', 'index.js', 'config.js', 'constants.js',
56
59
  ];
57
- const gaeaDirs = ['math/', 'static/'];
60
+ const gaeaDirs = ['math/', 'static/', 'image/'];
58
61
 
59
62
  let relative = null;
60
63
  for (const name of gaeaTopFiles) {