增加教程样式

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"
:key="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
@ -36,30 +36,68 @@
<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]"
>
<!-- 收起按钮 (仅保留底部悬浮或单一按钮此处移除上方重复项) -->
<div class="relative px-2">
<!-- 内容区域 (点击图片不收起只有特定的关闭按钮收起) -->
<div class="relative px-2" @click.stop>
<div
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>
<ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" />
</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" />
<!-- 底部收起按钮 -->
<div class="absolute right-4 bottom-4">
<!-- Mobile Image Stack -->
<div class="relative -mt-10 flex flex-col md:hidden">
<img
v-for="(img, idx) in item.mobileImages"
:key="idx"
:src="img"
class="w-full"
alt="mobile guide"
/>
<!-- Mobile Hot Zones -->
<div
class="flex items-center justify-end gap-1.5 text-sm font-bold group-hover:opacity-100 md:text-2xl"
>
<div
class="flex items-center gap-[10px] rounded-full bg-black/40 px-3 py-1 backdrop-blur-sm transition-all hover:bg-black/60"
>
<span class="tracking-tight">点击收起</span>
<ArrowIcon class="size-[12px] rotate-180 md:size-[22px]" />
</div>
</div>
v-for="(hz, hzIdx) in item.mobileHotzones"
: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>
<!-- 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>
@ -73,13 +111,42 @@
import { ref } from 'vue'
import ArrowIcon from './arrow-icon.svg?component'
import StartIcon from './Star-1.svg?component'
import { toast } from 'vue-sonner'
import mobile1 from './mobile1.png'
import mobile2 from './mobile2.png'
import mobile3 from './mobile3.png'
import pc1 from './pc-1.png'
import pc2 from './pc-2.png'
import pc3 from './pc-3.png'
// Sliced WebP Images
// Method 1
import m1_1 from './mobile1/row-1-column-1.webp'
import m1_2 from './mobile1/row-2-column-1.webp'
import m1_3 from './mobile1/row-3-column-1.webp'
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([
@ -89,8 +156,10 @@ const downloadMethods = ref([
subtitle: '首推',
isHot: true,
highlight: '',
mobileSrc: mobile1,
pcSrc: pc1,
mobileImages: [m1_1, m1_2, m1_3],
pcImages: [pc1_1, pc1_2, pc1_3],
mobileHotzones: [] as Hotzone[],
pcHotzones: [] as Hotzone[],
},
{
id: 2,
@ -98,8 +167,10 @@ const downloadMethods = ref([
subtitle: '',
isHot: false,
highlight: '',
mobileSrc: mobile2,
pcSrc: pc2,
mobileImages: [m2_1, m2_2, m2_3],
pcImages: [pc2_1, pc2_2, pc2_3],
mobileHotzones: [] as Hotzone[],
pcHotzones: [] as Hotzone[],
},
{
id: 3,
@ -107,8 +178,10 @@ const downloadMethods = ref([
subtitle: '',
isHot: false,
highlight: '谨慎选择',
mobileSrc: mobile3,
pcSrc: pc3,
mobileImages: [m3_1, m3_2, m3_3],
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) => {
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>
<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 class="flex items-center justify-between">
<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']"
@click="activeIndex = 0"
>
@ -39,7 +39,7 @@
</Button>
</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']"
@click="activeIndex = 1"
>