官网开发中 0803
This commit is contained in:
@@ -75,8 +75,8 @@ function closeMobile() {
|
||||
:class="useTransparent ? 'bg-transparent' : 'bg-white/80 backdrop-blur-md border-b border-gray-100 dark:bg-dark-900/80 dark:border-dark-700'"
|
||||
>
|
||||
<div class="section-container h-64px flex items-center justify-between">
|
||||
<!-- Logo -->
|
||||
<NuxtLink :to="switchLocalePath(locale)" class="flex items-center gap-8px shrink-0" @click="closeMobile">
|
||||
<!-- Logo:点击返回首页 -->
|
||||
<NuxtLink :to="localePath('/')" class="flex items-center gap-8px shrink-0" @click="closeMobile">
|
||||
<img v-if="logoUrl" :src="logoUrl" :alt="site?.site_title || 'Luxsin'" class="h-32px w-auto" />
|
||||
<span
|
||||
v-else
|
||||
@@ -99,7 +99,7 @@ function closeMobile() {
|
||||
>
|
||||
<NuxtLink
|
||||
:to="resolveLink(item.link)"
|
||||
class="text-sm font-medium transition-colors flex items-center gap-4px"
|
||||
class="text-base font-medium transition-colors flex items-center gap-4px"
|
||||
:class="lightText ? 'text-white/90 hover:text-white' : 'text-gray-700 hover:text-primary dark:text-gray-200'"
|
||||
>
|
||||
{{ siteStore.navLabel(item) }}
|
||||
@@ -147,7 +147,7 @@ function closeMobile() {
|
||||
v-else-if="isExternal(item.link)"
|
||||
:href="item.link"
|
||||
:target="item.open_new_tab ? '_blank' : undefined"
|
||||
class="text-sm font-medium transition-colors"
|
||||
class="text-base font-medium transition-colors"
|
||||
:class="lightText ? 'text-white/90 hover:text-white' : 'text-gray-700 hover:text-primary dark:text-gray-200'"
|
||||
>
|
||||
{{ siteStore.navLabel(item) }}
|
||||
@@ -158,7 +158,7 @@ function closeMobile() {
|
||||
v-else
|
||||
:to="resolveLink(item.link)"
|
||||
:target="item.open_new_tab ? '_blank' : undefined"
|
||||
class="text-sm font-medium transition-colors"
|
||||
class="text-base font-medium transition-colors"
|
||||
:class="lightText ? 'text-white/90 hover:text-white' : 'text-gray-700 hover:text-primary dark:text-gray-200'"
|
||||
>
|
||||
{{ siteStore.navLabel(item) }}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 内页 Hero 公共区:overline + 标题 + 副标题 + 可选背景图
|
||||
*
|
||||
* 非首页导航栏为 glass 风格(深色文字),因此无背景图时使用深色文字,
|
||||
* 有背景图时叠加半透明遮罩并使用白色文字。
|
||||
*/
|
||||
defineProps<{
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
overline?: string;
|
||||
bgUrl?: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="relative overflow-hidden">
|
||||
<!-- 背景图 + 遮罩 -->
|
||||
<div v-if="bgUrl" class="absolute inset-0 bg-cover bg-center" :style="{ backgroundImage: `url(${bgUrl})` }" />
|
||||
<div v-if="bgUrl" class="absolute inset-0 bg-black/45" />
|
||||
|
||||
<!-- 内容 -->
|
||||
<div
|
||||
class="section-container relative flex flex-col items-center text-center gap-16px py-72px md:py-96px"
|
||||
:class="bgUrl ? 'text-white' : 'text-gray-900 dark:text-white'"
|
||||
>
|
||||
<p v-if="overline" class="text-sm tracking-[0.35em] uppercase opacity-80 font-medium">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h1 class="text-3xl md:text-5xl font-bold leading-tight">{{ title }}</h1>
|
||||
<p v-if="subtitle" class="max-w-680px text-base md:text-lg opacity-90 leading-relaxed">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, config, isEn, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, config, isEn, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
const features = computed(() => config.value.features ?? []);
|
||||
</script>
|
||||
@@ -12,13 +12,13 @@ const features = computed(() => config.value.features ?? []);
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-56px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -32,10 +32,10 @@ const features = computed(() => config.value.features ?? []);
|
||||
:class="isDark ? 'bg-white/5 border border-white/10' : 'bg-white border border-gray-100 shadow-sm hover:shadow-md dark:bg-dark-800 dark:border-dark-700'"
|
||||
>
|
||||
<span v-if="feature.icon" class="text-3xl">{{ feature.icon }}</span>
|
||||
<h3 class="mt-16px text-lg font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h3 class="mt-16px text-lg font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ isEn ? feature.title_en : feature.title_zh }}
|
||||
</h3>
|
||||
<p class="mt-8px text-sm leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p class="mt-8px text-sm leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ isEn ? feature.desc_en : feature.desc_zh }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,21 +3,21 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, content } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, content, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="section-container py-120px flex-col-center text-center max-w-800px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="section.theme === 'dark' ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="section.theme === 'dark' ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-16px text-3xl md:text-5xl font-bold leading-tight" :class="section.theme === 'dark' ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-16px text-3xl md:text-5xl font-bold leading-tight" :class="section.theme === 'dark' ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-20px text-lg md:text-xl" :class="section.theme === 'dark' ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'">
|
||||
<p v-if="subtitle" class="mt-20px text-lg md:text-xl" :class="section.theme === 'dark' ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
<div v-if="content" class="mt-16px text-15px leading-relaxed" :class="section.theme === 'dark' ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" v-html="content" />
|
||||
<div v-if="content" class="mt-16px text-15px leading-relaxed" :class="section.theme === 'dark' ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle" v-html="content" />
|
||||
<SectionCta :section="section" class="mt-32px justify-center" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, config, isEn, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, config, isEn, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
const images = computed(() => config.value.images ?? []);
|
||||
</script>
|
||||
@@ -12,13 +12,13 @@ const images = computed(() => config.value.images ?? []);
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-56px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,28 +3,57 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, content, mediaUrl, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, content, mediaUrl, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
// 九宫格文案位置(config.text_position,默认左中):top/middle/bottom + left/center/right
|
||||
const textPosition = computed(() => (props.section.config as Record<string, string> | null)?.text_position ?? 'middle_left');
|
||||
|
||||
// 垂直对齐(flex-col 主轴):top->start / middle->center / bottom->end
|
||||
const vAlign = computed(() => ({
|
||||
top: 'justify-start',
|
||||
middle: 'justify-center',
|
||||
bottom: 'justify-end'
|
||||
} as Record<string, string>)[textPosition.value.split('_')[0] ?? ''] ?? 'justify-center');
|
||||
|
||||
// 水平对齐(flex-col 交叉轴):left->start / center->center / right->end
|
||||
const hAlign = computed(() => ({
|
||||
left: 'items-start',
|
||||
center: 'items-center',
|
||||
right: 'items-end'
|
||||
} as Record<string, string>)[textPosition.value.split('_')[1] ?? ''] ?? 'items-start');
|
||||
|
||||
// 水平内边距:左列贴左、右列贴右、中列居中留白
|
||||
const hPad = computed(() => ({
|
||||
left: 'md:pl-128px md:pr-96px',
|
||||
center: 'md:px-64px',
|
||||
right: 'md:pl-96px md:pr-128px'
|
||||
} as Record<string, string>)[textPosition.value.split('_')[1] ?? ''] ?? 'md:px-64px');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="section-container aspect-[2/3] md:aspect-auto md:min-h-[min(calc(92vh-64px),54vw)] grid md:grid-cols-2 gap-48px items-center">
|
||||
<!-- 左侧文案 -->
|
||||
<div class="flex flex-col gap-20px self-center md:min-h-[680px]">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="text-3xl md:text-5xl font-bold leading-tight" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="text-lg md:text-xl" :class="isDark ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
<div v-if="content" class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" v-html="content" />
|
||||
<SectionCta :section="section" class="mt-8px" />
|
||||
<div class="relative aspect-[2/3] md:aspect-auto md:min-h-[max(680px,min(calc(92vh-64px),54vw))] grid gap-48px px-16px md:px-0">
|
||||
<!-- 文案块:移动端文档流;桌面端全宽绝对定位 + 九宫格对齐 -->
|
||||
<div
|
||||
class="relative z-10 flex flex-col gap-20px py-64px md:py-64px md:absolute md:inset-0"
|
||||
:class="[vAlign, hAlign, hPad]"
|
||||
>
|
||||
<div class="flex flex-col gap-20px max-w-560px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="text-3xl md:text-5xl font-bold leading-tight" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="text-lg md:text-xl" :class="isDark ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
<div v-if="content" class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle" v-html="content" />
|
||||
<SectionCta :section="section" class="mt-8px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧图片 -->
|
||||
<div v-if="mediaUrl" class="flex-center">
|
||||
<!-- 图片:移动端文档流;桌面端占右侧一半 -->
|
||||
<div v-if="mediaUrl" class="flex-center md:absolute md:top-0 md:right-0 md:bottom-0 md:w-1/2">
|
||||
<img :src="mediaUrl" :alt="title" class="w-full max-w-560px rounded-16px object-cover shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
// 引言评价:正文 content 作为引用语,subtitle 作为作者/出处
|
||||
const { content, subtitle, isDark } = useSectionContent(props.section);
|
||||
const { content, subtitle, isDark, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -13,9 +13,10 @@ const { content, subtitle, isDark } = useSectionContent(props.section);
|
||||
<blockquote
|
||||
class="mt-8px text-2xl md:text-3xl font-medium leading-relaxed"
|
||||
:class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'"
|
||||
:style="titleStyle"
|
||||
v-html="content"
|
||||
/>
|
||||
<p v-if="subtitle" class="mt-24px text-sm tracking-wide" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-24px text-sm tracking-wide" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
—— {{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, config, isEn, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, config, isEn, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
const steps = computed(() => config.value.steps ?? []);
|
||||
</script>
|
||||
@@ -12,13 +12,13 @@ const steps = computed(() => config.value.steps ?? []);
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-64px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -35,10 +35,10 @@ const steps = computed(() => config.value.steps ?? []);
|
||||
<span class="text-4xl font-bold opacity-20" :class="isDark ? 'text-white' : 'text-gray-900'">
|
||||
{{ String(idx + 1).padStart(2, '0') }}
|
||||
</span>
|
||||
<h3 class="text-xl font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h3 class="text-xl font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ isEn ? step.title_en : step.title_zh }}
|
||||
</h3>
|
||||
<p class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ isEn ? step.desc_en : step.desc_zh }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock, SpecGroup } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, isEn, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, isEn, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
const specGroups = computed<SpecGroup[]>(() => props.section.spec_groups ?? []);
|
||||
|
||||
@@ -35,13 +35,13 @@ function needToggle(group: SpecGroup): boolean {
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-56px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -56,7 +56,7 @@ function needToggle(group: SpecGroup): boolean {
|
||||
>
|
||||
<!-- 分组标题 -->
|
||||
<div class="px-32px py-20px border-b" :class="isDark ? 'border-white/10' : 'border-gray-100 dark:border-dark-700'">
|
||||
<h3 class="text-lg font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h3 class="text-lg font-semibold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ isEn ? group.title_en : group.title_zh }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, content, mediaUrl, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, content, mediaUrl, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,16 +15,16 @@ const { overline, title, subtitle, content, mediaUrl, isDark } = useSectionConte
|
||||
|
||||
<!-- 文案 -->
|
||||
<div class="flex flex-col gap-20px order-1 md:order-2">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="text-3xl md:text-4xl font-bold leading-tight" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="text-3xl md:text-4xl font-bold leading-tight" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="text-lg" :class="isDark ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'">
|
||||
<p v-if="subtitle" class="text-lg" :class="isDark ? 'text-gray-300' : 'text-gray-600 dark:text-gray-300'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
<div v-if="content" class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" v-html="content" />
|
||||
<div v-if="content" class="text-15px leading-relaxed" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle" v-html="content" />
|
||||
<SectionCta :section="section" class="mt-8px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, config, isEn, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, config, isEn, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
const stats = computed(() => config.value.stats ?? []);
|
||||
</script>
|
||||
@@ -12,13 +12,13 @@ const stats = computed(() => config.value.stats ?? []);
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-64px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -26,10 +26,10 @@ const stats = computed(() => config.value.stats ?? []);
|
||||
<!-- 数据统计 -->
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-32px">
|
||||
<div v-for="(stat, idx) in stats" :key="idx" class="flex-col-center text-center">
|
||||
<p class="text-4xl md:text-5xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<p class="text-4xl md:text-5xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ stat.value }}<span class="text-2xl md:text-3xl ml-4px opacity-70">{{ stat.unit }}</span>
|
||||
</p>
|
||||
<p class="mt-12px text-sm" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p class="mt-12px text-sm" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ isEn ? stat.label_en : stat.label_zh }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { SectionBlock } from '~/types/site';
|
||||
|
||||
const props = defineProps<{ section: SectionBlock }>();
|
||||
|
||||
const { overline, title, subtitle, isDark } = useSectionContent(props.section);
|
||||
const { overline, title, subtitle, isDark, overlineStyle, titleStyle, bodyStyle } = useSectionContent(props.section);
|
||||
|
||||
// 判断是否为可嵌入的 iframe 视频(YouTube / Bilibili)
|
||||
const isEmbed = computed(() => /youtube\.com|youtu\.be|bilibili\.com|player\.bilibili\.com/.test(props.section.video_url));
|
||||
@@ -13,13 +13,13 @@ const isEmbed = computed(() => /youtube\.com|youtu\.be|bilibili\.com|player\.bil
|
||||
<div class="section-container py-96px">
|
||||
<!-- 标题区 -->
|
||||
<div class="text-center max-w-640px mx-auto mb-48px">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'">
|
||||
<p v-if="overline" class="text-13px font-semibold tracking-widest uppercase" :class="isDark ? 'text-primary-300' : 'text-primary'" :style="overlineStyle">
|
||||
{{ overline }}
|
||||
</p>
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'">
|
||||
<h2 class="mt-12px text-3xl md:text-4xl font-bold" :class="isDark ? 'text-white' : 'text-gray-900 dark:text-white'" :style="titleStyle">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'">
|
||||
<p v-if="subtitle" class="mt-16px text-base" :class="isDark ? 'text-gray-400' : 'text-gray-500 dark:text-gray-400'" :style="bodyStyle">
|
||||
{{ subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user