|
70 | 70 | .nav-tab:hover { color: var(--text); } |
71 | 71 | .nav-tab.active { color: var(--coffee); border-bottom-color: var(--coffee); } |
72 | 72 |
|
73 | | - /* ── Slideshow container ── */ |
| 73 | + /* ── Poster stage ── */ |
74 | 74 | .slideshow-wrap { |
75 | 75 | flex: 1; |
76 | 76 | display: flex; |
77 | 77 | flex-direction: column; |
78 | 78 | align-items: center; |
79 | | - justify-content: center; |
| 79 | + justify-content: flex-start; |
80 | 80 | position: relative; |
81 | | - padding: 0 3rem; |
| 81 | + padding: 1.4rem 3rem 0; |
82 | 82 | overflow: hidden; |
83 | 83 | } |
84 | 84 |
|
85 | 85 | .slideshow-stage { |
86 | 86 | position: relative; |
87 | 87 | width: 100%; |
88 | | - max-width: 1100px; |
| 88 | + max-width: min(1600px, calc((100svh - 190px) * 16 / 9)); |
89 | 89 | flex: 1; |
90 | 90 | display: flex; |
91 | 91 | align-items: center; |
92 | 92 | justify-content: center; |
93 | 93 | min-height: 0; |
94 | 94 | } |
95 | 95 |
|
96 | | - .slide-img { |
97 | | - max-width: 100%; |
98 | | - max-height: 68vh; |
99 | | - object-fit: contain; |
| 96 | + .poster-frame-wrap { |
| 97 | + width: 100%; |
| 98 | + aspect-ratio: 16 / 9; |
| 99 | + background: var(--surface); |
| 100 | + border: 1px solid var(--border2); |
100 | 101 | border-radius: 6px; |
101 | 102 | box-shadow: 0 4px 20px rgba(0,0,0,0.10); |
102 | | - transition: opacity 0.3s ease; |
103 | | - cursor: default; |
| 103 | + overflow: hidden; |
| 104 | + } |
| 105 | + |
| 106 | + .poster-frame { |
| 107 | + width: 100%; |
| 108 | + height: 100%; |
| 109 | + border: 0; |
| 110 | + display: block; |
| 111 | + background: var(--surface); |
| 112 | + } |
| 113 | + |
| 114 | + .slide-img { |
| 115 | + width: 100%; |
| 116 | + height: 100%; |
| 117 | + object-fit: contain; |
| 118 | + display: block; |
104 | 119 | } |
105 | 120 |
|
106 | 121 | /* ── Nav arrows ── */ |
|
155 | 170 | transition: all 0.15s; |
156 | 171 | } |
157 | 172 | .open-poster:hover { background: var(--accent); color: #fff; } |
| 173 | + .poster-select { |
| 174 | + max-width: min(46vw, 520px); |
| 175 | + border: 1px solid var(--border2); |
| 176 | + border-radius: 3px; |
| 177 | + background: var(--surface); |
| 178 | + color: var(--text); |
| 179 | + font-family: "JetBrains Mono", monospace; |
| 180 | + font-size: 0.72rem; |
| 181 | + padding: 0.35rem 0.6rem; |
| 182 | + } |
158 | 183 | .dot { |
159 | 184 | width: 8px; height: 8px; |
160 | 185 | border-radius: 50%; |
|
194 | 219 | header { padding: 1rem 1.2rem; } |
195 | 220 | .nav-tabs { padding: 0 1.2rem; overflow-x: auto; } |
196 | 221 | .nav-tab { flex: 0 0 auto; } |
197 | | - .slideshow-wrap { padding: 0 0.75rem; justify-content: flex-start; } |
198 | | - .slideshow-stage { align-items: flex-start; padding-top: 0.75rem; } |
199 | | - .arrow { width: 36px; height: 36px; font-size: 1rem; } |
200 | | - .arrow-left { left: 0; } |
201 | | - .arrow-right { right: 0; } |
202 | | - .slide-img { |
203 | | - width: min(100%, 430px); |
204 | | - max-height: calc(100svh - 185px); |
205 | | - aspect-ratio: 9 / 16; |
206 | | - object-fit: contain; |
207 | | - border-radius: 8px; |
| 222 | + .slideshow-wrap { padding: 0.8rem 0.75rem 0; justify-content: flex-start; } |
| 223 | + .slideshow-stage { |
| 224 | + align-items: flex-start; |
| 225 | + width: 100%; |
| 226 | + max-width: 100%; |
| 227 | + flex: 0 0 auto; |
208 | 228 | } |
| 229 | + .arrow { width: 36px; height: 36px; font-size: 1rem; } |
| 230 | + .arrow-left { left: 0.25rem; } |
| 231 | + .arrow-right { right: 0.25rem; } |
209 | 232 | .slideshow-bar { padding: 0.8rem 0 1rem; flex-wrap: wrap; } |
| 233 | + .poster-select { max-width: 100%; width: 100%; order: 3; } |
210 | 234 | } |
211 | 235 | </style> |
212 | 236 | </head> |
|
232 | 256 | <div class="slideshow-wrap" id="slideshow-wrap" style="display:none;"> |
233 | 257 | <div class="slideshow-stage"> |
234 | 258 | <button class="arrow arrow-left" id="arrow-left" onclick="prevSlide()" title="上一张 (←)">◀</button> |
235 | | - <img class="slide-img" id="slide-img" src="" alt="poster" /> |
| 259 | + <div class="poster-frame-wrap" id="poster-frame-wrap"></div> |
236 | 260 | <button class="arrow arrow-right" id="arrow-right" onclick="nextSlide()" title="下一张 (→)">▶</button> |
237 | 261 | </div> |
238 | 262 | <div class="slideshow-bar"> |
239 | 263 | <span class="slide-counter" id="slide-counter"></span> |
| 264 | + <select class="poster-select" id="poster-select" onchange="showSlide(Number(this.value))"></select> |
240 | 265 | <div class="dots-wrap" id="dots-wrap"></div> |
241 | 266 | <a class="open-poster" id="open-poster" href="#" target="_self">打开当前海报 →</a> |
242 | 267 | </div> |
|
262 | 287 | function showSlide(idx) { |
263 | 288 | if (!images.length) return; |
264 | 289 | currentIdx = ((idx % images.length) + images.length) % images.length; |
265 | | - const img = document.getElementById('slide-img'); |
266 | | - img.src = images[currentIdx].url; |
267 | | - img.alt = images[currentIdx].name; |
| 290 | + const current = images[currentIdx]; |
| 291 | + const wrap = document.getElementById('poster-frame-wrap'); |
| 292 | + if (current.poster_url) { |
| 293 | + wrap.innerHTML = `<iframe class="poster-frame" src="${current.poster_url}" title="${current.name || 'poster'}"></iframe>`; |
| 294 | + } else { |
| 295 | + wrap.innerHTML = `<img class="slide-img" src="${current.url}" alt="${current.name || 'poster'}">`; |
| 296 | + } |
268 | 297 |
|
269 | 298 | // Counter |
270 | 299 | document.getElementById('slide-counter').textContent = |
271 | 300 | `${currentIdx + 1} / ${images.length}`; |
| 301 | + document.getElementById('poster-select').value = String(currentIdx); |
272 | 302 | const openLink = document.getElementById('open-poster'); |
273 | | - if (images[currentIdx].poster_url) { |
274 | | - openLink.href = images[currentIdx].poster_url; |
| 303 | + if (current.poster_url) { |
| 304 | + openLink.href = current.poster_url; |
275 | 305 | openLink.style.display = 'inline-block'; |
276 | 306 | } else { |
277 | 307 | openLink.style.display = 'none'; |
|
287 | 317 | }); |
288 | 318 | } |
289 | 319 |
|
| 320 | +function renderSelect() { |
| 321 | + const select = document.getElementById('poster-select'); |
| 322 | + select.innerHTML = images.map((img, i) => { |
| 323 | + const label = img.arxiv_id ? `arXiv:${img.arxiv_id}` : img.name || `Poster ${i + 1}`; |
| 324 | + return `<option value="${i}">${label}</option>`; |
| 325 | + }).join(''); |
| 326 | + select.style.display = images.length > 1 ? 'inline-block' : 'none'; |
| 327 | +} |
| 328 | + |
290 | 329 | function renderDots() { |
291 | 330 | const wrap = document.getElementById('dots-wrap'); |
292 | 331 | if (images.length <= 1) { wrap.innerHTML = ''; return; } |
|
330 | 369 |
|
331 | 370 | document.getElementById('empty-state').style.display = 'none'; |
332 | 371 | document.getElementById('slideshow-wrap').style.display = 'flex'; |
| 372 | + renderSelect(); |
333 | 373 | renderDots(); |
334 | 374 | showSlide(0); |
335 | 375 | } catch (e) { |
|
356 | 396 | else prevSlide(); |
357 | 397 | }); |
358 | 398 |
|
359 | | -// ── Click left/right half of image ── |
360 | | -document.getElementById('slide-img').addEventListener('click', (e) => { |
361 | | - const rect = e.target.getBoundingClientRect(); |
362 | | - const x = e.clientX - rect.left; |
363 | | - if (x < rect.width / 2) prevSlide(); |
364 | | - else nextSlide(); |
365 | | -}); |
366 | | - |
367 | 399 | document.addEventListener('DOMContentLoaded', loadPosters); |
368 | 400 | window.addEventListener('resize', () => showSlide(currentIdx)); |
369 | 401 | </script> |
|
0 commit comments