2026-03-28 23:26:53 +08:00
|
|
|
<script setup>
|
2026-03-29 11:43:08 +08:00
|
|
|
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
|
2026-03-28 23:26:53 +08:00
|
|
|
import { withBase } from 'vitepress'
|
|
|
|
|
import macbookImage from '../../../../assets/macbook.png'
|
2026-03-29 11:03:08 +08:00
|
|
|
import story1Cover from '../../../zh-cn/vibe-stories/images/story-1/image5.png'
|
|
|
|
|
import story2Cover from '../../../zh-cn/vibe-stories/images/story-2/image4.png'
|
|
|
|
|
import story3Cover from '../../../zh-cn/vibe-stories/images/story-3/image3.png'
|
|
|
|
|
import story4Cover from '../../../zh-cn/vibe-stories/images/story-4/image7.png'
|
2026-03-28 23:26:53 +08:00
|
|
|
|
|
|
|
|
// Try to inject translation context from parent or provide a default fallback
|
|
|
|
|
const t = inject('t', {
|
|
|
|
|
value: {
|
|
|
|
|
stories: {
|
2026-03-29 12:34:19 +08:00
|
|
|
cat: '用户故事',
|
2026-03-29 12:15:13 +08:00
|
|
|
title: '看见每一个<br><span class="highlight">闪亮的你</span>',
|
2026-03-29 12:34:19 +08:00
|
|
|
sub: '加入他们,分享你的 vibe coding 故事',
|
|
|
|
|
authorPrefix: '讲述者:',
|
|
|
|
|
ui: {
|
|
|
|
|
prevLabel: '上一则故事',
|
|
|
|
|
nextLabel: '下一则故事',
|
|
|
|
|
selectLabel: '查看这个故事',
|
|
|
|
|
imageAlt: '用户故事封面'
|
|
|
|
|
}
|
2026-03-28 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2026-03-29 12:34:19 +08:00
|
|
|
const tStories = computed(() => [
|
2026-03-28 23:26:53 +08:00
|
|
|
{
|
|
|
|
|
id: 1,
|
2026-03-29 11:03:08 +08:00
|
|
|
title: t.value?.stories?.s1?.title || '放弃月入过万,他在农村小学带孩子们“用AI赶苍蝇”',
|
|
|
|
|
author: t.value?.stories?.s1?.author || '小学老师小浩',
|
|
|
|
|
avatar: '👨🏫',
|
|
|
|
|
image: story1Cover,
|
2026-03-29 12:34:19 +08:00
|
|
|
imageStyle: {
|
|
|
|
|
objectPosition: 'center center'
|
|
|
|
|
},
|
2026-03-28 23:26:53 +08:00
|
|
|
link: '/zh-cn/vibe-stories/story-1'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
2026-03-29 11:03:08 +08:00
|
|
|
title: t.value?.stories?.s2?.title || '期末考试周,我偷偷用AI造了个“校园闲鱼”',
|
|
|
|
|
author: t.value?.stories?.s2?.author || '一位大二学生',
|
|
|
|
|
avatar: '🎓',
|
|
|
|
|
image: story2Cover,
|
2026-03-29 12:34:19 +08:00
|
|
|
imageStyle: {
|
|
|
|
|
objectPosition: 'center center'
|
|
|
|
|
},
|
2026-03-28 23:26:53 +08:00
|
|
|
link: '/zh-cn/vibe-stories/story-2'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
2026-03-29 11:03:08 +08:00
|
|
|
title: t.value?.stories?.s3?.title || '我给每个学生,做了一个不会累的“学霸同桌”',
|
|
|
|
|
author: t.value?.stories?.s3?.author || '高中信息技术老师',
|
|
|
|
|
avatar: '🧑🏫',
|
|
|
|
|
image: story3Cover,
|
2026-03-29 12:34:19 +08:00
|
|
|
imageStyle: {
|
|
|
|
|
objectPosition: '34% center'
|
|
|
|
|
},
|
2026-03-28 23:26:53 +08:00
|
|
|
link: '/zh-cn/vibe-stories/story-3'
|
2026-03-29 11:03:08 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 4,
|
|
|
|
|
title: t.value?.stories?.s4?.title || '48岁货车司机,熬了几个通宵,硬是用AI磕出一个出海工具站',
|
|
|
|
|
author: t.value?.stories?.s4?.author || '货车司机老黄',
|
|
|
|
|
avatar: '🚚',
|
|
|
|
|
image: story4Cover,
|
2026-03-29 12:34:19 +08:00
|
|
|
imageStyle: {
|
|
|
|
|
objectPosition: 'center center'
|
|
|
|
|
},
|
2026-03-29 11:03:08 +08:00
|
|
|
link: '/zh-cn/vibe-stories/story-4'
|
2026-03-28 23:26:53 +08:00
|
|
|
}
|
2026-03-29 12:34:19 +08:00
|
|
|
])
|
2026-03-28 23:26:53 +08:00
|
|
|
|
|
|
|
|
const currentIndex = ref(0)
|
|
|
|
|
let autoplayTimer = null
|
|
|
|
|
const isPaginating = ref(false)
|
|
|
|
|
const containerRef = ref(null)
|
|
|
|
|
let wheelHandler = null
|
|
|
|
|
|
2026-03-29 11:43:08 +08:00
|
|
|
const screenRegion = ref({
|
|
|
|
|
centerX: 50,
|
|
|
|
|
centerY: 45.75,
|
|
|
|
|
width: 80,
|
|
|
|
|
height: 90,
|
|
|
|
|
radius: 4
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const formatPercent = (value) => `${value}%`
|
|
|
|
|
const formatPixels = (value) => `${value}px`
|
|
|
|
|
|
|
|
|
|
const screenContentStyle = computed(() => ({
|
|
|
|
|
top: formatPercent(screenRegion.value.centerY - screenRegion.value.height / 2),
|
|
|
|
|
left: formatPercent(screenRegion.value.centerX - screenRegion.value.width / 2),
|
|
|
|
|
width: formatPercent(screenRegion.value.width),
|
|
|
|
|
height: formatPercent(screenRegion.value.height),
|
|
|
|
|
borderRadius: formatPixels(screenRegion.value.radius)
|
|
|
|
|
}))
|
|
|
|
|
|
2026-03-29 12:34:19 +08:00
|
|
|
const currentStory = computed(() => tStories.value[currentIndex.value] ?? tStories.value[0])
|
|
|
|
|
|
|
|
|
|
// Keep crop settings explicit in source so they survive reload/HMR.
|
|
|
|
|
const currentImageStyle = computed(() => ({
|
|
|
|
|
objectFit: 'cover',
|
|
|
|
|
objectPosition: 'center center',
|
|
|
|
|
...(currentStory.value?.imageStyle || {})
|
|
|
|
|
}))
|
|
|
|
|
|
2026-03-28 23:26:53 +08:00
|
|
|
const transitionName = ref('slide-left')
|
|
|
|
|
|
|
|
|
|
const next = () => {
|
|
|
|
|
if (isPaginating.value) return
|
|
|
|
|
isPaginating.value = true
|
|
|
|
|
transitionName.value = 'slide-left'
|
2026-03-29 12:34:19 +08:00
|
|
|
currentIndex.value = (currentIndex.value + 1) % tStories.value.length
|
2026-03-28 23:26:53 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
|
isPaginating.value = false
|
|
|
|
|
}, 800)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const prev = () => {
|
|
|
|
|
if (isPaginating.value) return
|
|
|
|
|
isPaginating.value = true
|
|
|
|
|
transitionName.value = 'slide-right'
|
2026-03-29 12:34:19 +08:00
|
|
|
currentIndex.value = (currentIndex.value - 1 + tStories.value.length) % tStories.value.length
|
2026-03-28 23:26:53 +08:00
|
|
|
setTimeout(() => {
|
|
|
|
|
isPaginating.value = false
|
|
|
|
|
}, 800)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setIndex = (index) => {
|
|
|
|
|
if (index === currentIndex.value) return
|
|
|
|
|
transitionName.value = index > currentIndex.value ? 'slide-left' : 'slide-right'
|
|
|
|
|
currentIndex.value = index
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const startAutoplay = () => {
|
|
|
|
|
autoplayTimer = setInterval(() => {
|
|
|
|
|
if (!isPaginating.value) {
|
|
|
|
|
transitionName.value = 'slide-left'
|
2026-03-29 12:34:19 +08:00
|
|
|
currentIndex.value = (currentIndex.value + 1) % tStories.value.length
|
2026-03-28 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
}, 4000)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stopAutoplay = () => {
|
|
|
|
|
if (autoplayTimer) {
|
|
|
|
|
clearInterval(autoplayTimer)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
startAutoplay()
|
|
|
|
|
const container = containerRef.value
|
|
|
|
|
if (!container) return
|
|
|
|
|
|
|
|
|
|
wheelHandler = (e) => {
|
|
|
|
|
if (Math.abs(e.deltaX) > 20 && Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
if (e.deltaX > 0) {
|
|
|
|
|
next()
|
|
|
|
|
} else {
|
|
|
|
|
prev()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
container.addEventListener('wheel', wheelHandler, { passive: false })
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
stopAutoplay()
|
|
|
|
|
const container = containerRef.value
|
|
|
|
|
if (container && wheelHandler) {
|
|
|
|
|
container.removeEventListener('wheel', wheelHandler)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div ref="containerRef" class="vibe-stories-container">
|
|
|
|
|
<div class="section-header">
|
2026-03-29 12:15:13 +08:00
|
|
|
<h3 class="section-headline" v-html="t.stories?.title || '看见每一个<br><span class=\'highlight\'>闪亮的你</span>'"></h3>
|
|
|
|
|
<p class="section-sub">{{ t.stories?.sub || '加入他们,分享你的 vibe coding 故事' }}</p>
|
2026-03-28 23:26:53 +08:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="laptop-wrapper" @mouseenter="stopAutoplay" @mouseleave="startAutoplay">
|
|
|
|
|
<div class="laptop-container">
|
|
|
|
|
<!-- Navigation Controls -->
|
2026-03-29 12:34:19 +08:00
|
|
|
<button class="nav-btn prev" :aria-label="t.stories?.ui?.prevLabel || 'Previous story'" @click="prev">
|
2026-03-28 23:26:53 +08:00
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6" /></svg>
|
|
|
|
|
</button>
|
2026-03-29 12:34:19 +08:00
|
|
|
<button class="nav-btn next" :aria-label="t.stories?.ui?.nextLabel || 'Next story'" @click="next">
|
2026-03-28 23:26:53 +08:00
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6" /></svg>
|
|
|
|
|
</button>
|
|
|
|
|
|
2026-03-29 11:43:08 +08:00
|
|
|
<div class="screen-content" :style="screenContentStyle">
|
2026-03-29 12:34:19 +08:00
|
|
|
<a :href="withBase(currentStory.link)" class="screen-link">
|
2026-03-28 23:26:53 +08:00
|
|
|
<transition :name="transitionName">
|
2026-03-29 12:34:19 +08:00
|
|
|
<div :key="currentStory.id" class="screen-image-wrapper">
|
|
|
|
|
<img
|
|
|
|
|
:src="currentStory.image"
|
2026-03-28 23:26:53 +08:00
|
|
|
class="screen-image"
|
2026-03-29 12:34:19 +08:00
|
|
|
:style="currentImageStyle"
|
|
|
|
|
:alt="t.stories?.ui?.imageAlt || 'Story screenshot'"
|
2026-03-28 23:26:53 +08:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</transition>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Laptop Frame -->
|
|
|
|
|
<img :src="macbookImage" class="laptop-frame" alt="MacBook Frame" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Story Info & Avatar -->
|
|
|
|
|
<div class="story-info">
|
2026-03-29 12:34:19 +08:00
|
|
|
<div class="story-avatar">{{ currentStory.avatar }}</div>
|
2026-03-28 23:26:53 +08:00
|
|
|
<div class="story-text">
|
2026-03-29 12:34:19 +08:00
|
|
|
<a :href="withBase(currentStory.link)" class="story-title">
|
|
|
|
|
{{ currentStory.title }}
|
2026-03-28 23:26:53 +08:00
|
|
|
</a>
|
2026-03-29 12:34:19 +08:00
|
|
|
<div class="story-author">{{ t.stories?.authorPrefix || 'by' }} {{ currentStory.author }}</div>
|
2026-03-28 23:26:53 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Indicators -->
|
|
|
|
|
<div class="indicators">
|
|
|
|
|
<button
|
|
|
|
|
v-for="(_, index) in tStories"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="indicator-dot"
|
|
|
|
|
:class="{ active: index === currentIndex }"
|
2026-03-29 12:34:19 +08:00
|
|
|
:aria-label="t.stories?.ui?.selectLabel || 'Select story'"
|
2026-03-28 23:26:53 +08:00
|
|
|
@click="setIndex(index)"
|
|
|
|
|
></button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.vibe-stories-container {
|
|
|
|
|
max-width: 1120px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 0 20px 28px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-header {
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-headline {
|
|
|
|
|
font-size: 60px;
|
|
|
|
|
line-height: 1.08;
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
letter-spacing: -0.034em;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
color: #1d1d1f;
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC', sans-serif;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .section-headline {
|
|
|
|
|
color: #f5f5f7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.highlight {
|
|
|
|
|
background: linear-gradient(120deg, #0066cc, #3399ff);
|
|
|
|
|
background-clip: text;
|
|
|
|
|
-webkit-background-clip: text;
|
|
|
|
|
-webkit-text-fill-color: transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .highlight {
|
|
|
|
|
background: linear-gradient(120deg, #2997ff, #66b3ff);
|
|
|
|
|
background-clip: text;
|
|
|
|
|
-webkit-background-clip: text;
|
|
|
|
|
-webkit-text-fill-color: transparent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.section-sub {
|
|
|
|
|
font-size: 19px;
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
color: #6e6e73;
|
|
|
|
|
max-width: 760px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC', sans-serif;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .section-sub {
|
|
|
|
|
color: #a1a1a6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.laptop-wrapper {
|
|
|
|
|
position: relative;
|
|
|
|
|
width: 100%;
|
|
|
|
|
margin-top: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.laptop-container {
|
|
|
|
|
position: relative;
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-width: 700px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.laptop-frame {
|
2026-03-29 11:43:08 +08:00
|
|
|
position: relative;
|
2026-03-28 23:26:53 +08:00
|
|
|
z-index: 10;
|
|
|
|
|
width: 100%;
|
2026-03-29 11:43:08 +08:00
|
|
|
height: auto;
|
2026-03-28 23:26:53 +08:00
|
|
|
pointer-events: none;
|
|
|
|
|
filter: drop-shadow(0 25px 25px rgb(0 0 0 / 0.15));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .laptop-frame {
|
|
|
|
|
filter: drop-shadow(0 25px 25px rgb(255 255 255 / 0.05));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.screen-content {
|
|
|
|
|
position: absolute;
|
|
|
|
|
z-index: 1;
|
2026-03-29 11:03:08 +08:00
|
|
|
background: #0b0b0f;
|
|
|
|
|
overflow: hidden;
|
2026-03-28 23:26:53 +08:00
|
|
|
perspective: 1000px;
|
|
|
|
|
transform: translateZ(0);
|
|
|
|
|
-webkit-transform: translateZ(0);
|
|
|
|
|
-webkit-mask-image: -webkit-radial-gradient(white, black);
|
|
|
|
|
mask-image: radial-gradient(white, black);
|
|
|
|
|
isolation: isolate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.screen-link {
|
2026-03-29 11:03:08 +08:00
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
2026-03-28 23:26:53 +08:00
|
|
|
display: block;
|
2026-03-29 11:43:08 +08:00
|
|
|
background: transparent;
|
2026-03-28 23:26:53 +08:00
|
|
|
overflow: hidden;
|
2026-03-29 11:43:08 +08:00
|
|
|
border-radius: inherit;
|
2026-03-28 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-29 11:03:08 +08:00
|
|
|
.screen-link:focus,
|
|
|
|
|
.screen-link:focus-visible {
|
|
|
|
|
outline: none;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-28 23:26:53 +08:00
|
|
|
.screen-image-wrapper {
|
|
|
|
|
position: absolute;
|
2026-03-29 11:03:08 +08:00
|
|
|
inset: 0;
|
|
|
|
|
overflow: hidden;
|
2026-03-29 11:43:08 +08:00
|
|
|
border-radius: inherit;
|
2026-03-28 23:26:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.screen-image {
|
2026-03-29 12:34:19 +08:00
|
|
|
position: absolute;
|
|
|
|
|
inset: 0;
|
2026-03-28 23:26:53 +08:00
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
2026-03-29 12:34:19 +08:00
|
|
|
min-width: 100%;
|
|
|
|
|
min-height: 100%;
|
|
|
|
|
max-width: none;
|
|
|
|
|
max-height: none;
|
2026-03-28 23:26:53 +08:00
|
|
|
object-fit: cover;
|
|
|
|
|
object-position: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transitions */
|
|
|
|
|
.slide-left-enter-active,
|
|
|
|
|
.slide-left-leave-active,
|
|
|
|
|
.slide-right-enter-active,
|
|
|
|
|
.slide-right-leave-active {
|
|
|
|
|
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
|
|
|
|
will-change: transform;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.slide-left-enter-from {
|
|
|
|
|
transform: translateX(100%);
|
|
|
|
|
}
|
|
|
|
|
.slide-left-leave-to {
|
|
|
|
|
transform: translateX(-100%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.slide-right-enter-from {
|
|
|
|
|
transform: translateX(-100%);
|
|
|
|
|
}
|
|
|
|
|
.slide-right-leave-to {
|
|
|
|
|
transform: translateX(100%);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Nav Buttons */
|
|
|
|
|
.nav-btn {
|
|
|
|
|
position: absolute;
|
|
|
|
|
top: 50%;
|
|
|
|
|
transform: translateY(-50%);
|
|
|
|
|
z-index: 20;
|
|
|
|
|
background: rgba(255, 255, 255, 0.6);
|
|
|
|
|
backdrop-filter: blur(8px);
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
width: 48px;
|
|
|
|
|
height: 48px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
color: #333;
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.laptop-wrapper:hover .nav-btn {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-btn:hover {
|
|
|
|
|
background: rgba(255, 255, 255, 0.9);
|
|
|
|
|
transform: translateY(-50%) scale(1.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-btn.prev {
|
|
|
|
|
left: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.nav-btn.next {
|
|
|
|
|
right: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
.nav-btn {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
width: 36px;
|
|
|
|
|
height: 36px;
|
|
|
|
|
}
|
|
|
|
|
.nav-btn.prev { left: 10px; }
|
|
|
|
|
.nav-btn.next { right: 10px; }
|
|
|
|
|
|
|
|
|
|
.section-headline { font-size: 42px; }
|
|
|
|
|
.section-sub { font-size: 17px; }
|
|
|
|
|
.laptop-container { max-width: 100%; }
|
|
|
|
|
.story-info {
|
|
|
|
|
margin-top: 18px;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Story Info */
|
|
|
|
|
.story-info {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 16px;
|
|
|
|
|
margin-top: 22px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.story-avatar {
|
|
|
|
|
font-size: 48px;
|
|
|
|
|
line-height: 1;
|
|
|
|
|
background: #f5f5f7;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
width: 72px;
|
|
|
|
|
height: 72px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .story-avatar {
|
|
|
|
|
background: #2c2c2e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.story-text {
|
|
|
|
|
text-align: left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.story-title {
|
|
|
|
|
display: block;
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #1d1d1f;
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
transition: color 0.2s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .story-title {
|
|
|
|
|
color: #f5f5f7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.story-title:hover {
|
|
|
|
|
color: #0066cc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .story-title:hover {
|
|
|
|
|
color: #2997ff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.story-author {
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
color: #86868b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Indicators */
|
|
|
|
|
.indicators {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
margin-top: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.indicator-dot {
|
|
|
|
|
width: 8px;
|
|
|
|
|
height: 8px;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background: #d2d2d7;
|
|
|
|
|
border: none;
|
|
|
|
|
padding: 0;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .indicator-dot {
|
|
|
|
|
background: #424245;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.indicator-dot:hover {
|
|
|
|
|
background: #86868b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.indicator-dot.active {
|
|
|
|
|
width: 24px;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
background: #1d1d1f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dark .indicator-dot.active {
|
|
|
|
|
background: #f5f5f7;
|
|
|
|
|
}
|
2026-03-29 11:43:08 +08:00
|
|
|
|
2026-03-28 23:26:53 +08:00
|
|
|
</style>
|