Skip to content

Commit 818aa62

Browse files
committed
feat: add activity modal
1 parent 08c0919 commit 818aa62

File tree

13 files changed

+162
-76
lines changed

13 files changed

+162
-76
lines changed

assets/image/cursor.svg

Lines changed: 9 additions & 0 deletions
Loading

assets/scss/style.scss

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Noto+Sans+TC:wght@100;200;300;400;500;600;700;800;900&display=swap');
44

55

6-
76
@font-face {
87
font-family: 'mantou-sans';
98
src: url('/assets/fonts/MantouSans-Regular.ttf') format('truetype');
@@ -174,7 +173,7 @@ position:absolute,
174173
}
175174

176175
.cursor-pointer{
177-
cursor: pointer;
176+
cursor: url('~/assets/image/cursor.svg'),auto;
178177
&:hover{
179178
background: linear-gradient(90deg, #E6793B 1.54%, #FF4185 97.86%);
180179
background: -webkit-linear-gradient(90deg, #E6793B 1.54%, #FF4185 97.86%);
@@ -184,4 +183,4 @@ position:absolute,
184183
}
185184
}
186185

187-
}
186+
}

components/UI/BaseButton.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<v-btn variant="flat" plain :class="['baseButton', 'rounded-pill', 'pa-0', props.fullWidth ? 'w-100' : '']">
3-
<p
4-
:class="[props.fullWidth ? '':'text-h6', 'my-5', 'ml-6', props.icon ? 'mr-2' : 'mr-6', props.theme === 'primary' ? 'text-white' : 'text-text-primary']" :style="{'fontWeight': props.fullWidth ? '600':''}">
3+
<p :class="[props.fullWidth ? '' : 'text-h6', 'my-5', 'ml-6', props.icon ? 'mr-2' : 'mr-6', props.theme === 'primary' ? 'text-white' : 'text-text-primary']"
4+
:style="{ 'fontWeight': props.fullWidth ? '600' : '' }">
55
{{
66
props.title }}</p>
77
<v-icon v-if="props.icon" :icon="props.icon"
@@ -38,17 +38,19 @@ const color = computed(() => props.theme === 'primary' ? "#DA7D4A" : props.theme
3838
</script>
3939

4040
<style scoped lang="scss">
41-
.v-btn--variant-tonal .v-btn__underlay{
42-
background: white
41+
.v-btn--variant-tonal .v-btn__underlay {
42+
background: white;
43+
4344
}
45+
4446
.v-btn.baseButton {
4547
width: fit-content;
4648
height: fit-content;
4749
background-color: v-bind(color) !important;
50+
cursor: url('~/assets/image/cursor.svg'), auto;
4851
4952
.v-btn__underlay {
5053
background: none;
5154
}
5255
}
53-
5456
</style>

components/UI/BaseSwiper.vue

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
2-
<swiper :effect="'coverflow'" :spaceBetween="0" :grabCursor="true" :centeredSlides="true" :slidesPerView="'auto'"
3-
:pagination="customPagination" :modules="modules" :loop="true" class="mySwiper">
2+
<swiper :navigation="customNavigation" :effect="'coverflow'" :spaceBetween="0" :grabCursor="true" :centeredSlides="true"
3+
:slidesPerView="'auto'" :pagination="customPagination" :modules="modules" :loop="true" class="mySwiper">
44
<swiper-slide v-for="policy in [...POLICY, ...POLICY] " :key="policy.id" class="bg-white d-flex">
55
<v-img :src="policy.imgSrc" width="428px" class="ga-6" />
66
<v-container class="pa-0 ml-lg-8 d-flex flex-column justify-center">
@@ -11,18 +11,27 @@
1111
}}</h4>
1212
<base-button title="查看" theme="primary" icon="mdi-arrow-right" @click="activateDialog(policy.id)"></base-button>
1313
</v-container></swiper-slide>
14-
<div class="swiper-pagination"></div>
14+
<div class="actions mt-3">
15+
<div class="swiper-button-prev"><v-btn class="ma-2" variant="outlined" icon="mdi-arrow-left"></v-btn></div>
16+
<div class="swiper-pagination"></div>
17+
<div class="swiper-button-next"><v-btn class="ma-2" variant="outlined" icon="mdi-arrow-right"></v-btn></div>
18+
</div>
19+
20+
21+
1522
</swiper>
1623
</template>
1724
<script lang="ts">
1825
import { Swiper, SwiperSlide } from 'swiper/vue'
1926
import 'swiper/css'
2027
import 'swiper/css/pagination'
21-
import { Pagination } from 'swiper/modules'
28+
import 'swiper/css/navigation';
29+
import { Pagination, Navigation } from 'swiper/modules'
2230
import { POLICY } from '~/utils/constant'
2331
import BaseButton from '~/components/UI/BaseButton.vue';
2432
import { useHomeStore } from '~/stores/home'
2533
34+
2635
export default {
2736
components: {
2837
Swiper,
@@ -31,20 +40,26 @@ export default {
3140
},
3241
setup() {
3342
const homeStore = useHomeStore()
34-
const activateDialog = (id:string) => {
35-
homeStore.handleActiveDialog(Dialog.POLICY,id)
43+
const activateDialog = (id: string) => {
44+
homeStore.handleActiveDialog(Dialog.POLICY, id)
3645
}
3746
const customPagination = {
3847
el: '.swiper-pagination',
39-
renderBullet: (index:number, className:string) => {
40-
return `<span class="${className} mx-2 bg-primary" style="width:12px;height:12px" key={${index}} value={${index}}></span>`
48+
renderBullet: (index: number, className: string) => {
49+
return `<span class="${className} mx-2 bg-primary" style="width:12px;height:12px" key={${index}} value={${index}}></span>`
4150
}
4251
}
43-
52+
53+
const customNavigation = {
54+
nextEl: '.swiper-button-next',
55+
prevEl: '.swiper-button-prev'
56+
}
57+
4458
return {
45-
modules: [Pagination],
59+
modules: [Pagination, Navigation],
4660
customPagination,
47-
activateDialog
61+
activateDialog,
62+
customNavigation
4863
}
4964
},
5065
}
@@ -67,28 +82,58 @@ export default {
6782
border-radius: 32px;
6883
overflow: hidden;
6984
transform: scale(0.9);
85+
7086
&.swiper-slide-active {
7187
transform: scale(1);
7288
}
89+
7390
img {
74-
display: block;
75-
width: 100%;
76-
}
91+
display: block;
92+
width: 100%;
93+
}
7794
}
7895
7996
.swiper-pagination {
80-
bottom: var(--swiper-pagination-bottom, 8px);
81-
top: var(--swiper-pagination-top, auto);
82-
left: 0;
83-
width: 100%;
97+
width: fit-content;
98+
position: static;
99+
display: flex;
100+
align-items: center;
101+
}
102+
103+
.actions {
104+
display: flex;
105+
justify-content: center;
84106
}
85107
86-
@media(max-width: 960px){
87108
88-
.swiper-slide{
109+
.swiper-button-next,
110+
.swiper-button-prev {
111+
position: static;
112+
display: block;
113+
width: fit-content;
114+
height: fit-content;
115+
margin-top: 0px;
116+
117+
.v-btn--variant-outlined {
118+
border: none;
119+
background-color: white;
120+
color: #DA7D4A
121+
}
122+
123+
&::after {
124+
content: "";
125+
display: none;
126+
}
127+
}
128+
129+
130+
131+
@media(max-width: 960px) {
132+
133+
.swiper-slide {
89134
width: 311px;
90-
height:508px;
91-
display:flex;
135+
height: 508px;
136+
display: flex;
92137
flex-direction: column;
93138
}
94139
}
Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
<template>
2-
<div :class="['d-flex', props.isDesktop ? 'flex-row' : 'flex-column', 'ga-8']">
2+
<div :class="['d-flex', props.isDesktop ? 'flex-row' : 'flex-column', 'ga-8', 'h-100']">
33
<div :class="['d-flex', 'flex-column', 'text-text-primary', 'text-body-1']"
4-
:style="{ width: props.isDesktop ? '40%' : '' }"><img :src="activities.main?.imgSrc" class="rounded-lg"
5-
:style="{ 'width': '100%', 'aspect-ratio': '507/400' }" />
6-
<p :class="['mt-4', 'mb-2', props.isDesktop ? 'text-caption' : 'text-body-1']">{{ activities.main?.title}}
4+
:style="{ width: props.isDesktop ? '40%' : '', position: props.isDesktop ? 'sticky' : undefined, height: '100%', top: '0px' }">
5+
<img :src="activities.main?.imgSrc" class="rounded-lg"
6+
:style="{ 'width': '100%', 'aspect-ratio': '343/251', 'objectFit': 'cover' }" />
7+
<p :class="['mt-4', 'mb-2', props.isDesktop ? 'text-caption' : 'text-body-1']">{{ activities.main?.title }}
78
</p>
89
<div class="d-flex align-center ga-2">
910
<p>分享</p><v-btn class="rounded-pill px-0 bg-white" style="height:32px;min-width:32px" variant="text"
1011
v-for="item in SOCIAL"><v-icon style="font-size:24px" :color="item.color" :icon="'mdi-' + item.icon"
1112
:class="item.class || ''"></v-icon></v-btn>
1213
</div>
1314
</div>
14-
<div :style="{ width: props.isDesktop ? '60%' : '' }">
15+
<div class="h-100" :style="{ width: props.isDesktop ? '60%' : '' }">
1516
<div>
16-
<h4 class="text-primary text-h4 mb-10">{{ activities.main?.title }}</h4>
17-
<!-- <div v-for="item in activities.main?.content" class="mb-6">
18-
<h5 class="text-h5 mb-2">{{ item.title }}</h5>
19-
<p>{{ item.content }}</p>
20-
</div> -->
21-
<v-card class="bg-gray-50 rounded-lg pa-4 d-flex flex-column w-100" style="margin-top:88px;box-shadow: none">
17+
<h4 class="text-primary text-h4 mb-2">{{ activities.main?.title }}</h4>
18+
<p class="text-text-caption mb-10">{{ activities.main?.date }}</p>
19+
<p class="text-text-body-1 text-text-primary mb-6">{{ activities.main?.content }}</p>
20+
<p class="text-text-body-1 text-text-primary mb-6" v-for="sub in activities.main?.subContent">{{ sub }}</p>
21+
<v-card class="bg-gray-50 rounded-lg pa-4 d-flex flex-column w-100 mt-16" style="box-shadow: none">
2222
<p class="text-body-1 mb-4" style="font-weight: 600;">更多政策議題</p>
2323
<div class="d-flex ga-4"><v-card class="bg-transparent"
24-
:style="{ 'box-shadow': 'none', 'max-width': props.isDesktop ? '244px' : '' }"
25-
v-for="policy in activities.other">
26-
<img :src="policy.imgSrc" class="rounded-lg w-100"
27-
:style="{ height: props.isDesktop ? '134px' : undefined, objectFit: props.isDesktop ? 'cover' : undefined }" />
28-
<p class="text-body-1 mt-3 text-text-primary">{{ policy.title }}</p>
24+
:style="{ 'box-shadow': 'none', 'max-width': props.isDesktop ? '244px' : '', 'width': props.isDesktop ? '' : '50%' }"
25+
v-for="activity in activities.other">
26+
<img :src="activity.imgSrc" class="rounded-lg w-100"
27+
:style="{ height: props.isDesktop ? '134px' : undefined, aspectRatio: '244/134', objectFit: 'cover' }" />
28+
<p class="text-body-1 mt-3 text-text-primary cursor-pointer" @click="handleSelectActivity(activity.id)">{{
29+
activity.title }}</p>
2930
</v-card>
3031
</div>
3132
</v-card>
@@ -45,6 +46,10 @@ const props = defineProps({
4546
}
4647
})
4748
const activities = computed(() => {
48-
return { main: ACTIVITY.find(policy => policy.id === homeStore.activeDialog.id), other: ACTIVITY.filter(policy => policy.id !== homeStore.activeDialog.id) }
49+
return { main: ACTIVITY.find(activity => activity.id === homeStore.activeDialog.id), other: ACTIVITY.filter(activity => activity.id !== homeStore.activeDialog.id) }
4950
})
51+
52+
const handleSelectActivity = (id: string) => {
53+
homeStore.handleActiveDialog(Dialog.ACTIVITY, id)
54+
}
5055
</script>

components/UI/Dialog/BaseDialog.vue

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<template>
22
<v-row justify="center">
3-
<v-dialog scrollable v-model="isActive" :width="props.isDesktop ? '95%' : undefined" style="max-width: 1440px"
3+
<v-dialog scrollable v-model="isActive" :width="props.isDesktop ? '100%' : undefined" style="max-width: 1440px"
44
:fullscreen="props.isDesktop ? false : true" :scrim="props.isDesktop ? true : false"
55
@close="homeStore.handleActiveDialog(Dialog.NULL)" :attach="true" transition="dialog-bottom-transition">
6-
<v-card class="rounded-xl pa-4" style="height:95%;box-shadow: none;">
6+
<v-card :class="['rounded-xl', props.isDesktop ? 'pt-6 px-12 pb-12' : 'pa-4']" style="height:95%;box-shadow: none;">
77
<v-card-title class="d-flex align-center justify-space-between pa-0">
88
<h4 class="text-h5" style="font-weight: 700;">{{ title }}</h4><v-icon
99
@click="homeStore.handleActiveDialog(Dialog.NULL)" icon="mdi-close-circle"
1010
:style="{ 'font-size': props.isDesktop ? '32px' : '24px' }"></v-icon>
1111
</v-card-title>
12-
<v-card-text :class="['pa-0', props.isDesktop ? 'mt-4' : 'mt-2']">
12+
<v-card-text :class="['pa-0', props.isDesktop ? 'mt-4' : 'mt-2']" ref="contentRef">
1313
<service-content :isDesktop="props.isDesktop"
1414
v-if="homeStore.activeDialog.type === Dialog.SERVICE"></service-content>
1515
<donate-content :isDesktop="props.isDesktop"
@@ -31,7 +31,10 @@ import DonateContent from '~/components/UI/Dialog/DonateContent.vue';
3131
import ActivityContent from '~/components/UI/Dialog/ActivityContent.vue';
3232
import PolicyContent from '~/components/UI/Dialog/PolicyContent.vue';
3333
import { DIALOG_TITLE } from '~/utils/constant';
34+
import { ref, watch } from 'vue';
35+
3436
const homeStore = useHomeStore()
37+
const contentRef = ref<HTMLDivElement & { $el: HTMLDivElement } | null>(null)
3538
const isActive = computed(() => { return homeStore.activeDialog.type !== Dialog.NULL })
3639
const props = defineProps({
3740
isDesktop: {
@@ -40,8 +43,21 @@ const props = defineProps({
4043
}
4144
})
4245
46+
watch(() => [homeStore.activeDialog.id, homeStore.activeDialog.type, contentRef.value], () => {
47+
if (homeStore.activeDialog.id && (homeStore.activeDialog.type === Dialog.ACTIVITY || homeStore.activeDialog.type === Dialog.POLICY) && contentRef.value) {
48+
contentRef.value.$el.scrollTop = 0
49+
}
50+
})
51+
4352
4453
const title = computed(() => {
4554
return DIALOG_TITLE[`${homeStore.activeDialog.type as keyof typeof DIALOG_TITLE}`]
4655
})
47-
</script>
56+
57+
</script>
58+
59+
<style lang="scss" scoped>
60+
.v-card-text{
61+
scroll-behavior: smooth;
62+
}
63+
</style>

components/UI/Dialog/PolicyContent.vue

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
2-
<div :class="['d-flex', props.isDesktop ? 'flex-row' : 'flex-column', 'ga-8']">
3-
<div :class="['d-flex', 'flex-column', 'text-text-primary', 'text-body-1']"
4-
:style="{ width: props.isDesktop ? '40%' : '' }"><img :src="policies.main?.imgSrc" class="rounded-lg"
2+
<div :class="['d-flex', props.isDesktop ? 'flex-row' : 'flex-column', 'ga-8','h-100']" >
3+
<div :class="['d-flex', 'flex-column', 'text-text-primary', 'text-body-1','h-100']"
4+
:style="{ width: props.isDesktop ? '40%' : '',position: props.isDesktop ? 'sticky':undefined,top:'0px'}"><img :src="policies.main?.imgSrc" class="rounded-lg"
55
:style="{ 'width': '100%', 'aspect-ratio': '507/400' }" />
66
<p :class="['mt-4', 'mb-2', props.isDesktop ? 'text-caption' : 'text-body-1']">{{ policies.main?.title.join("") }}
77
</p>
@@ -11,8 +11,8 @@
1111
:class="item.class || ''"></v-icon></v-btn>
1212
</div>
1313
</div>
14-
<div :style="{ width: props.isDesktop ? '60%' : '' }">
15-
<div>
14+
<div :style="{ width: props.isDesktop ? '60%' : '' }" >
15+
1616
<h4 class="text-primary text-h4 mb-10">{{ policies.main?.title.join("") }}</h4>
1717
<div v-for="item in policies.main?.list" class="mb-6">
1818
<h5 class="text-h5 mb-2">{{ item.title }}</h5>
@@ -24,11 +24,10 @@
2424
v-for="policy in policies.other">
2525
<img :src="policy.imgSrc" class="rounded-lg w-100"
2626
:style="{ height: props.isDesktop ? '134px' : undefined, objectFit: props.isDesktop ? 'cover' : undefined }" />
27-
<p class="text-body-1 mt-3 text-text-primary">{{ policy.title.join("") }}</p>
27+
<p class="text-body-1 mt-3 text-text-primary cursor-pointer" @click="handleSelectItem(policy.id)" >{{ policy.title.join("") }}</p>
2828
</v-card>
2929
</div>
3030
</v-card>
31-
</div>
3231
</div>
3332
</div>
3433
</template>
@@ -46,4 +45,10 @@ const props = defineProps({
4645
const policies = computed(() => {
4746
return { main: POLICY.find(policy => policy.id === homeStore.activeDialog.id), other: POLICY.filter(policy => policy.id !== homeStore.activeDialog.id) }
4847
})
48+
49+
const handleSelectItem = (id:string) => {
50+
homeStore.handleActiveDialog(Dialog.POLICY, id)
51+
}
52+
53+
4954
</script>

components/UI/Dialog/ServiceContent.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
<base-button title="送出意見" theme="primary" :fullWidth="true" :disabled="false" @click="handleMail"></base-button>
3737
</v-col>
38-
<v-col v-else class="d-flex flex-column align-center h-100 justify-center ga-8">
38+
<v-col v-else :class="['d-flex' ,'flex-column' ,'align-center', props.isDesktop? '': 'h-100', 'justify-center', 'ga-8']">
3939
<h3 class="text-h3">感謝您的意見</h3><v-img :src="donate_finish" :width="187"
4040
style="max-height:166px"></v-img><base-button style="width: 187px" title="關閉" theme="gray"
4141
@click="homeStore.handleActiveDialog(Dialog.NULL)"></base-button>

layouts/BaseFooter.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,8 @@ import { LEGISLATOR } from '~/utils/constant';
6161
max-width: 100%;
6262
}
6363
}
64+
.v-application .px-26{
65+
padding:104px 0px 172px 0px
66+
}
6467
}
6568
</style>

0 commit comments

Comments
 (0)