style(home components): clean up scss and use utility classes

- remove unused SCSS style files for Discovery sub-components
- replace scoped SCSS styles with inline utility classes across home components
- remove redundant style imports and empty style blocks from component files
- simplify template conditions and remove unnecessary min-h-0 attributes
This commit is contained in:
duanshuwen
2026-05-28 22:32:05 +08:00
parent f74af3a4a5
commit 35b4eb3cca
10 changed files with 66 additions and 306 deletions

View File

@@ -1,12 +1,13 @@
<template>
<div class="w-full border-box flex flex-col overflow-hidden pl-12 mt-6 mb-6">
<span class="font-size-14 color-333">{{ text }}</span>
<div class="w-full flex flex-col overflow-hidden pl-[12px] mt-[6px] mb-[6px]">
<span class="text-[14px] text-[#333]">{{ text }}</span>
<slot></slot>
</div>
</template>
<script setup>
import { defineProps } from "vue";
defineProps({
text: {
type: String,
@@ -14,5 +15,3 @@ defineProps({
},
});
</script>
<style lang="scss" scoped></style>

View File

@@ -1,16 +1,16 @@
<template>
<div class="empty-container">
<div class="flex flex-col items-center justify-center py-[90px]">
<!-- 图片变量 -->
<img v-if="!hasMessage" :src="imageSrc" class="main-image" />
<img v-if="!hasMessage" :src="imageSrc" class="w-[160px] h-[160px] mb-5" />
<!-- 主标题变量 -->
<div v-if="!hasMessage" class="title">{{ mainTitle }}</div>
<div v-if="!hasMessage" class="text-[18px] font-bold text-[#2c3e50] mb-1 text-center">{{ mainTitle }}</div>
<!-- 副标题变量 -->
<div v-if="!hasMessage" class="sub-title-wrapper">
<span class="dot"></span>
<span class="sub-title">{{ subTitle }}</span>
<span class="dot"></span>
<div v-if="!hasMessage" class="flex items-center">
<span class="w-[5px] h-[5px] bg-[#42b983] rounded-full"></span>
<span class="text-[12px] text-[#afb9c1] ml-[6px] mr-[6px]">{{ subTitle }}</span>
<span class="w-[5px] h-[5px] bg-[#42b983] rounded-full"></span>
</div>
</div>
</template>
@@ -39,45 +39,3 @@ const props = defineProps({
}
});
</script>
<style lang="scss" scoped>
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 90px 0;
.main-image {
width: 160px;
height: 160px;
margin-bottom: 20px;
}
.title {
font-size: 18px;
font-weight: bold;
color: #2c3e50;
margin-bottom: 4px;
text-align: center;
}
.sub-title-wrapper {
display: flex;
align-items: center;
.sub-title {
font-size: 12px;
color: #afb9c1;
margin: 0 6px;
}
.dot {
width: 5px;
height: 5px;
background-color: #42b983;
border-radius: 50%;
}
}
}
</style>

View File

@@ -17,18 +17,17 @@
</div>
</div>
<div v-show="tabIndex === 0" class="flex-full overflow-hidden min-h-0"
@touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
@touchmove="handleScrollAreaTouchMove">
<!-- 发现页 -->
<div v-show="tabIndex === 0" class="flex-full overflow-hidden" @touchstart.capture="handleScrollAreaTouchStart"
@touchstart="handleScrollAreaTouchStart" @touchmove="handleScrollAreaTouchMove">
<Discovery @scroll-touch-start="handleScrollAreaTouchStart" @scroll-touch="handleScrollAreaTouchMove" />
</div>
<!-- 消息列表可滚动区域 -->
<div v-show="tabIndex === 1" class="flex-full overflow-hidden min-h-0" scroll-y :scroll-top="scrollTop"
:scroll-with-animation="true" @scroll="handleScroll" @scrolltolower="handleScrollToLower"
@touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
@touchmove="handleScrollAreaTouchMove">
<div v-show="tabIndex === 1" class="flex-full overflow-hidden" :scroll-top="scrollTop" @scroll="handleScroll"
@scrolltolower="handleScrollToLower" @touchstart.capture="handleScrollAreaTouchStart"
@touchstart="handleScrollAreaTouchStart" @touchmove="handleScrollAreaTouchMove">
<div class="area-msg-list-content" v-for="item in chatMsgList" :key="item.msgId" :id="item.msgId">
<template v-if="item.msgType === MessageRole.AI">

View File

@@ -1,28 +1,31 @@
<template>
<div class="card-swiper" :class="{ 'is-single': props.list.length <= 1 }" @touchstart="handleTouchStart"
@touchmove.stop.prevent="handleTouchMove" @touchend="handleTouchEnd" @touchcancel="handleTouchCancel">
<div class="swiper-stage">
<div v-for="slot in renderSlots" :key="slot.key" class="swiper-card"
:class="[`is-${slot.role}`, { 'is-current': slot.role === 'current' }]" :style="slot.style"
@tap="handleCardTap(slot)">
<div class="card-shell">
<div class="card-media">
<img class="card-image" :src="slot.item.coverImage" mode="aspectFill" />
<div class="w-full" @touchstart="handleTouchStart" @touchmove.stop.prevent="handleTouchMove"
@touchend="handleTouchEnd" @touchcancel="handleTouchCancel">
<div :class="['relative w-full h-[270px] overflow-hidden', list.length <= 1 ? 'overflow-visible' : '']">
<div v-for="slot in renderSlots" :key="slot.key"
class="absolute left-1/2 top-2 w-[236px] h-[234px] max-w-[calc(100%-56px)] origin-center [will-change:transform,opacity]"
:style="slot.style" @tap="handleCardTap(slot)">
<div
:class="['relative w-full h-full p-2 overflow-hidden rounded-3xl bg-white', slot.role === 'current' ? '[box-shadow:0_12px_20px_rgba(15,23,42,0.18)]' : '[box-shadow:0_12px_20px_rgba(15,23,42,0.14)]']">
<div class="w-full h-[142px] m-0 overflow-hidden rounded-[20px]">
<img class="block w-full h-full" :src="slot.item.coverImage" />
</div>
<div class="card-body">
<div v-if="slot.item.tag" class="card-tag">
<div class="px-2">
<div v-if="slot.item.tag"
class="inline-flex items-center justify-center mt-3 min-w-[50px] max-w-full h-[18px] px-2 rounded bg-[#fff4db] text-[#d78621] text-[9px] font-semibold">
{{ slot.item.tag }}
</div>
<div class="card-title ellipsis-1">
<div class="mt-[6px] text-[#172033] text-[16px] leading-[1.2] font-bold truncate">
{{ slot.item.title }}
</div>
<div v-if="slot.item.subTitle" class="card-desc ellipsis-1">
<div v-if="slot.item.subTitle" class="mt-[2px] text-[#7f8ea3] text-[12px] leading-[18px] truncate">
{{ slot.item.subTitle }}
</div>
</div>
<div v-if="canSwipe" class="card-mask" :style="getMaskStyle(slot.role)" />
<div v-if="canSwipe" class="absolute inset-0 bg-white/42 pointer-events-none"
:style="getMaskStyle(slot.role)"></div>
</div>
</div>
</div>
@@ -53,8 +56,7 @@ const SWIPE_THRESHOLD = 60;
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
const lerp = (from, to, progress) => from + (to - from) * progress;
const { windowWidth = 375 } = uni.getWindowInfo();
const sideOffset = Math.max(108, Math.min(windowWidth * 0.26, 148));
const sideOffset = Math.max(108, Math.min(375 * 0.26, 148));
const hiddenOffset = sideOffset + 92;
const activeCursor = ref(0);
@@ -464,8 +466,4 @@ onBeforeUnmount(() => {
clearSettleTimer();
clearRecycleTimer();
});
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>
</script>

View File

@@ -1,97 +0,0 @@
.card-swiper {
width: 100%;
}
.swiper-stage {
position: relative;
width: 100%;
height: 270px;
overflow: hidden;
}
.swiper-card {
position: absolute;
left: 50%;
top: 8px;
width: 236px;
height: 234px;
max-width: calc(100% - 56px);
transform-origin: center center;
will-change: transform, opacity;
}
.card-shell {
position: relative;
width: 100%;
height: 100%;
padding: 8px;
box-sizing: border-box;
overflow: hidden;
border-radius: 24px;
background: #ffffff;
box-shadow: 0 12px 20px rgba(15, 23, 42, 0.14);
}
.card-media {
width: 100%;
height: 142px;
margin: 0;
overflow: hidden;
border-radius: 20px;
}
.card-image {
width: 100%;
height: 100%;
display: block;
}
.card-body {
padding: 0 8px;
}
.card-tag {
display: inline-flex;
align-items: center;
justify-content: center;
margin-top: 12px;
min-width: 50px;
max-width: 100%;
height: 18px;
padding: 0 8px;
border-radius: 4px;
background: #fff4db;
color: #d78621;
font-size: 9px;
font-weight: 600;
}
.card-title {
margin-top: 6px;
color: #172033;
font-size: 16px;
line-height: 1.2;
font-weight: 700;
}
.card-desc {
margin-top: 2px;
color: #7f8ea3;
font-size: 12px;
line-height: 18px;
}
.card-mask {
position: absolute;
inset: 0;
background: rgba(255, 255, 255, 0.42);
pointer-events: none;
}
.is-current .card-shell {
box-shadow: 0 12px 20px rgba(15, 23, 42, 0.18);
}
.is-single .swiper-stage {
overflow: visible;
}

View File

@@ -1,15 +1,19 @@
<template>
<div class="find-tabs-wrapper">
<div class="tabs-scroll" scroll-x="true" :scroll-left="scrollLeft" scroll-with-animation="true"
@scroll="handleScroll">
<div class="tabs-list">
<div v-for="(tab, idx) in tabs" :key="idx" :id="getTabId(idx)" class="tab-item"
:class="{ active: modelValue === idx }" @tap="handleSwitch(tab, idx)">
<div class="tab-content">
<div class="tab-label">
<span class="tab-text">{{ tab.label }}</span>
<div class="w-full bg-transparent">
<div class="w-full overflow-x-auto [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
:scroll-left="scrollLeft" scroll-with-animation="true" @scroll="handleScroll">
<div class="flex items-end h-[50px] gap-4 flex-nowrap px-3">
<div v-for="(tab, idx) in tabs" :key="idx" :id="getTabId(idx)"
class="relative inline-flex items-center justify-center h-[50px] shrink-0" @tap="handleSwitch(tab, idx)">
<div class="relative flex items-center justify-center h-[50px]">
<div class="relative inline-flex items-center justify-center">
<span
:class="['relative text-base font-medium text-[#808c99]/90 z-10 px-1 leading-none', modelValue === idx ? 'text-[#0b0b0b] font-bold' : '']">
{{ tab.label }}
</span>
<img v-if="modelValue === idx && (isZhiNian ? indicatorSrcB : indicatorSrc)"
:src="isZhiNian ? indicatorSrcB : indicatorSrc" class="tab-indicator" mode="widthFix" />
:src="isZhiNian ? indicatorSrcB : indicatorSrc"
class="absolute -bottom-[6px] left-1/2 -translate-x-1/2 w-[56px] h-auto z-[1]" />
</div>
</div>
</div>
@@ -87,7 +91,3 @@ onMounted(() => {
});
</script>
<style lang="scss" scoped>
@import "./styles/index.scss";
</style>

View File

@@ -1,71 +0,0 @@
.find-tabs-wrapper {
width: 100%;
background-color: transparent;
}
.tabs-scroll {
width: 100%;
}
.tabs-list {
display: flex;
align-items: flex-end;
height: 50px;
gap: 16px;
flex-wrap: nowrap;
padding: 0 12px;
}
.tab-item {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
height: 50px;
box-sizing: border-box;
flex: 0 0 auto;
}
.tab-item:last-child {
margin-right: 12px;
}
.tab-content {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 50px;
}
.tab-label {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
}
.tab-text {
position: relative;
font-size: 16px;
font-weight: 500;
color: rgba(128, 140, 153, 0.9);
z-index: 2;
padding: 0 4px;
line-height: 1;
}
.tab-item.active .tab-text {
color: #0b0b0b;
font-weight: bold;
}
.tab-indicator {
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
width: 56px;
height: auto;
z-index: 1;
}

View File

@@ -1,20 +1,20 @@
<template>
<div class="container pl-12">
<div class="pl-[12px]">
<ModuleTitle :title="themeName" />
<div class="container-scroll font-size-0 scroll-x whitespace-nowrap">
<div
class="mt-1 mb-[6px] text-[0] overflow-x-auto whitespace-nowrap [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
<div class="min-w-[130px] max-w-[150px] bg-white inline-block rounded-[20px] mr-[10px]"
v-for="(item, index) in list" :key="index" @click="sendReply(item)">
<div class="card-item bg-white inline-block rounded-20 mr-10" v-for="(item, index) in list" :key="index"
@click="sendReply(item)">
<div class="flex flex-row justify-start p-[10px]">
<img class="w-[40px] h-[40px] shrink-0 rounded-[14px]" :src="createSvgIndex(index)" />
<div class="flex flex-row flex-justify-start p-10">
<img class="card-img flex-shrink-0 rounded-14" :src="createSvgIndex(index)" />
<div class="min-width-0 flex flex-col flex-full border-box pl-8 py-4">
<div class="w-full font-size-12 font-600 color-171717 ellipsis-1">
<div class="min-w-0 flex flex-col flex-full pl-[8px] py-[4px]">
<div class="w-full text-[12px] font-semibold text-[#171717] truncate">
{{ item.title }}
</div>
<div class="w-full font-size-9 color-94A3B8 ellipsis-1">
<div class="w-full text-[9px] text-[#94A3B8] truncate">
{{ item.subTitle }}
</div>
</div>
@@ -74,7 +74,3 @@ const createSvg = (bgColor = '#FFFBEB', iconColor = '#F59E0B', size = 40) => {
}
</script>
<style lang="scss" scoped>
@import "./styles/index.scss";
</style>

View File

@@ -1,13 +0,0 @@
.container-scroll {
margin: 4px 0 6px;
}
.card-item {
min-width: 130px;
max-width: 150px;
}
.card-img {
height: 40px;
width: 40px;
}

View File

@@ -1,14 +1,14 @@
<template>
<div class="flex flex-col h-full overflow-hidden min-height-0">
<div class="flex-shrink-0">
<FindTabs v-if="discoveryTabs.length > 0" v-model="activeIndex" :tabs="discoveryTabs" @change="handleTabChange" />
<div class="flex flex-col h-full overflow-hidden">
<div class="shrink-0">
<FindTabs v-if="discoveryTabs.length" v-model="activeIndex" :tabs="discoveryTabs" @change="handleTabChange" />
</div>
<div class="discovery-scroll flex-full border-box min-height-0" scroll-y show-scrollbar="false"
@touchstart="emitScrollTouchStart" @touchmove="emitScrollTouch" @scroll="emitScrollTouch">
<CardSwiper v-if="discoveryCards.length > 0" :list="discoveryCards" @didSelectItem="handleCardClick" />
<div class="discovery-scroll flex-full" overflow-y @touchstart="emitScrollTouchStart" @touchmove="emitScrollTouch"
@scroll="emitScrollTouch">
<CardSwiper v-if="discoveryCards.length" :list="discoveryCards" @didSelectItem="handleCardClick" />
<QuickQuestions v-if="discoveryQuickQuestions.length > 0" :list="discoveryQuickQuestions"
<QuickQuestions v-if="discoveryQuickQuestions.length" :list="discoveryQuickQuestions"
@didSelectItem="handleQuickQuestionClick" />
</div>
@@ -192,12 +192,3 @@ onMounted(() => {
});
</script>
<style lang="scss" scoped>
.discovery-scroll {
flex-basis: 0;
height: 0;
min-height: 0;
overscroll-behavior-y: contain;
}
</style>