|
81 | 81 | </div> |
82 | 82 | </section> |
83 | 83 |
|
84 | | - <!-- Preview --> |
85 | | - <section class="preview"> |
86 | | - <div class="screenshot-card"> |
87 | | - <img src="/sketches/arus-dashboard.png" alt="Arus Console Dashboard" class="screenshot" /> |
| 84 | + <!-- Preview Slider --> |
| 85 | + <section class="preview-slider"> |
| 86 | + <div class="slider-container"> |
| 87 | + <div class="slider-track" :style="{ transform: `translateX(-${currentSlide * 100}%)` }"> |
| 88 | + <div class="slider-slide" v-for="(s, i) in slides" :key="i"> |
| 89 | + <div class="screenshot-card"> |
| 90 | + <img :src="s.src" :alt="s.alt" class="screenshot" /> |
| 91 | + <div class="slide-label">{{ s.label }}</div> |
| 92 | + </div> |
| 93 | + </div> |
| 94 | + </div> |
| 95 | + <button class="slider-arrow slider-prev" @click="prevSlide" :disabled="currentSlide === 0" aria-label="Previous slide"> |
| 96 | + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg> |
| 97 | + </button> |
| 98 | + <button class="slider-arrow slider-next" @click="nextSlide" :disabled="currentSlide === slides.length - 1" aria-label="Next slide"> |
| 99 | + <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg> |
| 100 | + </button> |
| 101 | + <div class="slider-dots"> |
| 102 | + <button |
| 103 | + v-for="(s, i) in slides" |
| 104 | + :key="i" |
| 105 | + class="slider-dot" |
| 106 | + :class="{ active: currentSlide === i }" |
| 107 | + @click="currentSlide = i" |
| 108 | + :aria-label="`Go to slide ${i + 1}`" |
| 109 | + ></button> |
| 110 | + </div> |
88 | 111 | </div> |
89 | 112 | </section> |
90 | 113 |
|
@@ -286,10 +309,43 @@ docker run -d --network arus-net --name arus-console -p 8082:80 \ |
286 | 309 | </template> |
287 | 310 |
|
288 | 311 | <script setup> |
289 | | -import { ref } from 'vue' |
| 312 | +import { ref, onMounted, onUnmounted } from 'vue' |
290 | 313 |
|
291 | 314 | const copied = ref(null) |
292 | 315 |
|
| 316 | +const currentSlide = ref(0) |
| 317 | +
|
| 318 | +const slides = [ |
| 319 | + { src: '/sketches/arus-dashboard.png', alt: 'Arus Dashboard', label: 'Dashboard — monitor all pipelines at a glance' }, |
| 320 | + { src: '/sketches/arus-sources.png', alt: 'Arus Sources', label: 'Sources — manage your database connections' }, |
| 321 | + { src: '/sketches/arus-pipelines.png', alt: 'Arus Pipelines', label: 'Pipelines — configure CDC & sync schedules' }, |
| 322 | + { src: '/sketches/arus-dag.png', alt: 'Arus DAG View', label: 'DAG View — visualize your data lineage' }, |
| 323 | + { src: '/sketches/arus-add-source.png', alt: 'Arus Add Source', label: 'Add Source — connect in under a minute' }, |
| 324 | +] |
| 325 | +
|
| 326 | +let slideTimer |
| 327 | +function startAutoplay() { |
| 328 | + stopAutoplay() |
| 329 | + slideTimer = setInterval(() => { |
| 330 | + nextSlide() |
| 331 | + }, 4000) |
| 332 | +} |
| 333 | +function stopAutoplay() { |
| 334 | + if (slideTimer) clearInterval(slideTimer) |
| 335 | + slideTimer = null |
| 336 | +} |
| 337 | +function nextSlide() { |
| 338 | + if (currentSlide.value < slides.length - 1) currentSlide.value++ |
| 339 | + else currentSlide.value = 0 |
| 340 | +} |
| 341 | +function prevSlide() { |
| 342 | + if (currentSlide.value > 0) currentSlide.value-- |
| 343 | + else currentSlide.value = slides.length - 1 |
| 344 | +} |
| 345 | +
|
| 346 | +onMounted(() => startAutoplay()) |
| 347 | +onUnmounted(() => stopAutoplay()) |
| 348 | +
|
293 | 349 | function copyCode(idx) { |
294 | 350 | const codes = [ |
295 | 351 | 'cat > .env << EOF\nARUS_JWT_SECRET=$(openssl rand -hex 32)\nARUS_ENCRYPTION_KEY=$(openssl rand -hex 32)\nARUS_DB_USER=arus\nARUS_DB_PASSWORD=arus_secret\nARUS_DB_NAME=arus_warehouse\nARUS_ADMIN_EMAIL=admin@arus.io\nARUS_ADMIN_PASSWORD=admin123\nPOSTGRES_USER=arus\nPOSTGRES_PASSWORD=arus_secret\nPOSTGRES_DB=arus_warehouse\nEOF\n\ndocker network create arus-net\n\ndocker run -d --network arus-net --name arus-db \\\n -v arus-db-data:/var/lib/postgresql/data \\\n --env-file .env \\\n postgres:15-alpine\n\ndocker run -d --network arus-net --name arus-api -p 8081:8081 \\\n -e ARUS_DB_HOST=arus-db \\\n --env-file .env \\\n registry.edsuwarna.xyz/arus-api:main-latest\n\ndocker run -d --network arus-net --name arus-console -p 8082:80 \\\n registry.edsuwarna.xyz/arus-console:main-latest', |
@@ -434,17 +490,50 @@ function checkClass(v) { |
434 | 490 | .dag-node.target { background: rgba(234,179,8,0.1); border: 1px solid rgba(234,179,8,0.2); color: #fde68a; } |
435 | 491 | .dag-arrow { color: #5c626e; display: flex; align-items: center; } |
436 | 492 |
|
437 | | -/* === PREVIEW === */ |
438 | | -.preview { |
| 493 | +/* === PREVIEW SLIDER === */ |
| 494 | +.preview-slider { |
439 | 495 | max-width: 1100px; margin: 0 auto; padding: 0 24px 48px; |
440 | 496 | } |
| 497 | +.slider-container { |
| 498 | + position: relative; overflow: hidden; |
| 499 | + border-radius: 12px; |
| 500 | +} |
| 501 | +.slider-track { |
| 502 | + display: flex; transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1); |
| 503 | +} |
| 504 | +.slider-slide { |
| 505 | + min-width: 100%; box-sizing: border-box; |
| 506 | +} |
441 | 507 | .screenshot-card { |
442 | 508 | background: #14171d; border: 1px solid #23262e; border-radius: 12px; |
443 | 509 | overflow: hidden; box-shadow: 0 4px 24px rgba(0,0,0,0.3); |
444 | 510 | } |
445 | | -.screenshot { |
446 | | - display: block; width: 100%; height: auto; |
| 511 | +.screenshot { display: block; width: 100%; height: auto; } |
| 512 | +.slide-label { |
| 513 | + padding: 12px 20px; font-size: 13px; color: #9aa0a8; |
| 514 | + border-top: 1px solid #23262e; text-align: center; |
| 515 | +} |
| 516 | +.slider-arrow { |
| 517 | + position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; |
| 518 | + width: 40px; height: 40px; border-radius: 50%; |
| 519 | + background: rgba(11,13,17,0.7); border: 1px solid #23262e; |
| 520 | + color: #e8eaed; cursor: pointer; display: flex; align-items: center; justify-content: center; |
| 521 | + transition: all 0.2s; backdrop-filter: blur(4px); |
| 522 | +} |
| 523 | +.slider-arrow:hover { background: rgba(234,179,8,0.15); border-color: #eab308; color: #eab308; } |
| 524 | +.slider-arrow:disabled { opacity: 0.3; cursor: default; } |
| 525 | +.slider-arrow:disabled:hover { background: rgba(11,13,17,0.7); border-color: #23262e; color: #e8eaed; } |
| 526 | +.slider-prev { left: 16px; } |
| 527 | +.slider-next { right: 16px; } |
| 528 | +.slider-dots { |
| 529 | + display: flex; justify-content: center; gap: 8px; padding: 16px 0 4px; |
| 530 | +} |
| 531 | +.slider-dot { |
| 532 | + width: 8px; height: 8px; border-radius: 50%; border: none; cursor: pointer; |
| 533 | + background: #23262e; transition: all 0.3s; padding: 0; |
447 | 534 | } |
| 535 | +.slider-dot.active { background: #eab308; width: 24px; border-radius: 4px; } |
| 536 | +.slider-dot:hover { background: #5c626e; } |
448 | 537 |
|
449 | 538 | /* === STATS === */ |
450 | 539 | .stats { |
|
0 commit comments