Merge remote-tracking branch 'origin/main' into develop
Some checks failed
site-dist-deploy / build-and-deploy (push) Has been cancelled
@ -21,6 +21,7 @@
|
||||
"axios": "^1.13.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"crisp-sdk-web": "^1.0.27",
|
||||
"crypto-js": "^4.2.0",
|
||||
"lucide-vue-next": "^0.562.0",
|
||||
"reka-ui": "^2.7.0",
|
||||
|
||||
8
pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ importers:
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
crisp-sdk-web:
|
||||
specifier: ^1.0.27
|
||||
version: 1.0.27
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
@ -1048,6 +1051,9 @@ packages:
|
||||
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
crisp-sdk-web@1.0.27:
|
||||
resolution: {integrity: sha512-aNWR3te65YiaVFu/iwdqOo3cyUBZHUheE4d6EtgQu/T18jh/9SpoYXjXF/OzUD3Cqy0pGryoqtuy5gxD8tqX9Q==}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -3047,6 +3053,8 @@ snapshots:
|
||||
dependencies:
|
||||
is-what: 5.5.0
|
||||
|
||||
crisp-sdk-web@1.0.27: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
|
||||
35
src/App.vue
@ -1,9 +1,3 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import 'vue-sonner/style.css'
|
||||
import { Toaster } from '@/components/ui/sonner'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<main>
|
||||
@ -22,4 +16,33 @@ import { Toaster } from '@/components/ui/sonner'
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import { onMounted } from 'vue'
|
||||
import 'vue-sonner/style.css'
|
||||
import { Toaster } from '@/components/ui/sonner'
|
||||
import { Crisp } from 'crisp-sdk-web'
|
||||
|
||||
const WEBSITE_ID = '47fcc1ac-9674-4ab1-9e3c-6b5666f59a38'
|
||||
|
||||
onMounted(() => {
|
||||
// 定义加载逻辑
|
||||
const loadCrisp = () => {
|
||||
console.log('页面资源已就绪,开始初始化 Crisp...')
|
||||
Crisp.configure(WEBSITE_ID)
|
||||
|
||||
// 可选:初始化后自动隐藏或执行其他逻辑
|
||||
// Crisp.chat.hide();
|
||||
}
|
||||
|
||||
// 如果页面已经加载完成(或者是从其他路由跳转过来的)
|
||||
if (document.readyState === 'complete') {
|
||||
loadCrisp()
|
||||
} else {
|
||||
// 否则等待 window load 事件,确保图片、CSS等资源全部加载完毕
|
||||
window.addEventListener('load', loadCrisp, { once: true })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="font-sans text-white">
|
||||
<div class="flex flex-col gap-5">
|
||||
<div class="flex flex-col gap-[10px]">
|
||||
<div
|
||||
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 class="px-4 md:pl-[42px]">
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-x-2 text-sm leading-tight font-bold md:text-4xl"
|
||||
class="flex flex-wrap items-center gap-x-2 text-sm leading-tight font-bold md:text-2xl"
|
||||
>
|
||||
<StartIcon v-if="item.isHot" class="size-[20px] md:size-[30px]" />
|
||||
<span>{{ item.title }}</span>
|
||||
@ -23,11 +23,14 @@
|
||||
|
||||
<!-- 打开按钮 -->
|
||||
<div
|
||||
class="mt-2 flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100"
|
||||
class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100"
|
||||
>
|
||||
<div
|
||||
v-show="activeId !== item.id"
|
||||
class="mt-[16px] flex items-center gap-[10px] md:mt-[60px] md:text-xl"
|
||||
>
|
||||
<div v-show="activeId !== item.id" class="flex items-center gap-[10px] md:text-2xl">
|
||||
<span class="tracking-tight">点击展开详情</span>
|
||||
<ArrowIcon class="size-[12px] md:size-[22px]" />
|
||||
<ArrowIcon class="size-[12px] md:size-[18px]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,30 +39,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"
|
||||
class="flex items-center justify-end gap-1.5 self-end text-sm font-bold group-hover:opacity-100 md:text-xl"
|
||||
>
|
||||
<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" />
|
||||
|
||||
<!-- 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
|
||||
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">
|
||||
<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>
|
||||
<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 +114,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 +159,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 +170,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 +181,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 +193,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>
|
||||
|
||||
|
Before Width: | Height: | Size: 230 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile1/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile1/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile1/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 276 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile2/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile2/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile2/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 311 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile3/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile3/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
src/pages/Help/DownloadMethodList/mobile3/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 305 KiB |
|
Before Width: | Height: | Size: 358 KiB |
|
Before Width: | Height: | Size: 418 KiB |
BIN
src/pages/Help/DownloadMethodList/pc1/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
src/pages/Help/DownloadMethodList/pc1/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
src/pages/Help/DownloadMethodList/pc1/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
src/pages/Help/DownloadMethodList/pc2/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
src/pages/Help/DownloadMethodList/pc2/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
src/pages/Help/DownloadMethodList/pc2/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
src/pages/Help/DownloadMethodList/pc3/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
src/pages/Help/DownloadMethodList/pc3/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
src/pages/Help/DownloadMethodList/pc3/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 192 KiB |
@ -1,50 +1,48 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-black text-white">
|
||||
<!-- Full Width Header -->
|
||||
<div class="h-[88px] md:h-[125px]">
|
||||
<div class="fixed z-50 w-full bg-black pt-[20px] md:pt-[45px]">
|
||||
<div class="h-[88px] md:h-[94px]">
|
||||
<div class="fixed z-50 w-full bg-black pt-[20px] md:pt-[34px]">
|
||||
<div class="container">
|
||||
<header
|
||||
class="flex h-[68px] items-center justify-between rounded-full bg-[#ADFF5B] pr-[30px] pl-6 md:h-[80px] md:pr-[58px] md:pl-[41px]"
|
||||
class="flex h-[68px] items-center justify-between rounded-full bg-[#ADFF5B] pr-[30px] pl-6 md:h-[60px] md:pr-[58px] md:pl-[41px]"
|
||||
>
|
||||
<router-link to="/" class="flex items-center gap-2">
|
||||
<!-- Desktop Logo -->
|
||||
<!-- <Logo :src="Logo" alt="Hi快VPN" class="hidden h-10 w-auto text-black md:block" />-->
|
||||
<!-- Mobile Logo -->
|
||||
<MobileLogo alt="Hi快VPN" class="block h-[28px] text-black md:h-[50px]" />
|
||||
<MobileLogo alt="Hi快VPN" class="block h-[28px] text-black md:h-[36px]" />
|
||||
</router-link>
|
||||
<RightText class="block h-[15px] text-black md:h-[31px]" />
|
||||
<RightText class="block h-[15px] text-black md:h-[24px]" />
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="h-[145px] md:h-[262px]">
|
||||
<div class="h-[125px] md:h-[180px]">
|
||||
<div class="fixed z-50 w-full bg-black">
|
||||
<div class="container pb-[10px] md:px-[12vw]">
|
||||
<div
|
||||
class="pt-[34px] pb-[15px] text-center text-xl font-[900] md:pt-[110px] md:pb-[30px] md:text-3xl"
|
||||
>
|
||||
<div class="m-auto w-[340px] pb-[10px] md:w-[760px]">
|
||||
<div class="pt-[30px] pb-[15px] text-center text-xl font-[900] md:pb-[30px] md:text-2xl">
|
||||
请选择适用您情形的选项
|
||||
</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"
|
||||
>
|
||||
<Button
|
||||
class="w-full cursor-pointer rounded-full bg-[#ADFF5B] text-xs text-black hover:bg-[#ADFF5B]/90 md:h-[60px] md:text-2xl"
|
||||
class="h-[30px] w-full cursor-pointer rounded-full bg-[#ADFF5B] text-xs text-black hover:bg-[#ADFF5B]/90 md:h-[40px] md:text-xl"
|
||||
>
|
||||
我只有中国大陆Apple ID
|
||||
</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"
|
||||
>
|
||||
<Button
|
||||
class="w-full cursor-pointer rounded-full bg-[#ADFF5B] text-xs text-black hover:bg-[#ADFF5B]/90 md:h-[60px] md:text-2xl"
|
||||
class="h-[30px] w-full cursor-pointer rounded-full bg-[#ADFF5B] text-xs text-black hover:bg-[#ADFF5B]/90 md:h-[40px] md:text-xl"
|
||||
>
|
||||
我有海外Apple ID
|
||||
</Button>
|
||||
@ -54,13 +52,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container md:px-[12vw]">
|
||||
<div class="m-auto w-[340px] md:w-[760px]">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<!-- tab1 -->
|
||||
<div v-if="activeIndex === 0" key="tab1">
|
||||
<div
|
||||
class="pt-[34px] pb-[15px] text-center text-xl font-[900] md:pt-[100px] md:pb-[39px] md:text-3xl"
|
||||
>
|
||||
<div class="pt-[15px] pb-[15px] text-center text-xl font-[900] md:pb-[39px] md:text-2xl">
|
||||
Hi快提供三种下载方式
|
||||
</div>
|
||||
<DownloadMethodList />
|
||||
@ -68,7 +64,7 @@
|
||||
<!-- tab2 -->
|
||||
<div v-else-if="activeIndex === 1" key="tab2">
|
||||
<div
|
||||
class="mx-auto flex w-[237px] items-center justify-center pt-[34px] pb-[15px] text-center text-xl font-[900] md:w-full md:gap-[18px] md:pt-[100px] md:text-3xl"
|
||||
class="mx-auto flex w-[237px] items-center justify-center pt-[34px] text-center text-xl font-[900] md:w-full md:gap-[18px] md:text-2xl"
|
||||
>
|
||||
<ChatIcon class="h-[60px] w-[50px]" />登录海外 Apple ID 后再点击下方下载按钮
|
||||
</div>
|
||||
@ -86,7 +82,7 @@
|
||||
</div>
|
||||
|
||||
<div class="container md:px-[92px]">
|
||||
<div class="pt-[56px] pb-[15px] text-center text-xl font-[900] md:pb-[69px] md:text-3xl">
|
||||
<div class="pt-[56px] pb-[15px] text-center text-xl font-[900] md:text-2xl">
|
||||
常见问题与解答
|
||||
</div>
|
||||
<div class="px-[24px]">
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<router-link
|
||||
v-if="item.isInternal"
|
||||
:to="item.link"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform hover:brightness-110 active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
@ -29,7 +29,7 @@
|
||||
v-else
|
||||
:href="item.link"
|
||||
target="_blank"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
class="flex h-[40px] w-[140px] shrink-0 items-center space-x-2 rounded-full transition-transform hover:brightness-110 active:scale-95 md:h-[50px] md:w-[180px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
<button
|
||||
v-else
|
||||
@click="openLoginModal"
|
||||
class="flex h-[48px] items-center justify-center rounded-full bg-[#78788029] px-6 text-sm font-bold backdrop-blur-md transition hover:scale-[0.97] hover:bg-white/30 md:h-[60px] md:w-[220px] md:text-2xl"
|
||||
class="flex h-[48px] cursor-pointer items-center justify-center rounded-full bg-[#78788029] px-6 text-sm font-bold backdrop-blur-md transition hover:brightness-110 md:h-[60px] md:w-[220px] md:text-2xl"
|
||||
>
|
||||
登录 / 注册
|
||||
</button>
|
||||
@ -96,14 +96,14 @@
|
||||
class="mb-5 w-full text-center text-xs leading-5 font-[300] md:ml-[17px] md:text-left md:text-sm"
|
||||
>
|
||||
<p>最新加密协议-安全有保障</p>
|
||||
<p>EPL专线-纯净、稳定</p>
|
||||
<p>IEPL专线-纯净、稳定</p>
|
||||
<p>不限速/不限流-网速多快,Hi快多快</p>
|
||||
<p>极速闪连-永远快人一步</p>
|
||||
<div class="flex justify-center md:justify-start">
|
||||
<a
|
||||
href="https://x.com/hifasttech"
|
||||
target="_blank"
|
||||
class="mt-[12px] flex h-[30px] w-[100px] shrink-0 items-center justify-center space-x-2 rounded-full transition-transform active:scale-95 md:mt-[16px]"
|
||||
class="mt-[12px] flex h-[30px] w-[100px] shrink-0 items-center justify-center space-x-2 rounded-full transition-transform hover:brightness-110 md:mt-[16px]"
|
||||
style="
|
||||
backdrop-filter: blur(36px);
|
||||
box-shadow:
|
||||
@ -132,8 +132,8 @@
|
||||
</div>
|
||||
<div class="text-center text-[10px] leading-[14px] font-[300] md:ml-[17px] md:text-left">
|
||||
<span class="font-[600]">Hi快VPN™</span> © All rights reserved.<br />
|
||||
<a href="#" class="underline">Terms of Service</a>
|
||||
<a href="#" class="ml-2 underline">Privacy Policy</a>
|
||||
<router-link to="/terms-of-service" class="underline">Terms of Service</router-link>
|
||||
<router-link to="/privacy-policy" class="ml-2 underline">Privacy Policy</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -174,7 +174,7 @@ import DownloadButton from './components/DownloadButton.vue'
|
||||
import Logo from './logo.svg?component'
|
||||
import MobileLogo from './mobile-logo.svg?component'
|
||||
import ScreenshotMobile from './screenshot-mobile.png'
|
||||
import ScreenshotDesktop from './screenshot-desktop.png'
|
||||
import ScreenshotDesktop from './screenshot-desktop.webp'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 MiB |
BIN
src/pages/Home/screenshot-desktop.webp
Normal file
|
After Width: | Height: | Size: 149 KiB |
53
src/pages/PrivacyPolicy/index.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-black text-white" style="font-family: 'Roboto', sans-serif">
|
||||
<!-- Main Content -->
|
||||
<main class="mx-auto max-w-[1000px] px-6 md:px-2 md:pt-16 md:pb-[50px]">
|
||||
<!-- Mobile Images -->
|
||||
<div class="md:hidden">
|
||||
<img
|
||||
src="./mobile/row-1-column-1.webp"
|
||||
alt="Terms of Service - Part 1"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
<img
|
||||
src="./mobile/row-2-column-1.webp"
|
||||
alt="Terms of Service - Part 2"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
<img
|
||||
src="./mobile/row-3-column-1.webp"
|
||||
alt="Terms of Service - Part 3"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Images (2x) -->
|
||||
<div class="hidden md:block">
|
||||
<img
|
||||
src="./pc/row1.png"
|
||||
alt="Terms of Service - Part 1"
|
||||
class="mb-10 origin-left scale-50"
|
||||
/>
|
||||
<img
|
||||
src="./pc/row2.png"
|
||||
alt="Terms of Service - Part 2"
|
||||
class="mb-0 w-full"
|
||||
style="width: 100%; height: auto"
|
||||
/>
|
||||
<img
|
||||
src="./pc/row3.png"
|
||||
alt="Terms of Service - Part 3"
|
||||
class="m-auto mt-[60px] h-[28px] w-[594px]"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// No additional logic needed for this static page
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* No additional styles needed */
|
||||
</style>
|
||||
BIN
src/pages/PrivacyPolicy/mobile/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
src/pages/PrivacyPolicy/mobile/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
src/pages/PrivacyPolicy/mobile/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
src/pages/PrivacyPolicy/pc/row1.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
src/pages/PrivacyPolicy/pc/row2.png
Normal file
|
After Width: | Height: | Size: 200 KiB |
BIN
src/pages/PrivacyPolicy/pc/row3.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
49
src/pages/TermsOfService/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-black text-white" style="font-family: 'Roboto', sans-serif">
|
||||
<!-- Main Content -->
|
||||
<main class="mx-auto max-w-[1000px] px-6 md:px-2 md:pt-16 md:pb-[50px]">
|
||||
<!-- Mobile Images -->
|
||||
<div class="md:hidden">
|
||||
<img
|
||||
src="./mobile/row-1-column-1.webp"
|
||||
alt="Terms of Service - Part 1"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
<img
|
||||
src="./mobile/row-2-column-1.webp"
|
||||
alt="Terms of Service - Part 2"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
<img
|
||||
src="./mobile/row-3-column-1.webp"
|
||||
alt="Terms of Service - Part 3"
|
||||
class="mb-0 w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Images (2x) -->
|
||||
<div class="hidden md:block">
|
||||
<img src="./pc/row1.png" alt="Terms of Service - Part 1" class="mb-10 h-[18px] w-[206px]" />
|
||||
<img
|
||||
src="./pc/row2.png"
|
||||
alt="Terms of Service - Part 2"
|
||||
class="mb-0 w-full"
|
||||
style="width: 100%; height: auto"
|
||||
/>
|
||||
<img
|
||||
src="./pc/row3.png"
|
||||
alt="Terms of Service - Part 3"
|
||||
class="m-auto mt-[60px] h-[70px] w-[693px]"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// No additional logic needed for this static page
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* No additional styles needed */
|
||||
</style>
|
||||
BIN
src/pages/TermsOfService/mobile/row-1-column-1.webp
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
src/pages/TermsOfService/mobile/row-2-column-1.webp
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
src/pages/TermsOfService/mobile/row-3-column-1.webp
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
src/pages/TermsOfService/pc/row1.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/pages/TermsOfService/pc/row2.png
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
src/pages/TermsOfService/pc/row3.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
@ -18,6 +18,16 @@ const router = createRouter({
|
||||
name: 'user-center',
|
||||
component: () => import('../pages/UserCenter/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/terms-of-service',
|
||||
name: 'terms-of-service',
|
||||
component: () => import('../pages/TermsOfService/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/privacy-policy',
|
||||
name: 'privacy-policy',
|
||||
component: () => import('../pages/PrivacyPolicy/index.vue'),
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('/src/styles/roboto.woff2') format('woff2');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@layer utilities {
|
||||
|
||||