- 提取首页和用户中心共享 Header,统一移动端与桌面端尺寸及登录状态展示 - 调整首页首屏视频、标语和产品图的响应式排列,并适配视频播放弹窗 - 新增移动端合伙人权益图片,优化产品卡片和轮播区域的自适应尺寸 - 修复轮播左右箭头缩放显示,并保持桌面端与线上页面一致 - 统一移动端公共容器左右 24px 留白
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="h-[60px] md:h-[125px]">
|
||||
<div class="fixed top-[20px] z-50 w-full md:top-[45px]">
|
||||
<div class="container">
|
||||
<header
|
||||
class="lucid-glass-bar flex h-[40px] items-center justify-between rounded-[90px] p-[4px] transition-all duration-300 md:h-[60px]"
|
||||
>
|
||||
<router-link
|
||||
to="/"
|
||||
class="ml-[clamp(0.25rem,2vw,0.625rem)] flex min-w-0 items-center gap-[clamp(0.25rem,1vw,0.5rem)] whitespace-nowrap md:ml-[47px]"
|
||||
>
|
||||
<Logo
|
||||
alt="Hi快VPN"
|
||||
class="h-[clamp(0.875rem,4vw,1.125rem)] w-auto shrink-0 md:h-[29px]"
|
||||
/>
|
||||
<span
|
||||
class="text-[clamp(0.875rem,4.25vw,1.5rem)] leading-none font-black whitespace-nowrap md:ml-3 md:text-2xl"
|
||||
>
|
||||
高能合伙人
|
||||
</span>
|
||||
</router-link>
|
||||
|
||||
<router-link
|
||||
v-if="isLoggedIn"
|
||||
to="/user-center"
|
||||
aria-label="进入用户中心"
|
||||
class="flex size-[30px] shrink-0 items-center justify-center rounded-full bg-[#78788029] text-xl font-bold text-white shadow-lg transition hover:scale-105 md:size-[40px] md:text-3xl"
|
||||
>
|
||||
{{ userLetter }}
|
||||
</router-link>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="flex h-[30px] shrink-0 cursor-pointer items-center justify-center rounded-full bg-[#78788029] px-[clamp(0.625rem,3vw,1.5rem)] text-[clamp(0.75rem,3.2vw,0.875rem)] leading-none font-bold whitespace-nowrap backdrop-blur-md transition hover:brightness-110 md:h-[50px] md:w-[220px] md:px-6 md:text-xl"
|
||||
@click="openLoginModal"
|
||||
>
|
||||
登录/注册
|
||||
</button>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LoginFormModal ref="loginModalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import LoginFormModal from '@/pages/Home/components/LoginFormModal.vue'
|
||||
import Logo from '@/pages/Home/logo.svg?component'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const token = useLocalStorage('Authorization', '')
|
||||
const userEmail = useLocalStorage('UserEmail', '')
|
||||
const loginModalRef = ref<InstanceType<typeof LoginFormModal> | null>(null)
|
||||
|
||||
interface UserInfoResponse {
|
||||
auth_methods?: Array<{
|
||||
auth_type?: string
|
||||
auth_identifier?: string
|
||||
}>
|
||||
}
|
||||
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const userLetter = computed(() => userEmail.value?.charAt(0).toUpperCase() || '?')
|
||||
|
||||
const openLoginModal = () => {
|
||||
loginModalRef.value?.show()
|
||||
}
|
||||
|
||||
const handleLoginQuery = () => {
|
||||
if (route.query.login !== 'true') return
|
||||
|
||||
openLoginModal()
|
||||
router.replace({ query: { ...route.query, login: undefined } })
|
||||
}
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
if (route.path !== '/' || !token.value) return
|
||||
|
||||
try {
|
||||
const res = (await request.get('/api/v1/public/user/info')) as UserInfoResponse
|
||||
const emailInfo = res.auth_methods?.find((item) => item.auth_type === 'email')
|
||||
if (emailInfo?.auth_identifier) userEmail.value = emailInfo.auth_identifier
|
||||
} catch (error: unknown) {
|
||||
console.error('Failed to fetch user info:', error)
|
||||
const status =
|
||||
typeof error === 'object' && error !== null
|
||||
? (error as { code?: number; status?: number })
|
||||
: {}
|
||||
if (status.code === 401 || status.status === 401) {
|
||||
token.value = ''
|
||||
userEmail.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchUserInfo()
|
||||
handleLoginQuery()
|
||||
})
|
||||
|
||||
watch(() => route.query.login, handleLoginQuery)
|
||||
</script>
|
||||
+227
-118
@@ -2,55 +2,37 @@
|
||||
<div
|
||||
class="relative min-h-screen overflow-hidden bg-black bg-cover bg-center bg-no-repeat pb-[calc(4rem+env(safe-area-inset-bottom))] font-sans text-white md:flex md:flex-col"
|
||||
>
|
||||
<!-- Full Width Header -->
|
||||
<div class="h-[60px] md:h-[125px]">
|
||||
<div class="fixed top-[20px] z-50 w-full md:top-[45px]">
|
||||
<div class="container">
|
||||
<header
|
||||
class="lucid-glass-bar flex h-[40px] items-center justify-between rounded-[90px] pr-[5px] pl-5 transition-all duration-300 md:h-[60px] md:pr-[10px]"
|
||||
>
|
||||
<router-link to="/" class="flex items-center gap-2">
|
||||
<!-- Desktop Logo -->
|
||||
<Logo alt="Hi快VPN" class="h-[18px] w-auto md:ml-8 md:h-[29px]" />
|
||||
<span class="ml-3 text-2xl font-black">高能合伙人</span>
|
||||
</router-link>
|
||||
<div v-if="isLoggedIn" class="flex items-center">
|
||||
<router-link
|
||||
to="/user-center"
|
||||
class="flex size-[30px] items-center justify-center rounded-full bg-[#78788029] text-xl font-bold text-white shadow-lg transition hover:scale-105 md:size-[40px] md:text-3xl"
|
||||
>
|
||||
{{ userLetter }}
|
||||
</router-link>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
@click="openLoginModal"
|
||||
class="flex h-[30px] 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-[40px] md:w-[220px] md:text-xl"
|
||||
>
|
||||
代理后台登录/注册
|
||||
</button>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AppHeader />
|
||||
|
||||
<!-- Main Content Container -->
|
||||
<div class="container mx-auto flex max-w-[1220px] flex-col">
|
||||
<main class="pt-10">
|
||||
<!-- module0 -->
|
||||
<div class="mb-[80px] flex justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="mb-[20px] ml-[42px] md:ml-[17px]">
|
||||
<div class="home-hero mb-[80px] flex flex-col justify-between md:flex-row">
|
||||
<div
|
||||
class="flex w-full items-center justify-between gap-4 md:w-auto md:flex-col md:justify-start md:gap-0"
|
||||
>
|
||||
<div class="min-w-0 md:mb-[20px] md:ml-[17px]">
|
||||
<h2 class="mb-2 text-2xl font-black md:text-8xl">
|
||||
<Logo class="h-[34px] md:h-[43px]" />
|
||||
</h2>
|
||||
<p class="font-600 text-3xl">网在我在, 网快我快</p>
|
||||
<p
|
||||
class="font-600 text-[clamp(1.25rem,7vw,1.875rem)] leading-tight md:text-3xl md:leading-9"
|
||||
>
|
||||
网在我在, 网快我快
|
||||
</p>
|
||||
</div>
|
||||
<img src="./Group%20133.png" alt="" class="mt-[52px] h-[287px] w-[182px]" />
|
||||
<img
|
||||
src="./Group%20133.png"
|
||||
alt="Hi快VPN 手机应用"
|
||||
class="home-hero__product w-auto shrink-0"
|
||||
/>
|
||||
</div>
|
||||
<!-- video -->
|
||||
<div
|
||||
class="max-w-[800px] flex-1 cursor-pointer overflow-hidden rounded-[40px] transition duration-300 hover:scale-[1.02]"
|
||||
<button
|
||||
type="button"
|
||||
aria-label="播放介绍视频"
|
||||
class="block aspect-video w-full max-w-[800px] flex-1 cursor-pointer overflow-hidden rounded-[clamp(1.25rem,5vw,2.5rem)] p-0 text-left transition duration-300 hover:scale-[1.02]"
|
||||
@click="openVideoModal"
|
||||
>
|
||||
<img
|
||||
@@ -58,14 +40,29 @@
|
||||
class="h-full w-full object-cover object-center"
|
||||
alt="Video Cover"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<!-- modules1 -->
|
||||
<div class="mb-[80px] w-full">
|
||||
<img src="./modules1/Group%20235.png" alt="邀请规则" class="mx-auto w-[1024px]" />
|
||||
<img
|
||||
src="./modules1/module2-mobile.png"
|
||||
alt="高能合伙人权益"
|
||||
class="mx-auto h-auto w-full md:hidden"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<img
|
||||
src="./modules1/Group%20235.png"
|
||||
alt="高能合伙人权益"
|
||||
class="mx-auto hidden h-auto w-full max-w-[1024px] md:block"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<!-- modules2 -->
|
||||
<div class="mb-[80px] w-full rounded-[40px] bg-[#ADFF5B] p-8 pb-2 text-black">
|
||||
<div
|
||||
class="mb-[80px] w-full rounded-[40px] bg-[#ADFF5B] px-[clamp(1rem,5vw,2rem)] pt-8 pb-2 text-black md:p-8 md:pb-2"
|
||||
>
|
||||
<div class="text-center text-4xl font-black">“超强产品力,全面秒杀同级app”</div>
|
||||
<div class="mt-2 text-center">为高能合伙人提供强力的的产品背书,每个点拿出去都能打。</div>
|
||||
<div class="el-style-scrollbar mt-8 flex gap-2 overflow-x-auto pb-4">
|
||||
@@ -78,31 +75,44 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- modules3 -->
|
||||
<div class="mb-[40px] w-full rounded-[40px] pb-2 text-black">
|
||||
<div class="text-center text-4xl font-black">
|
||||
<Group215Icon class="mx-auto" />
|
||||
<!-- modules3 + modules4 -->
|
||||
<section class="home-showcase text-black" aria-labelledby="home-showcase-description">
|
||||
<div class="home-showcase__heading text-center">
|
||||
<Group215Icon class="home-showcase__title mx-auto h-auto w-full" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="text-center text-[#999999]">给您的客户提供专业视角的建议</div>
|
||||
<div class="mt-[20px] flex justify-center">
|
||||
<Carousel class="relative w-full max-w-[700px]" :opts="{ loop: true }">
|
||||
<div class="size-[700px] overflow-hidden rounded-[40px]">
|
||||
<p id="home-showcase-description" class="home-showcase__description text-center">
|
||||
给您的客户提供专业视角的建议
|
||||
</p>
|
||||
<div class="home-showcase__content flex justify-center">
|
||||
<Carousel
|
||||
class="home-showcase__carousel relative w-full"
|
||||
:opts="{ loop: true }"
|
||||
aria-label="产品优势展示"
|
||||
>
|
||||
<div class="home-showcase__viewport aspect-square w-full overflow-hidden">
|
||||
<CarouselContent>
|
||||
<CarouselItem v-for="(img, index) in modules4Images" :key="index">
|
||||
<img
|
||||
:src="img"
|
||||
alt=""
|
||||
class="h-[700px] w-[700px] object-cover select-none"
|
||||
:alt="`产品优势展示 ${index + 1}`"
|
||||
class="aspect-square h-auto w-full object-cover select-none"
|
||||
draggable="false"
|
||||
loading="lazy"
|
||||
/>
|
||||
</CarouselItem>
|
||||
</CarouselContent>
|
||||
</div>
|
||||
<CarouselPrevious class="-left-[100px]" />
|
||||
<CarouselNext class="-right-[100px]" />
|
||||
<CarouselPrevious
|
||||
class="home-showcase__nav home-showcase__nav--previous"
|
||||
aria-label="上一张"
|
||||
/>
|
||||
<CarouselNext
|
||||
class="home-showcase__nav home-showcase__nav--next"
|
||||
aria-label="下一张"
|
||||
/>
|
||||
</Carousel>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
<div class="container flex flex-col items-center justify-center">
|
||||
@@ -115,19 +125,19 @@
|
||||
<router-link to="/privacy" class="ml-2 underline">Privacy Policy</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<LoginFormModal ref="loginModalRef" />
|
||||
|
||||
<!-- Video Modal -->
|
||||
<Dialog
|
||||
v-model:open="videoModalVisible"
|
||||
@update:open="(val) => !val && handleVideoModalClose()"
|
||||
>
|
||||
<DialogContent class="max-w-[60vw]! overflow-hidden rounded-2xl border-none bg-black/90 p-0">
|
||||
<div class="relative w-full pt-[56.25%]">
|
||||
<DialogContent
|
||||
class="home-video-dialog overflow-hidden border-none bg-black/90 p-0 shadow-2xl"
|
||||
>
|
||||
<div class="aspect-video w-full overflow-hidden rounded-[inherit] bg-black">
|
||||
<video
|
||||
ref="videoRef"
|
||||
src="/fast-video.MP4"
|
||||
class="absolute inset-0 h-full w-full"
|
||||
class="block h-full w-full object-contain"
|
||||
controls
|
||||
autoplay
|
||||
></video>
|
||||
@@ -138,10 +148,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import LoginFormModal from './components/LoginFormModal.vue'
|
||||
import { ref } from 'vue'
|
||||
import AppHeader from '@/components/layout/AppHeader.vue'
|
||||
import Logo from './logo.svg?component'
|
||||
import Group215Icon from './modules3/Group 215.svg?component'
|
||||
import {
|
||||
@@ -152,7 +160,6 @@ import {
|
||||
CarouselPrevious,
|
||||
} from '@/components/ui/carousel'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
import request from '@/utils/request'
|
||||
import Frame98 from './modules2/Frame 98.png'
|
||||
import Frame99 from './modules2/Frame 99.png'
|
||||
import Frame100 from './modules2/Frame 100.png'
|
||||
@@ -183,59 +190,161 @@ const handleVideoModalClose = () => {
|
||||
videoRef.value.currentTime = 0
|
||||
}
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const token = useLocalStorage('Authorization', '')
|
||||
const userEmail = useLocalStorage('UserEmail', '')
|
||||
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const userLetter = computed(() => {
|
||||
if (!userEmail.value) return '?'
|
||||
return userEmail.value.charAt(0).toUpperCase()
|
||||
})
|
||||
|
||||
const fetchUserInfo = async () => {
|
||||
if (!token.value) return
|
||||
|
||||
try {
|
||||
const res = (await request.get('/api/v1/public/user/info')) as any
|
||||
const emailInfo = res.auth_methods?.find((item: any) => item.auth_type === 'email')
|
||||
if (emailInfo) {
|
||||
userEmail.value = emailInfo.auth_identifier
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Failed to fetch user info:', error)
|
||||
if (error?.code === 401 || error?.status === 401) {
|
||||
token.value = ''
|
||||
userEmail.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchUserInfo()
|
||||
if (route.query.login === 'true') {
|
||||
openLoginModal()
|
||||
router.replace({ query: { ...route.query, login: undefined } })
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.query.login,
|
||||
(newVal) => {
|
||||
if (newVal === 'true') {
|
||||
openLoginModal()
|
||||
router.replace({ query: { ...route.query, login: undefined } })
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const loginModalRef = ref<InstanceType<typeof LoginFormModal> | null>(null)
|
||||
|
||||
const openLoginModal = () => {
|
||||
loginModalRef.value?.show()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.home-hero {
|
||||
gap: clamp(1.5rem, 6vw, 2.5rem);
|
||||
}
|
||||
|
||||
.home-hero__product {
|
||||
block-size: clamp(4rem, 18.133vw, 4.25rem);
|
||||
}
|
||||
|
||||
.home-video-dialog {
|
||||
inline-size: min(
|
||||
calc(100vw - 2rem - env(safe-area-inset-left) - env(safe-area-inset-right)),
|
||||
calc((100dvh - 4rem - env(safe-area-inset-top) - env(safe-area-inset-bottom)) * 16 / 9)
|
||||
) !important;
|
||||
max-inline-size: none !important;
|
||||
border-radius: clamp(0.75rem, 4vw, 1rem);
|
||||
}
|
||||
|
||||
:deep(.home-video-dialog [data-slot='dialog-close']) {
|
||||
top: clamp(0.375rem, 2vw, 0.75rem);
|
||||
right: clamp(0.375rem, 2vw, 0.75rem);
|
||||
z-index: 10;
|
||||
display: grid;
|
||||
inline-size: 2.75rem;
|
||||
block-size: 2.75rem;
|
||||
place-items: center;
|
||||
border-radius: 999px;
|
||||
color: white;
|
||||
background: rgb(0 0 0 / 55%);
|
||||
}
|
||||
|
||||
:deep(.home-video-dialog [data-slot='dialog-close'] svg) {
|
||||
inline-size: 1.25rem;
|
||||
block-size: 1.25rem;
|
||||
}
|
||||
|
||||
@media (width >= 48rem) {
|
||||
.home-hero {
|
||||
gap: clamp(2rem, 4vw, 4rem);
|
||||
}
|
||||
|
||||
.home-hero__product {
|
||||
inline-size: 11.375rem;
|
||||
block-size: 17.9375rem;
|
||||
margin-block-start: 3.25rem;
|
||||
}
|
||||
|
||||
.home-video-dialog {
|
||||
inline-size: min(
|
||||
60vw,
|
||||
calc((100dvh - 4rem - env(safe-area-inset-top) - env(safe-area-inset-bottom)) * 16 / 9)
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.home-showcase {
|
||||
inline-size: min(100%, calc(100vw - 2.25rem));
|
||||
margin-block-end: clamp(2rem, 5vw, 4rem);
|
||||
padding-block-end: clamp(0.5rem, 1.5vw, 1rem);
|
||||
border-radius: clamp(1.25rem, 4vw, 2.5rem);
|
||||
}
|
||||
|
||||
.home-showcase__heading {
|
||||
padding-inline: clamp(0.25rem, 2vw, 1rem);
|
||||
}
|
||||
|
||||
.home-showcase__title {
|
||||
max-inline-size: min(20.625rem, 100%);
|
||||
}
|
||||
|
||||
.home-showcase__description {
|
||||
margin-block-start: clamp(0.5rem, 1.5vw, 0.875rem);
|
||||
padding-inline: clamp(0.75rem, 3vw, 1.5rem);
|
||||
color: #999;
|
||||
font-size: clamp(1rem, 2.5vw, 1.125rem);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.home-showcase__content {
|
||||
margin-block-start: clamp(1rem, 3vw, 1.75rem);
|
||||
}
|
||||
|
||||
.home-showcase__carousel {
|
||||
max-inline-size: min(43.75rem, 100%, 85dvh);
|
||||
touch-action: pan-y pinch-zoom;
|
||||
}
|
||||
|
||||
.home-showcase__viewport {
|
||||
border-radius: clamp(1.25rem, 5vw, 2.5rem);
|
||||
}
|
||||
|
||||
.home-showcase__nav {
|
||||
display: grid;
|
||||
inline-size: clamp(2.75rem, 10vw, 4rem);
|
||||
block-size: clamp(2.75rem, 10vw, 4rem);
|
||||
place-items: center;
|
||||
border: 1px solid rgb(255 255 255 / 35%);
|
||||
border-radius: 999px;
|
||||
background: rgb(0 0 0 / 48%);
|
||||
backdrop-filter: blur(0.5rem);
|
||||
transition:
|
||||
background-color 180ms ease,
|
||||
opacity 180ms ease;
|
||||
}
|
||||
|
||||
.home-showcase__nav:hover,
|
||||
.home-showcase__nav:focus-visible {
|
||||
background: rgb(0 0 0 / 68%);
|
||||
}
|
||||
|
||||
.home-showcase__nav:focus-visible {
|
||||
outline: 2px solid white;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.home-showcase__nav--previous {
|
||||
left: clamp(0.5rem, 2.5vw, 1rem);
|
||||
}
|
||||
|
||||
.home-showcase__nav--next {
|
||||
right: clamp(0.5rem, 2.5vw, 1rem);
|
||||
}
|
||||
|
||||
.home-showcase__nav :deep(svg) {
|
||||
inline-size: auto;
|
||||
block-size: clamp(1.75rem, 7vw, 2.5rem);
|
||||
max-inline-size: 100%;
|
||||
}
|
||||
|
||||
@media (width >= 64rem) {
|
||||
.home-showcase__nav {
|
||||
border-color: transparent;
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
|
||||
.home-showcase__nav--previous {
|
||||
left: clamp(-6.25rem, -7vw, -4rem);
|
||||
}
|
||||
|
||||
.home-showcase__nav--next {
|
||||
right: clamp(-6.25rem, -7vw, -4rem);
|
||||
}
|
||||
|
||||
.home-showcase__nav :deep(svg) {
|
||||
inline-size: auto;
|
||||
block-size: clamp(4rem, 8vw, 7.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.home-showcase__nav {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg width="48" height="120" viewBox="0 0 48 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg viewBox="0 0 48 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 59.9033L37.5049 0L47.4883 4.35156L12.8008 59.9033L47.4883 115.456L37.5049 119.808L0 59.9033Z" fill="#ADFF5B"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 204 B |
@@ -1,35 +1,6 @@
|
||||
<template>
|
||||
<div class="flex min-h-screen flex-col bg-black text-white">
|
||||
<!-- Full Width Header -->
|
||||
<div class="h-[60px] md:h-[125px]">
|
||||
<div class="fixed top-[20px] z-50 w-full md:top-[45px]">
|
||||
<div class="container">
|
||||
<header
|
||||
class="lucid-glass-bar flex h-[40px] items-center justify-between rounded-[90px] pr-[5px] pl-5 transition-all duration-300 md:h-[60px] md:pr-[10px]"
|
||||
>
|
||||
<router-link to="/" class="flex items-center gap-2">
|
||||
<!-- Desktop Logo -->
|
||||
<Logo alt="Hi快VPN" class="h-[18px] w-auto md:ml-8 md:h-[29px]" />
|
||||
<span class="ml-3 text-2xl font-black">高能合伙人</span>
|
||||
</router-link>
|
||||
<div v-if="isLoggedIn" class="flex items-center">
|
||||
<router-link
|
||||
to="/user-center"
|
||||
class="flex size-[30px] items-center justify-center rounded-full bg-[#78788029] text-xl font-bold text-white shadow-lg transition hover:scale-105 md:size-[40px] md:text-3xl"
|
||||
>
|
||||
{{ userLetter }}
|
||||
</router-link>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
class="flex h-[30px] 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-[40px] md:w-[220px] md:text-xl"
|
||||
>
|
||||
代理后台登录/注册
|
||||
</button>
|
||||
</header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AppHeader />
|
||||
<div class="flex flex-1 flex-col">
|
||||
<!-- Main Neon Green Card -->
|
||||
<!-- <div class="container md:hidden">
|
||||
@@ -45,21 +16,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import AppHeader from '@/components/layout/AppHeader.vue'
|
||||
import DesktopLayout from './DesktopLayout/index.vue'
|
||||
import Logo from '@/pages/Home/logo.svg?component'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
|
||||
const token = useLocalStorage('Authorization', '')
|
||||
const userEmail = useLocalStorage('UserEmail', '')
|
||||
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const userLetter = computed(() => {
|
||||
if (!userEmail.value) return '?'
|
||||
return userEmail.value.charAt(0).toUpperCase()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
<style scoped></style>
|
||||
|
||||
@@ -53,9 +53,9 @@ html, body {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
/* 1. 移动端默认:左右 18px 边距 */
|
||||
padding-left: 18px;
|
||||
padding-right: 18px;
|
||||
/* 1. 移动端默认:左右保持相同的 24px 边距 */
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
|
||||
/* 2. 桌面端逻辑:当屏幕达到 1440px 及以上 */
|
||||
@media (width >= 1440px) {
|
||||
|
||||
Reference in New Issue
Block a user