增加教程样式

This commit is contained in:
speakeloudest 2026-01-04 01:38:25 -08:00
parent e38904422d
commit d8e29af1dc
26 changed files with 113 additions and 31 deletions

View File

@ -5,7 +5,7 @@
v-for="item in downloadMethods" v-for="item in downloadMethods"
:key="item.id" :key="item.id"
@click="toggle(item.id)" @click="toggle(item.id)"
class="group relative flex cursor-pointer flex-col rounded-[30px] border-[4px] border-white bg-black pt-4 pb-2 transition-all active:scale-[0.97] md:pb-6" class="group relative flex cursor-pointer flex-col rounded-[30px] border-[4px] border-white bg-black pt-4 pb-2 transition-all md:pb-6"
> >
<div class="px-4 md:px-[42px]"> <div class="px-4 md:px-[42px]">
<div <div
@ -36,30 +36,68 @@
<div <div
class="animate-in fade-in zoom-in-95 border-t-2 border-white pt-[10px] text-[15px] leading-relaxed duration-200 md:pt-[20px]" class="animate-in fade-in zoom-in-95 border-t-2 border-white pt-[10px] text-[15px] leading-relaxed duration-200 md:pt-[20px]"
> >
<!-- 收起按钮 (仅保留底部悬浮或单一按钮此处移除上方重复项) --> <!-- 内容区域 (点击图片不收起只有特定的关闭按钮收起) -->
<div class="relative px-2"> <div class="relative px-2" @click.stop>
<div <div
class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100 md:text-2xl" class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100 md:text-2xl"
> >
<div class="flex items-center gap-[10px]"> <div class="relative z-10 flex items-center gap-[10px]" @click="toggle(item.id)">
<span class="tracking-tight">点击收起</span> <span class="tracking-tight">点击收起</span>
<ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" /> <ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" />
</div> </div>
</div> </div>
<img :src="item.mobileSrc" class="-mt-10 w-full md:hidden" alt="mobile guide" />
<img :src="item.pcSrc" class="-mt-10 hidden w-full md:block" alt="pc guide" /> <!-- Mobile Image Stack -->
<!-- 底部收起按钮 --> <div class="relative -mt-10 flex flex-col md:hidden">
<div class="absolute right-4 bottom-4"> <img
v-for="(img, idx) in item.mobileImages"
:key="idx"
:src="img"
class="w-full"
alt="mobile guide"
/>
<!-- Mobile Hot Zones -->
<div <div
class="flex items-center justify-end gap-1.5 text-sm font-bold group-hover:opacity-100 md:text-2xl" v-for="(hz, hzIdx) in item.mobileHotzones"
> :key="hzIdx"
<div class="absolute z-20 cursor-pointer"
class="flex items-center gap-[10px] rounded-full bg-black/40 px-3 py-1 backdrop-blur-sm transition-all hover:bg-black/60" :style="{
> left: hz.x + '%',
<span class="tracking-tight">点击收起</span> top: hz.y + '%',
<ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" /> width: hz.w + '%',
</div> height: hz.h + '%',
</div> }"
@click="handleHotzone(hz)"
></div>
</div>
<!-- PC Image Stack -->
<div class="relative mt-4 hidden flex-col md:flex">
<img
v-for="(img, idx) in item.pcImages"
:key="idx"
:src="img"
class="w-full"
alt="pc guide"
/>
<!-- PC Hot Zones -->
<div
v-for="(hz, hzIdx) in item.pcHotzones"
:key="hzIdx"
class="absolute z-20 cursor-pointer"
:style="{
left: hz.x + '%',
top: hz.y + '%',
width: hz.w + '%',
height: hz.h + '%',
}"
@click="handleHotzone(hz)"
></div>
</div>
<!-- 底部收起按钮 -->
<div class="absolute right-4 bottom-4 z-10">
<div @click="toggle(item.id)" class="h-[30px] w-[200px]"></div>
</div> </div>
</div> </div>
</div> </div>
@ -73,13 +111,42 @@
import { ref } from 'vue' import { ref } from 'vue'
import ArrowIcon from './arrow-icon.svg?component' import ArrowIcon from './arrow-icon.svg?component'
import StartIcon from './Star-1.svg?component' import StartIcon from './Star-1.svg?component'
import { toast } from 'vue-sonner'
import mobile1 from './mobile1.png' // Sliced WebP Images
import mobile2 from './mobile2.png' // Method 1
import mobile3 from './mobile3.png' import m1_1 from './mobile1/row-1-column-1.webp'
import pc1 from './pc-1.png' import m1_2 from './mobile1/row-2-column-1.webp'
import pc2 from './pc-2.png' import m1_3 from './mobile1/row-3-column-1.webp'
import pc3 from './pc-3.png' import pc1_1 from './pc1/row-1-column-1.webp'
import pc1_2 from './pc1/row-2-column-1.webp'
import pc1_3 from './pc1/row-3-column-1.webp'
// Method 2
import m2_1 from './mobile2/row-1-column-1.webp'
import m2_2 from './mobile2/row-2-column-1.webp'
import m2_3 from './mobile2/row-3-column-1.webp'
import pc2_1 from './pc2/row-1-column-1.webp'
import pc2_2 from './pc2/row-2-column-1.webp'
import pc2_3 from './pc2/row-3-column-1.webp'
// Method 3
import m3_1 from './mobile3/row-1-column-1.webp'
import m3_2 from './mobile3/row-2-column-1.webp'
import m3_3 from './mobile3/row-3-column-1.webp'
import pc3_1 from './pc3/row-1-column-1.webp'
import pc3_2 from './pc3/row-2-column-1.webp'
import pc3_3 from './pc3/row-3-column-1.webp'
interface Hotzone {
x: number //
y: number //
w: number //
h: number //
type: 'copy' | 'link'
payload: string
label?: string
}
// //
const downloadMethods = ref([ const downloadMethods = ref([
@ -89,8 +156,10 @@ const downloadMethods = ref([
subtitle: '首推', subtitle: '首推',
isHot: true, isHot: true,
highlight: '', highlight: '',
mobileSrc: mobile1, mobileImages: [m1_1, m1_2, m1_3],
pcSrc: pc1, pcImages: [pc1_1, pc1_2, pc1_3],
mobileHotzones: [] as Hotzone[],
pcHotzones: [] as Hotzone[],
}, },
{ {
id: 2, id: 2,
@ -98,8 +167,10 @@ const downloadMethods = ref([
subtitle: '', subtitle: '',
isHot: false, isHot: false,
highlight: '', highlight: '',
mobileSrc: mobile2, mobileImages: [m2_1, m2_2, m2_3],
pcSrc: pc2, pcImages: [pc2_1, pc2_2, pc2_3],
mobileHotzones: [] as Hotzone[],
pcHotzones: [] as Hotzone[],
}, },
{ {
id: 3, id: 3,
@ -107,8 +178,10 @@ const downloadMethods = ref([
subtitle: '', subtitle: '',
isHot: false, isHot: false,
highlight: '谨慎选择', highlight: '谨慎选择',
mobileSrc: mobile3, mobileImages: [m3_1, m3_2, m3_3],
pcSrc: pc3, pcImages: [pc3_1, pc3_2, pc3_3],
mobileHotzones: [] as Hotzone[],
pcHotzones: [] as Hotzone[],
}, },
]) ])
@ -117,6 +190,15 @@ const activeId = ref<number | null>(null)
const toggle = (id: number) => { const toggle = (id: number) => {
activeId.value = activeId.value === id ? null : id activeId.value = activeId.value === id ? null : id
} }
const handleHotzone = (hz: Hotzone) => {
if (hz.type === 'copy') {
navigator.clipboard.writeText(hz.payload)
toast.success(`${hz.label || '内容'}已复制`)
} else if (hz.type === 'link') {
window.open(hz.payload, '_blank')
}
}
</script> </script>
<style scoped> <style scoped>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@ -28,7 +28,7 @@
</div> </div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div <div
class="w-1/2 rounded-full border-5 p-[6px] p-[10px] md:border-[10px]" class="w-1/2 rounded-full border-5 p-[6px] md:border-[10px] md:p-[10px]"
:class="[activeIndex === 0 ? 'border-white' : 'border-black']" :class="[activeIndex === 0 ? 'border-white' : 'border-black']"
@click="activeIndex = 0" @click="activeIndex = 0"
> >
@ -39,7 +39,7 @@
</Button> </Button>
</div> </div>
<div <div
class="w-1/2 rounded-full border-5 p-[6px] p-[10px] md:border-[10px]" class="w-1/2 rounded-full border-5 p-[6px] md:border-[10px] md:p-[10px]"
:class="[activeIndex === 1 ? 'border-white' : 'border-black']" :class="[activeIndex === 1 ? 'border-white' : 'border-black']"
@click="activeIndex = 1" @click="activeIndex = 1"
> >