style: 竞赛主页样式修改

This commit is contained in:
2026-01-30 17:21:11 +08:00
parent de78bfc051
commit 89a89ea5ef
18 changed files with 773 additions and 278 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -1,31 +1,41 @@
/* 字体定义 */
@font-face {
font-family: 'Arial';
src: url('./fonts/ARIAL.ttf') format('ttf');
src: url('./fonts/ARIAL.ttf') format('truetype');
}
@font-face {
font-family: 'ArialBold';
src: url('./fonts/ARIALBD.ttf') format('ttf');
src: url('./fonts/ARIALBD.ttf') format('truetype');
}
@font-face {
font-family: 'ArialMedium';
src: url('./fonts/ArialMdm.ttf') format('ttf');
src: url('./fonts/ArialMdm.ttf') format('truetype');
}
@font-face {
font-family: 'Poppins';
src: url('./fonts/Poppins-Regular.ttf') format('ttf');
src: url('./fonts/Poppins-Regular.ttf') format('truetype');
font-weight: normal;
}
@font-face {
font-family: 'PoppinsMedium';
src: url('./fonts/Poppins-Medium.ttf') format('ttf');
src: url('./fonts/Poppins-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'PoppinsBold';
src: url('./fonts/Poppins-SemiBold.ttf') format('ttf');
src: url('./fonts/Poppins-SemiBold.ttf') format('truetype');
}
@font-face {
font-family: 'Instrument';
src: url('./InstrumentSans-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'InstrumentBold';
src: url('./InstrumentSans-Bold.ttf') format('truetype');
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -2506,4 +2506,7 @@ textarea:focus {
}
.justify-center {
justify-content: center;
}
.flex-1{
flex: 1;
}

View File

@@ -2424,4 +2424,7 @@ textarea:focus{
}
.justify-center {
justify-content: center;
}
.flex-1{
flex: 1;
}

View File

@@ -1047,8 +1047,7 @@
.desc {
color: #b10000;
// font-family: 'Instrument';
font-family: revert-layer;
font-family: 'Instrument';
font-weight: 500;
font-size: 2.4rem;
}
@@ -1067,8 +1066,7 @@
.desc {
color: #b10000;
// font-family: 'Instrument';
font-family: revert-layer;
font-family: 'Instrument';
font-weight: 500;
font-size: 2.4rem;
}
@@ -1376,8 +1374,7 @@
}
.desc {
// font-family: 'instrument';
font-family: revert-layer;
font-family: 'Instrument';
font-weight: 400;
font-size: 1.6rem;
color: #6d6d6d;

View File

@@ -1,28 +1,170 @@
<template>
<div class="apply-container container flex flex-col" ref="applyRef">
<div class="title" ref="applyTitleRef">How to Apply</div>
<div class="sub-title" ref="applySubTitleRef">Requirments</div>
<div class="requirments-list flex" ref="reqListRef">
<div class="left flex flex-col space-between">
<div class="item-box" v-for="item in leftRequirment" :key="item.type">
<div class="item-header flex align-center">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<div
class="apply-container flex flex-col"
id="apply"
ref="applyRef"
>
<div
class="title animation-element"
ref="applyTitleRef"
>
How to Apply
</div>
<div
class="sub-title animation-element"
ref="applySubTitleRef"
>
Step by step
</div>
<div
class="requirments-list flex flex-col"
ref="reqListRef"
>
<div class="top flex">
<div
class="item-box animation-element"
v-for="(item, index) in leftRequirment"
:key="item.type"
:ref="el => { if(el) itemRefs[index] = el }"
:style="{ background: item.background || '#fff' }"
>
<div class="item-header flex flex-center">
<div class="item-title">{{ item.type }}</div>
</div>
<div class="context" v-for="el in item.desc">
{{ el }}
<div class="context-container flex flex-center">
<div
class="context"
v-for="el in item.desc"
>
{{ el }}
</div>
<div
class="list"
v-if="item.listTitle"
>
<div class="list-title">{{ item.listTitle }}</div>
<ul class="list-items">
<li
class="list-item"
v-for="el in item.list"
>
{{ el }}
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="right">
<div class="item-box">
<div class="item-box">
<div class="item-header flex align-center">
<img src="@/assets/images/award/bloom_logo.png" class="logo" />
<div class="item-title">{{ rightRequirment.type }}</div>
<div class="bottom flex">
<div class="step-3 flex flex-col animation-element" ref="step3Ref">
<div class="header">Step 3. Prepare Your Submission</div>
<div class="content flex">
<div class="content-left flex flex-col space-between">
<div class="content-item">
<div class="item-header flex align-center">
<div class="point"></div>
<div>Process Video</div>
</div>
<div class="desc-wrapper flex flex-col space-between">
<div class="item-desc">
Include a screenrecorded video
<br />
your creative process
<br />
using AiDA.
<br />
</div>
<ul class="desc-lists">
<div class="desc-lists-title">
Video requirements:
</div>
<li>Format: MP4</li>
<li>Resolution: 1080×1920 px</li>
<li>Duration: Maximum 1 minute</li>
<li>File size: Maximum 20MB</li>
</ul>
</div>
</div>
<div class="content-item">
<div class="item-header flex align-center">
<div class="point"></div>
<div>File Name</div>
</div>
<div class="item-desc indent">
AiDAGlobalDesignAward
<br />
2026_[Your Full Name]
</div>
</div>
</div>
<div class="context" v-for="el in rightRequirment.desc">
{{ el }}
<div class="content-right">
<div class="content-item flex flex-col">
<div class="item-header flex align-center">
<div class="point"></div>
<div>Design Portfolio(PDF)</div>
</div>
<div
class="desc-wrapper flex-1 flex flex-col space-between"
>
<ul class="desc-lists">
<div class="desc-lists-title">
<p>
Submit one single PDF file that includes:
</p>
<p>Required structure:</p>
</div>
<li>Design title</li>
<li>Moodboard</li>
<li>Concept explanation</li>
<div>(How to used AiDA to develop design)</div>
</ul>
<ul class="desc-lists">
<div class="desc-lists-title">
<p>PDF requirements:</p>
</div>
<li>Maximum 15 pages</li>
<li>Maximum file size: 20MB</li>
<li>
Language: English or native language
<br />
with English translation
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="step-4 animation-element" ref="step4Ref">
<div class="header flex flex-col flex-center">
<p>Step 4. Finalist Requirement</p>
<p class="sub-title">(for top 20 Designers)</p>
</div>
<div class="content">
<div class="content-item">
<div class="desc-wrapper flex-1 flex flex-col space-between">
<ul class="desc-lists">
<div class="desc-lists-title">
The 20 finalists will be required to
<br />
submit physical garments for final
<br />
evaluation
</div>
<li>Number of pieces: 1</li>
<li>
Garments must be produced
<br />
based on the submitted
<br />
AiDA-generated designs
</li>
<li>
Shipping instructions will be provided by
Code-create
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -32,178 +174,375 @@
</template>
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
import { gsap } from 'gsap'
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
import { gsap } from 'gsap'
const leftRequirment = ref([
{
type: 'Video',
desc: ['The process of doing design']
},
{
type: 'Design',
desc: [
'Structure: design title, moodboard and elaboration (how will you use AiDA to design)',
'Design sketch: Maximum 4 outfit design with proposed materials'
]
const leftRequirment = ref([
{
type: 'Step 1. Become an\nAiDA Subscriber',
desc: [
'All applicants must be active\nAiDA subscribers at the time of\nsubmission. You may subscribe\nunder either a monthly or yearly plan.'
]
},
{
type: 'Step 2. Create Your Design Using AiDA',
desc: [
'Applicants must create their\ndesigns exclusively using the\nAiDA platform. '
],
listTitle: 'Your work shold clearly demonstrate:',
list: [
'· How AiDA is used as a creative tool',
'· Your design concept and creative direction',
'· The intergration of AI and human creativity'
],
background: '#F9F9F9'
}
])
const applyRef = ref()
const applyTitleRef = ref()
const applySubTitleRef = ref()
const reqListRef = ref()
const itemRefs = ref<HTMLElement[]>([])
const step3Ref = ref()
const step4Ref = ref()
const hasPlayedAnim = ref(false)
let timeline: gsap.core.Timeline | null = null
let observer: IntersectionObserver | null = null
const setupApplyInitialState = () => {
// 设置标题和副标题的初始状态
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
scale: 0,
transformOrigin: '50% 50%'
})
}
// 设置步骤元素的初始状态
const allStepElements: HTMLElement[] = []
if (itemRefs.value && itemRefs.value.length > 0) {
allStepElements.push(...itemRefs.value)
}
if (step3Ref.value) {
allStepElements.push(step3Ref.value as HTMLElement)
}
if (step4Ref.value) {
allStepElements.push(step4Ref.value as HTMLElement)
}
if (allStepElements.length > 0) {
gsap.set(allStepElements, {
opacity: 0,
y: 50
})
}
}
])
const rightRequirment = ref({
type: 'Submission Format',
desc: [
'Naming as “AiDA global award 2026_applicantname”',
'Mp4\n(1080x1920pixels/20mb within 1min)',
'Single PDF file\n(within 15 pages, maximum 20mb)',
'English or native language\nwith English translation'
]
})
const initAnimations = () => {
if (hasPlayedAnim.value) return
const applyRef = ref<HTMLElement | null>(null)
const applyTitleRef = ref<HTMLElement | null>(null)
const applySubTitleRef = ref<HTMLElement | null>(null)
const reqListRef = ref<HTMLElement | null>(null)
const hasPlayedApplyAnim = ref(false)
let applyObserver: IntersectionObserver | null = null
const setupApplyInitialState = () => {
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
scale: 0,
transformOrigin: '50% 50%'
timeline = gsap.timeline({
defaults: { ease: 'back.out(1.7)' }
})
}
const headers = reqListRef.value?.querySelectorAll<HTMLElement>('.item-header')
const contexts = reqListRef.value?.querySelectorAll<HTMLElement>('.context')
gsap.set([headers, contexts], { opacity: 0 })
}
const playApplyAnimation = () => {
if (hasPlayedApplyAnim.value) return
const titleEls = [applyTitleRef.value, applySubTitleRef.value].filter(
Boolean
) as HTMLElement[]
const headers = reqListRef.value?.querySelectorAll<HTMLElement>('.item-header')
const contexts = reqListRef.value?.querySelectorAll<HTMLElement>('.context')
if (!titleEls.length) return
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
tl.to(titleEls, {
opacity: 1,
scale: 1,
duration: 0.6,
ease: 'back.out(1.6)',
stagger: 0.1
})
if (headers?.length) {
tl.to(
headers,
{
if (applyTitleRef.value && applySubTitleRef.value) {
timeline.to([applyTitleRef.value, applySubTitleRef.value], {
scale: 1,
opacity: 1,
duration: 0.4,
duration: 0.6,
stagger: 0.1
},
'-=0.1'
)
}
if (contexts?.length) {
tl.to(
contexts,
{
})
}
const allStepElements: HTMLElement[] = []
if (itemRefs.value && itemRefs.value.length > 0) {
allStepElements.push(...itemRefs.value)
}
if (step3Ref.value) {
allStepElements.push(step3Ref.value as HTMLElement)
}
if (step4Ref.value) {
allStepElements.push(step4Ref.value as HTMLElement)
}
if (allStepElements.length > 0) {
timeline.to(allStepElements, {
opacity: 1,
duration: 0.4,
stagger: 0.05
},
'-=0.05'
)
y: 0,
duration: 0.6,
stagger: 0.2
}, '>')
}
hasPlayedAnim.value = true
}
hasPlayedApplyAnim.value = true
applyObserver?.disconnect()
}
onMounted(() => {
nextTick(() => {
setupApplyInitialState()
if ('IntersectionObserver' in window) {
applyObserver = new IntersectionObserver(
onMounted(() => {
nextTick(() => {
setupApplyInitialState()
observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
playApplyAnimation()
initAnimations()
observer?.disconnect()
}
})
},
{ threshold: 0.25 }
{
threshold: 0.3,
rootMargin: '0px 0px -100px 0px'
}
)
if (applyRef.value) applyObserver.observe(applyRef.value)
} else {
playApplyAnimation()
// Start observing the component root element
if (applyRef.value) {
observer.observe(applyRef.value)
}
})
})
onBeforeUnmount(() => {
// Cleanup animation timeline
if (timeline) {
timeline.kill()
}
// Cleanup IntersectionObserver
if (observer) {
observer.disconnect()
}
})
})
onBeforeUnmount(() => {
applyObserver?.disconnect()
})
</script>
<style scoped lang="less">
.apply-container {
flex: 1;
background: url('@/assets/images/award/apply_bg.png') no-repeat;
background-size: 100% 100%;
padding: 12.7rem 0 16.9rem;
.title {
text-align: center;
color: #232323;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 4rem;
margin-bottom: 3rem;
p {
margin: 0;
padding: 0;
}
.sub-title {
text-align: center;
color: #b10000;
font-size: 3rem;
font-family: 'Arial';
font-weight: 400;
ul {
margin: 0;
padding: 0;
}
.requirments-list {
.animation-element{
will-change: opacity transform;
}
.apply-container {
flex: 1;
padding-left: 41.4rem;
column-gap: 17.7rem;
margin-top: 12rem;
.left {
height: 143.3rem;
background: url('@/assets/images/award/apply_bg.png') no-repeat;
background-size: 100% 100%;
padding: 12.7rem 21.4rem 12rem;
.title {
text-align: center;
color: #232323;
height: 100%;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 4rem;
margin-bottom: 3rem;
}
.item-box {
.item-header {
column-gap: 3.2rem;
.item-title {
color: #232323;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 2.8rem;
.sub-title {
text-align: center;
color: #b10000;
font-size: 3rem;
font-family: 'Arial';
font-weight: 400;
margin-bottom: 8.2rem;
}
.requirments-list {
flex: 1;
row-gap: 8.2rem;
.top {
height: 27.4rem;
color: #585858;
column-gap: 4.6rem;
.item-box {
height: 27.4rem;
}
}
.context {
margin-top: 4rem;
width: 46.8rem;
color: #585858;
font-family: 'Arial';
font-weight: 400;
line-height: 3rem;
font-size: 2.4rem;
padding-left: 5.6rem;
white-space: pre-line;
.item-box {
border-radius: 0.8rem;
&:nth-of-type(1) {
width: 47rem;
flex-grow: initial;
}
&:nth-of-type(2) {
flex: 1;
}
.item-header {
background-color: #424242;
border-radius: 0.8rem;
height: 7.8rem;
.item-title {
color: #fff;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 2.4rem;
text-align: center;
white-space: pre-line;
}
}
.context-container {
margin-top: 4rem;
column-gap: 7rem;
.list {
font-family: 'Instrument';
font-weight: 400;
font-size: 2.4rem;
line-height: 3rem;
}
}
.context {
// margin-top: 4rem;
// width: 46.8rem;
text-align: center;
color: #585858;
font-family: 'Arial';
font-weight: 400;
line-height: 3rem;
font-size: 2.4rem;
// padding-left: 5.6rem;
white-space: pre-line;
}
}
.bottom {
column-gap: 4.6rem;
height: 63.4rem;
.step-3 {
flex: 1;
}
.step-3,
.step-4 {
.header {
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 2.4rem;
text-align: center;
height: 7.4rem;
line-height: 7.4rem;
color: #fff;
background-color: #b10000;
border-radius: 0.8rem;
}
.content {
padding: 4rem;
border-radius: 0.8rem;
column-gap: 6.4rem;
background: linear-gradient(
180deg,
#ffe8e8 0%,
#feefef 25%,
#f9f9f9 100%
);
flex: 1;
.content-left {
flex: 1;
}
.content-item {
.item-header {
column-gap: 2rem;
color: #585858;
font-family: 'InstrumentBold';
font-weight: 700;
font-size: 2.4rem;
line-height: 3rem;
.point {
width: 1.2rem;
height: 1.2rem;
background-color: #b10000;
border-radius: 50%;
}
}
.item-desc {
font-family: 'Instrument';
font-weight: 400;
font-size: 24px;
color: #585858;
&.indent {
padding-left: 3.8rem;
line-height: 3rem;
padding-top: 2rem;
}
}
.desc-wrapper {
margin-top: 3rem;
/* 基线行高变量,供子元素计算方块垂直偏移以对齐首行 */
--desc-line-height: 3rem;
font-family: 'Instrument';
font-weight: 400;
color: #585858;
font-size: 2.4rem;
line-height: 3rem;
row-gap: 3rem;
.desc-lists {
/* 使用自定义方块代替浏览器 marker保证大小为 1rem 并与文字垂直居中 */
padding-left: 0;
list-style: none;
li {
list-style: none;
/* 使内容对齐到首行顶部,方块通过 margin-top 调整到首行中间 */
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 0;
margin: 0.4rem 0;
&::before {
content: '';
/* 固定为 1rem 方块 */
width: 0.5rem;
height: 0.5rem;
background-color: #585858;
flex: 0 0 0.5rem;
border-radius: 0;
/* 让方块垂直居中于第一行文字:(line-height - square)/2 */
margin-top: calc(
(var(--desc-line-height, 3rem) - 1rem) / 2
);
}
}
}
}
}
.content-right {
.content-item {
height: 100%;
}
}
}
}
.step-4 {
width: 45.1rem;
.header {
color: #fff;
text-align: center;
background-color: #424242;
border-radius: 0.8rem;
height: 7.8rem;
white-space: pre-line;
font-family: 'PoppinsBold';
font-weight: 600;
font-size: 2.4rem;
line-height: 1.5;
.sub-title {
font-family: 'Poppins';
font-weight: 400;
font-size: 1.8rem;
color: #fff;
margin: 0;
}
}
.content {
background: #fff;
}
}
}
}
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="bloom container flex flex-col align-center">
<div class="bloom flex flex-col align-center">
<div
class="title"
ref="titleRef"
@@ -17,10 +17,34 @@
class="desc"
ref="textRef"
>
Where imagination meets innovation, creativity blooms. This theme celebrates
AI as a catalyst for fashion design, allowing your vision to flourish beyond
traditional boundaries. Let your ideas blossom into extraordinary designs that
merge human artistry with artificial intelligence.
<p class="section-1">
The
<span class="arial-bold">AiDA Global Design Award 2026</span>
is an
<span class="arial-bold">international design competition</span>
hosted by
<span class="arial-bold">CodeCreate</span>
, a globally leading
<br />
<span class="arial-bold">AI fashion solutions provider,</span>
celebrating the future of creativity powered by artificial intelligence.
<br />
Bringing together designers from around the world, AiDA empowers AI as a
creative partnerpushing fashion beyond
<br />
traditional boundaries and unlocking new possibilities where technology
amplifies human imagination.
</p>
<p class="section-2">
Under the theme
<span class="arial-bold">
Where Imagination Meets Innovation, Creativity Blooms,
</span>
participants are invited to transform bold ideas
<br />
into extraordinary designs, seamlessly merging human artistry with
artificial intelligence to shape the next era of fashion.
</p>
</div>
</div>
</template>
@@ -37,7 +61,9 @@
let bloomObserver: IntersectionObserver | null = null
const setupBloomInitialState = () => {
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
const titleEls = [titleRef.value, subtitleRef.value].filter(
Boolean
) as HTMLElement[]
if (titleEls.length) {
gsap.set(titleEls, {
opacity: 0,
@@ -58,7 +84,9 @@
const playBloomAnimation = () => {
if (hasPlayedBloomAnim.value) return
const titleEls = [titleRef.value, subtitleRef.value].filter(Boolean) as HTMLElement[]
const titleEls = [titleRef.value, subtitleRef.value].filter(
Boolean
) as HTMLElement[]
const textEl = textRef.value
if (!titleEls.length || !textEl) return
@@ -81,7 +109,7 @@
duration: 0.3,
ease: 'power2.out'
},
'+=0.12'
'-=0.3'
)
tl.to(
textEl,
@@ -103,8 +131,8 @@
setupBloomInitialState()
if ('IntersectionObserver' in window) {
bloomObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
playBloomAnimation()
}
@@ -125,11 +153,19 @@
onBeforeUnmount(() => {
bloomObserver?.disconnect()
})
</script>
<style scoped lang="less">
p {
margin: 0;
padding: 0;
}
.arial-bold {
font-family: 'ArialBold';
font-weight: 700;
}
.bloom {
height: 108rem;
padding-top: 12.8rem;
font-family: 'Poppins';
background: url('@/assets/images/award/bloom_bg.png') no-repeat;
@@ -149,13 +185,16 @@
}
.desc {
font-family: 'Arial';
font-size: 2.8rem;
font-weight: 400;
font-size: 2.4rem;
color: #585858;
text-align: center;
padding: 0 21.5rem;
line-height: 4.5rem;
margin-bottom: 12.3rem;
.section-2{
margin-top: 4rem;
}
}
}
</style>

View File

@@ -24,10 +24,13 @@
>
<div
class="prize-item flex flex-col flex-center"
:class="{ smaller: item.smaller }"
v-for="item in prizes"
:key="item.name"
>
<div class="prize-money">{{ item.money }}</div>
<div class="prize-money">
{{ item.money }}
</div>
<div class="prize-name">{{ item.name }}</div>
<div class="prize-desc flex flex-col flex-center">
<div
@@ -49,23 +52,24 @@
const prizes = [
{
money: 'US$5000',
name: 'Grand Prize',
name: 'Grand Awards',
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
},
{
money: 'US$3000',
name: 'First Runner-Up',
name: 'Gold Awards',
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
},
{
money: 'US$2000',
name: 'Second Runner-Up',
name: 'Silver Awards',
desc: ['Cash Award', 'Award Ceritificate', 'Global Media Exposure']
},
{
money: 'Certification',
money: 'Award\nCertification',
name: 'Finalists',
desc: ['Award Ceritificate', 'Global Media Exposure']
desc: ['Award Ceritificate', 'Global Media Exposure'],
smaller: true
}
]
@@ -214,10 +218,22 @@
no-repeat;
background-size: 100% 100%;
}
&.smaller {
.prize-money {
font-size: 3.6rem;
line-height: 3.8rem;
}
}
.prize-money {
font-family: 'PoppinsBold';
font-weight: bold;
font-size: 4rem;
white-space: pre-line;
text-align: center;
line-height: 7.6rem;
&.smaller {
font-size: 3.6rem;
}
}
.prize-name {
font-family: 'PoppinsMedium';

View File

@@ -32,25 +32,25 @@ const criteriaList = ref([
{
icon: criteria1,
name: 'Originality',
desc: 'Unique perspective and innovative approach to fashion design',
desc: 'Unique perspective and\ninnovative approach to\nfashion design',
style: { width: '13rem', height: '17rem' }
},
{
icon: criteria2,
name: 'Creativity',
desc: 'Artistic vision and exceptional design excellence',
desc: 'Artistic vision and exceptional\ndesign excellence',
style: { width: '16rem', height: '18rem' }
},
{
icon: criteria3,
name: 'AiDA Integration',
desc: 'Effective application of AI design tools and functions',
desc: 'Effective application of\nAiDA functions',
style: { width: '16rem', height: '18rem' }
},
{
icon: criteria4,
name: 'Execution',
desc: 'Quality of presentation and technical craftsmanship',
desc: 'Quality of presentation and\ntechnical craftsmanship',
style: { width: '18.8rem', height: '18rem' }
}
])
@@ -166,6 +166,7 @@ onBeforeUnmount(() => {
font-size: 2.4rem;
color: #e0e0e0;
text-align: center;
white-space: pre-line;
}
}
}

View File

@@ -1,5 +1,9 @@
<template>
<div class="blocks-list flex" ref="root" :class="{ 'in-view': inView }">
<div
class="blocks-list flex"
ref="root"
:class="{ 'in-view': inView }"
>
<div
class="block-item flex flex-col flex-center"
v-for="(item, idx) in blocksList"
@@ -17,21 +21,21 @@
import { ref, onMounted, onUnmounted } from 'vue'
const blocksList = ref([
{
number: 'NETWORKING\n OPPORTUNITIES',
label: 'with international\nmedia and designers'
},
{
number: 'INTERNATIONAL\nMEDIA EXPOSE',
label: 'through\nleading outlets'
},
{
number: 'UP TO\nUS$9000',
label: 'in total prize\npool awards'
label: 'In total cash prizes'
},
{
number: 'TRAVEL\NALLOWANCE',
label: 'for finalists to attend\naward ceremony'
number: 'GLOBAL MEDIA EXPOSE',
label: 'Showcased by top\ninternational media platforms'
},
{
number: 'NETWORKING\n OPPORTUNITIES',
label: 'Build connections with\ndesigners and industry leaders'
},
{
number: 'AWARD CEREMONY\nIN HONG KONG',
label: 'Travel allowance\nprovided for finalists'
}
])
const root = ref<HTMLElement | null>(null)
@@ -40,7 +44,7 @@
onMounted(() => {
io = new IntersectionObserver(
(entries) => {
entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
// 延迟 0.5s 后触发动画并断开观察
@@ -112,17 +116,17 @@
/* 当组件进入视口并且等待 0.5s 后,.in-view 会加入根节点,下面规则触发动画 */
.in-view .block-item .number {
animation: scaleIn 0.48s cubic-bezier(.2,.9,.2,1) forwards;
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: var(--delay);
}
.in-view .block-item .label {
animation: scaleIn 0.48s cubic-bezier(.2,.9,.2,1) forwards;
animation: scaleIn 0.48s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: calc(var(--delay) + 0.12s);
}
.in-view .block-item .line {
animation: growLine 0.7s cubic-bezier(.2,.9,.2,1) forwards;
animation: growLine 0.7s cubic-bezier(0.2, 0.9, 0.2, 1) forwards;
animation-delay: calc(var(--delay) + 0.18s);
}

View File

@@ -67,27 +67,35 @@
const points = ref([
{
label: 'Select Top 20',
time: 'May',
desc: 'Submit your design concept, mood board, and initial sketch.'
label: 'Application',
subLabel:'Deadline',
time: 'Jul 15',
desc: 'Application deadline and\nentry review process\nbegins.'
},
{
label: `Top 20`,
subLabel: 'Collections Finalize',
time: 'June',
desc: 'Complete collections, physical garments, and AiDA process videos due.'
label: `20 Finallists`,
subLabel: 'Announced',
time: 'Aug 30',
desc: 'Announcement of 20\nfinalists entering final\nevaluation stage.'
},
{
label: `Top 3`,
subLabel: 'Finalists Select',
time: 'August',
desc: 'Complete collections, physical garments, and AiDA process videos due.'
label: `Finallist\nSubmission`,
subLabel: 'Deadline',
time: 'Sept 30',
desc: 'Finalists submit\ncompleted outfits for\nfinal assessment.'
},
{
label: 'Award Ceremony',
time: 'November',
desc: 'Winners revealed with media coverage and live showcase.'
}
label: 'Receiving Outfits',
subLabel:'from Finallists',
time: 'October',
desc: 'AiDA receives physical\noutfits from all 20\nfinalists.'
},
{
label: 'Award',
subLabel:'Ceremony',
time: 'Nov 12',
desc: 'Award Ceremony &\nCommunity Gathering\n Soho House.'
},
])
const playAnimation = () => {
@@ -98,17 +106,12 @@
const timeline = containerRef.value.querySelector('.timeline-point')
const tl = gsap.timeline()
if (title && subtitle) {
tl.from([title, subtitle], {
scaleX: 0,
autoAlpha: 0,
transformOrigin: '50% 50%',
duration: 0.6,
stagger: 0.1,
ease: 'power2.out'
})
}
// 我们使用一个统一的开始 label使横线、timeline 裁剪与所有文字同时启动,
// 点图标在它们完成后立即开始。
tl.addLabel('start')
// 整体 timeline 的裁剪展开(与 start 同步)
if (timeline) {
tl.fromTo(
timeline,
@@ -119,10 +122,12 @@
clipPath: 'inset(0 0% 0 0)',
duration: 1.6,
ease: 'power1.out'
}
},
'start'
)
}
// 线条动画(与 start 同步)
if (line) {
tl.from(
line,
@@ -132,7 +137,56 @@
duration: 1.3,
ease: 'power1.out'
},
'-=1.1'
'start'
)
}
// 标题与副标题(与 start 同步)
if (title && subtitle) {
tl.from(
[title, subtitle],
{
scaleX: 0,
autoAlpha: 0.5,
transformOrigin: '50% 50%',
duration: 0.6,
stagger: 0.1,
ease: 'power2.out'
},
'start'
)
}
// 行内文字(标签、时间、描述)与 start 同步开始
const textItems = containerRef.value.querySelectorAll(
'.item-label, .item-time, .item-desc .txt'
)
if (textItems && textItems.length) {
tl.from(
textItems,
{
autoAlpha: 0.5,
duration: 0.6,
stagger: 0.08,
ease: 'power2.out'
},
'start'
)
}
// 所有文字与线条完成后,立即开始点图标动画(按顺序出现)
const icons = containerRef.value.querySelectorAll('.point-icon')
if (icons && icons.length) {
// 与 'start' 标签同步开始:改为纯淡入动画(移除缩放)
tl.from(
icons,
{
autoAlpha: 0,
duration: 2,
stagger: 0.12,
ease: 'power2.out'
},
'start+=0.3'
)
}
@@ -211,7 +265,7 @@
font-size: 2.8rem;
text-align: center;
white-space: pre-line;
height: 6rem;
// height: 6rem;
justify-content: center;
}
}
@@ -272,6 +326,7 @@
color: #e0e0e0;
width: 31.2rem;
height: 10.2rem;
white-space: pre-line;
}
}
}

View File

@@ -1,23 +1,26 @@
<template>
<div class="award-container">
<div class="header flex align-center space-between">
<div class="header-left">
<img
src="@/assets/images/award/code_create_logo.png"
class="logo"
/>
</div>
<div
class="header-right flex align-center"
@click="handleBtnClick"
>
<div class="text">{{ btnText }}</div>
<img
src="@/assets/images/award/arrow.png"
alt=""
class="arrow"
/>
<div class="header-wrapper">
<div class="header flex align-center space-between">
<div class="header-left">
<img
src="@/assets/images/award/code_create_logo.png"
class="logo"
/>
</div>
<div
class="header-right flex align-center"
@click="handleBtnClick"
>
<div class="text">{{ btnText }}</div>
<img
src="@/assets/images/award/arrow.png"
alt=""
class="arrow"
/>
</div>
</div>
<div class="header-placeholder"></div>
</div>
<router-view />
<div class="footer flex space-between align-center">
@@ -142,6 +145,7 @@
height: 100vh;
// 隐藏滚动条箭头,只显示滚动条本体
box-sizing: border-box;
&::-webkit-scrollbar {
display: none;
width: 0;
@@ -150,28 +154,37 @@
scrollbar-width: none;
-ms-overflow-style: none;
}
.header {
height: 8rem;
background-color: #232323;
padding-left: 21.5rem;
padding-right: 8.6rem;
box-sizing: border-box;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
.header-wrapper {
.header-placeholder {
height: 8rem;
}
.header-right {
column-gap: 1rem;
cursor: pointer;
.text {
font-size: 1.6rem;
color: #fff;
.header {
height: 8rem;
background-color: #232323;
padding-left: 21.5rem;
padding-right: 8.6rem;
box-sizing: border-box;
position: fixed;
top: 0;
width: 100%;
z-index: 9;
.header-left {
.logo {
width: 13rem;
height: 5rem;
}
}
.arrow {
width: 2.4rem;
height: 2.4rem;
.header-right {
column-gap: 1rem;
cursor: pointer;
.text {
font-size: 1.6rem;
color: #fff;
}
.arrow {
width: 2.4rem;
height: 2.4rem;
}
}
}
}

View File

@@ -1,6 +1,16 @@
<template>
<div class="award-page">
<div class="banner">
<video
src="@/assets/images/award/banner.mp4"
autoplay
muted
loop
class="banner-video"
playsinline
webkit-playsinline
x5-playsinline
></video>
<div
class="submit-btn flex flex-center"
@click="handleSubmitApplication"
@@ -54,9 +64,14 @@
}
.banner {
height: 108rem;
background: url('@/assets/images/award/banner.png') no-repeat;
background-size: cover;
// background: url('@/assets/images/award/banner.png') no-repeat;
// background-size: cover;
position: relative;
.banner-video {
width: 100%;
height: 100%;
object-fit: cover;
}
.submit-btn {
width: 41rem;
height: 6.394rem;
@@ -91,7 +106,7 @@
font-weight: 400;
font-size: 2rem;
line-height: 2.2rem;
color: #232323E5;
color: #232323e5;
}
}
}