chore: 删除award
3
src/assets/icons/CCrop.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 18H20V7C20 6.20435 19.6839 5.44129 19.1213 4.87868C18.5587 4.31607 17.7956 4 17 4H6V0H4V4H0V6H4V17C4 17.7956 4.31607 18.5587 4.87868 19.1213C5.44129 19.6839 6.20435 20 7 20H18V24H20V20H24V18ZM7 18C6.73478 18 6.48043 17.8946 6.29289 17.7071C6.10536 17.5196 6 17.2652 6 17V6H17C17.2652 6 17.5196 6.10536 17.7071 6.29289C17.8946 6.48043 18 6.73478 18 7V18H7Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 495 B |
3
src/assets/icons/CPublish.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 8H12C11.2647 8 10.6667 8.598 10.6667 9.33333C10.6667 10.0687 10.0687 10.6667 9.33333 10.6667H6.66667C5.93133 10.6667 5.33333 10.0687 5.33333 9.33333C5.33333 8.598 4.73533 8 4 8H2C0.897333 8 0 8.89733 0 10V12.6667C0 14.5047 1.49533 16 3.33333 16H12.6667C14.5047 16 16 14.5047 16 12.6667V10C16 8.89733 15.1027 8 14 8ZM14.6667 12.6667C14.6667 13.7693 13.7693 14.6667 12.6667 14.6667H3.33333C2.23067 14.6667 1.33333 13.7693 1.33333 12.6667V10C1.33333 9.632 1.632 9.33333 2 9.33333L4 9.332V9.33333C4 10.804 5.196 12 6.66667 12H9.33333C10.804 12 12 10.804 12 9.33333H14C14.368 9.33333 14.6667 9.632 14.6667 10V12.6667ZM4.862 3.52867C4.60133 3.268 4.60133 2.84667 4.862 2.586L7.05733 0.390667C7.31467 0.133333 7.65267 0.004 7.99067 0.002L8 0L8.00933 0.002C8.348 0.004 8.68533 0.133333 8.94267 0.390667L11.138 2.586C11.3987 2.84667 11.3987 3.268 11.138 3.52867C11.008 3.65867 10.8373 3.724 10.6667 3.724C10.496 3.724 10.3253 3.65867 10.1953 3.52867L8.66667 2V6.66667C8.66667 7.03533 8.36867 7.33333 8 7.33333C7.63133 7.33333 7.33333 7.03533 7.33333 6.66667V2L5.80467 3.52867C5.544 3.78933 5.12267 3.78933 4.862 3.52867Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
3
src/assets/icons/CSave.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.024 2.74801L13.252 0.976013C12.9432 0.665575 12.576 0.419466 12.1714 0.251935C11.7669 0.0844031 11.3332 -0.00122304 10.8953 1.31975e-05H3.33333C2.4496 0.00107177 1.60237 0.352601 0.97748 0.977493C0.352588 1.60239 0.00105857 2.44962 0 3.33335L0 12.6667C0.00105857 13.5504 0.352588 14.3976 0.97748 15.0225C1.60237 15.6474 2.4496 15.999 3.33333 16H12.6667C13.5504 15.999 14.3976 15.6474 15.0225 15.0225C15.6474 14.3976 15.9989 13.5504 16 12.6667V5.10468C16.0012 4.66684 15.9156 4.2331 15.7481 3.82858C15.5805 3.42405 15.3344 3.05678 15.024 2.74801ZM11.3333 1.38668V2.00001C11.3333 2.53045 11.1226 3.03915 10.7475 3.41423C10.3725 3.7893 9.86377 4.00001 9.33333 4.00001H6.66667C6.13623 4.00001 5.62753 3.7893 5.25245 3.41423C4.87738 3.03915 4.66667 2.53045 4.66667 2.00001V1.33335H10.8953C11.0429 1.33466 11.1898 1.35255 11.3333 1.38668ZM14.6667 12.6667C14.6667 13.1971 14.456 13.7058 14.0809 14.0809C13.7058 14.456 13.1971 14.6667 12.6667 14.6667H3.33333C2.8029 14.6667 2.29419 14.456 1.91912 14.0809C1.54405 13.7058 1.33333 13.1971 1.33333 12.6667V3.33335C1.33333 2.80291 1.54405 2.29421 1.91912 1.91913C2.29419 1.54406 2.8029 1.33335 3.33333 1.33335V2.00001C3.33439 2.88374 3.68592 3.73097 4.31081 4.35587C4.93571 4.98076 5.78294 5.33229 6.66667 5.33335H9.33333C10.1717 5.33074 10.9781 5.01179 11.5914 4.44026C12.2047 3.86872 12.5797 3.08674 12.6413 2.25068L14.0813 3.69068C14.455 4.0666 14.6653 4.57468 14.6667 5.10468V12.6667Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 198 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="22" height="12" viewBox="0 0 22 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 1L11 11L21 1" stroke="#585858" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 327 B |
|
Before Width: | Height: | Size: 492 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 231 KiB |
|
Before Width: | Height: | Size: 913 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.6144 18.7388L5.16736 4.29184C4.95412 4.0786 4.60838 4.0786 4.39514 4.29184C4.18189 4.50509 4.18189 4.85082 4.39514 5.06407L18.8421 19.5111C19.0554 19.7243 19.4011 19.7243 19.6144 19.5111C19.8276 19.2978 19.8276 18.9521 19.6144 18.7388Z" fill="#232323"/>
|
||||
<path d="M5.15908 19.5378L19.6061 5.09079C19.8193 4.87755 19.8193 4.53181 19.6061 4.31857C19.3928 4.10533 19.0471 4.10533 18.8339 4.31857L4.38685 18.7656C4.17361 18.9788 4.17361 19.3246 4.38685 19.5378C4.6001 19.751 4.94583 19.751 5.15908 19.5378Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 636 B |
|
Before Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 339 KiB |
|
Before Width: | Height: | Size: 443 KiB |
|
Before Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 400 KiB |
|
Before Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="20" height="20" rx="2.79453" fill="url(#pattern0_226_198)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_226_198" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_226_198" transform="scale(0.0104167)"/>
|
||||
</pattern>
|
||||
<image id="image0_226_198" width="96" height="96" preserveAspectRatio="none" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 340 KiB |
|
Before Width: | Height: | Size: 930 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 198 KiB |
@@ -1,10 +0,0 @@
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_226_195)">
|
||||
<path d="M-0.00195312 1.4335C-0.00195312 0.641696 0.656004 0 1.46782 0H18.5422C19.354 0 20.0119 0.641696 20.0119 1.4335V18.5804C20.0119 19.3722 19.354 20.0139 18.5422 20.0139H1.46782C0.656004 20.0139 -0.00195312 19.3722 -0.00195312 18.5804V1.4335ZM6.18109 16.7541V7.71661H3.17776V16.7541H6.18109ZM4.68005 6.482C5.72703 6.482 6.37873 5.78902 6.37873 4.92092C6.35996 4.03405 5.72828 3.35983 4.70006 3.35983C3.67185 3.35983 3.00013 4.0353 3.00013 4.92092C3.00013 5.78902 3.65183 6.482 4.66003 6.482H4.68005ZM10.8193 16.7541V11.7069C10.8193 11.4367 10.8393 11.1665 10.9194 10.9739C11.1358 10.4347 11.6299 9.87561 12.4605 9.87561C13.5475 9.87561 13.9815 10.7037 13.9815 11.9195V16.7541H16.9848V11.5705C16.9848 8.79361 15.5038 7.50271 13.5274 7.50271C11.9338 7.50271 11.2196 8.37832 10.8193 8.995V9.02627H10.7993L10.8193 8.995V7.71661H7.81723C7.85475 8.5647 7.81723 16.7541 7.81723 16.7541H10.8193Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_226_195">
|
||||
<rect width="20.0139" height="20.0139" rx="1.55252" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 47 KiB |
@@ -1,12 +0,0 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_226_203)">
|
||||
<path d="M20 17C20 18.6569 18.6569 20 17 20H3C1.34307 20 0 18.6569 0 17V3C0 1.34313 1.34313 0 3 0H17C18.6569 0 20 1.34313 20 3V17Z" fill="white"/>
|
||||
<path d="M13.3881 7.45803C11.7739 7.54236 10.3702 8.03169 9.2306 9.13723C8.0792 10.2542 7.55366 11.6228 7.69726 13.3195C7.06633 13.2414 6.49166 13.1554 5.91373 13.1067C5.71413 13.0899 5.47726 13.1138 5.3082 13.2092C4.747 13.5258 4.20906 13.8834 3.57133 14.282C3.68833 13.7528 3.76406 13.2894 3.89813 12.8437C3.99673 12.5161 3.95106 12.3338 3.64926 12.1204C1.71153 10.7523 0.894728 8.70496 1.50599 6.59703C2.07153 4.64703 3.46033 3.46443 5.3474 2.84796C7.92313 2.00663 10.8177 2.86483 12.3839 4.90976C12.9495 5.64843 13.2964 6.47749 13.3881 7.45803ZM5.95893 6.80123C5.9738 6.41569 5.63973 6.06836 5.24293 6.05676C4.83666 6.04483 4.50253 6.35529 4.49066 6.75563C4.47866 7.16136 4.789 7.48649 5.1982 7.49689C5.60386 7.50716 5.94393 7.19629 5.95893 6.80123ZM9.835 6.05649C9.43673 6.06383 9.1002 6.40303 9.10726 6.79009C9.11453 7.19129 9.44466 7.50516 9.8542 7.50023C10.2648 7.49529 10.5762 7.17809 10.5723 6.76843C10.5689 6.36629 10.2403 6.04909 9.835 6.05649Z" fill="#232323"/>
|
||||
<path d="M17.0146 17.5216C16.5035 17.294 16.0346 16.9525 15.5354 16.9004C15.0381 16.8484 14.5154 17.1353 13.9951 17.1885C12.4104 17.3506 10.9907 16.909 9.82001 15.8264C7.59355 13.767 7.91168 10.6094 10.4876 8.92184C12.777 7.42197 16.1345 7.92197 17.7487 10.0031C19.1573 11.8191 18.9917 14.2298 17.2721 15.7554C16.7745 16.1969 16.5955 16.5602 16.9148 17.1423C16.9737 17.2498 16.9804 17.3858 17.0146 17.5216ZM11.1963 11.8883C11.5217 11.8886 11.7897 11.634 11.802 11.3126C11.815 10.9723 11.5413 10.6869 11.2006 10.6855C10.8632 10.684 10.5806 10.9734 10.5924 11.3086C10.6035 11.6288 10.8733 11.8879 11.1963 11.8883ZM14.9471 10.6868C14.6314 10.6846 14.3631 10.9431 14.3502 11.2621C14.3365 11.6032 14.6017 11.8834 14.9393 11.8842C15.2658 11.8854 15.5239 11.6384 15.5357 11.3134C15.5483 10.9715 15.2831 10.6892 14.9471 10.6868Z" fill="#232323"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_226_203">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 811 B |
BIN
src/assets/images/test.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
1184
src/router/index.ts
@@ -1,529 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="apply-container flex flex-col"
|
||||
id="apply"
|
||||
ref="applyRef"
|
||||
>
|
||||
<div
|
||||
class="title animation-element"
|
||||
ref="applyTitleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.howToApply') }}
|
||||
</div>
|
||||
<div
|
||||
class="sub-title animation-element"
|
||||
ref="applySubTitleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.stepByStep') }}
|
||||
</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">{{ $t(item.type) }}</div>
|
||||
</div>
|
||||
<div class="context-container flex flex-center">
|
||||
<div
|
||||
class="context"
|
||||
v-for="el in item.desc"
|
||||
>
|
||||
{{ $t(el) }}
|
||||
</div>
|
||||
<div
|
||||
class="list"
|
||||
v-if="item.listTitle"
|
||||
>
|
||||
<div class="list-title">{{ $t(item.listTitle) }}</div>
|
||||
<ul class="list-items">
|
||||
<li
|
||||
class="list-item"
|
||||
v-for="el in item.list"
|
||||
>
|
||||
{{ $t(el) }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom flex">
|
||||
<div class="step-3 flex flex-col animation-element" ref="step3Ref">
|
||||
<div class="header">{{ $t('AwardsPage.step3Title') }}</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>{{ $t('AwardsPage.processVideo') }}</div>
|
||||
</div>
|
||||
<div class="desc-wrapper flex flex-col space-between">
|
||||
<div class="item-desc">
|
||||
{{ $t('AwardsPage.processVideoDesc') }}
|
||||
</div>
|
||||
<ul class="desc-lists">
|
||||
<div class="desc-lists-title">
|
||||
{{ $t('AwardsPage.videoRequirements') }}
|
||||
</div>
|
||||
<li>{{ $t('AwardsPage.videoFormat') }}</li>
|
||||
<li>{{ $t('AwardsPage.videoResolution') }}</li>
|
||||
<li>{{ $t('AwardsPage.videoDuration') }}</li>
|
||||
<li>{{ $t('AwardsPage.videoSize') }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-item">
|
||||
<div class="item-header flex align-center">
|
||||
<div class="point"></div>
|
||||
<div>{{ $t('AwardsPage.fileName') }}</div>
|
||||
</div>
|
||||
<div class="item-desc indent">
|
||||
{{ $t('AwardsPage.fileNameDesc') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<div class="content-item flex flex-col">
|
||||
<div class="item-header flex align-center">
|
||||
<div class="point"></div>
|
||||
<div>{{ $t('AwardsPage.designPortfolio') }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="desc-wrapper flex-1 flex flex-col space-between"
|
||||
>
|
||||
<ul class="desc-lists">
|
||||
<div class="desc-lists-title">
|
||||
<p>
|
||||
{{ $t('AwardsPage.submitPdf') }}
|
||||
</p>
|
||||
<p>{{ $t('AwardsPage.requiredStructure') }}</p>
|
||||
</div>
|
||||
<li>{{ $t('AwardsPage.pdfDesignTitle') }}</li>
|
||||
<li>{{ $t('AwardsPage.pdfMoodboard') }}</li>
|
||||
<li>{{ $t('AwardsPage.pdfConcept') }}</li>
|
||||
<div>{{ $t('AwardsPage.pdfConceptDesc') }}</div>
|
||||
</ul>
|
||||
<ul class="desc-lists">
|
||||
<div class="desc-lists-title">
|
||||
<p>{{ $t('AwardsPage.pdfRequirements') }}</p>
|
||||
</div>
|
||||
<li>{{ $t('AwardsPage.pdfMaxPages') }}</li>
|
||||
<li>{{ $t('AwardsPage.pdfMaxSize') }}</li>
|
||||
<li>
|
||||
{{ $t('AwardsPage.pdfLanguage') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step-4 animation-element" ref="step4Ref">
|
||||
<div class="header flex flex-col flex-center">
|
||||
<p>{{ $t('AwardsPage.step4Title') }}</p>
|
||||
<p class="sub-title">{{ $t('AwardsPage.step4Subtitle') }}</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">
|
||||
{{ $t('AwardsPage.step4Desc') }}
|
||||
</div>
|
||||
<li>{{ $t('AwardsPage.finalistPieces') }}</li>
|
||||
<li>
|
||||
{{ $t('AwardsPage.finalistBasedOn') }}
|
||||
</li>
|
||||
<li>
|
||||
{{ $t('AwardsPage.finalistShipping') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const leftRequirment = ref([
|
||||
{
|
||||
type: 'AwardsPage.step1Title',
|
||||
desc: ['AwardsPage.step1Desc']
|
||||
},
|
||||
{
|
||||
type: 'AwardsPage.step2Title',
|
||||
desc: ['AwardsPage.step2Desc'],
|
||||
listTitle: 'AwardsPage.step2ListTitle',
|
||||
list: [
|
||||
'AwardsPage.step2List[0]',
|
||||
'AwardsPage.step2List[1]',
|
||||
'AwardsPage.step2List[2]'
|
||||
],
|
||||
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 initAnimations = () => {
|
||||
if (hasPlayedAnim.value) return
|
||||
|
||||
timeline = gsap.timeline({
|
||||
defaults: { ease: 'back.out(1.7)' }
|
||||
})
|
||||
|
||||
if (applyTitleRef.value && applySubTitleRef.value) {
|
||||
timeline.to([applyTitleRef.value, applySubTitleRef.value], {
|
||||
scale: 1,
|
||||
opacity: 1,
|
||||
duration: 0.6,
|
||||
stagger: 0.1
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
y: 0,
|
||||
duration: 0.6,
|
||||
stagger: 0.2
|
||||
}, '>')
|
||||
}
|
||||
|
||||
hasPlayedAnim.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setupApplyInitialState()
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
initAnimations()
|
||||
observer?.disconnect()
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
threshold: 0.3,
|
||||
rootMargin: '0px 0px -100px 0px'
|
||||
}
|
||||
)
|
||||
|
||||
// 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()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.animation-element{
|
||||
will-change: opacity transform;
|
||||
}
|
||||
.apply-container {
|
||||
flex: 1;
|
||||
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;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 4rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
.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: 2.4rem;
|
||||
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>
|
||||
@@ -1,202 +0,0 @@
|
||||
<template>
|
||||
<div class="bloom flex flex-col align-center">
|
||||
<div
|
||||
class="title"
|
||||
ref="titleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.bloomYourCreativity') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="season"
|
||||
ref="subtitleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.themeOf2026') }}
|
||||
</div>
|
||||
<div
|
||||
class="desc"
|
||||
ref="textRef"
|
||||
>
|
||||
<p class="section-1">
|
||||
{{ $t('AwardsPage.bloomText.desc1.regular1') }}
|
||||
<span class="arial-bold">
|
||||
{{ $t('AwardsPage.bloomText.desc1.bold1') }}
|
||||
</span>
|
||||
{{ $t('AwardsPage.bloomText.desc1.regular2') }}
|
||||
<span class="arial-bold">
|
||||
{{ $t('AwardsPage.bloomText.desc1.bold2') }}
|
||||
</span>
|
||||
{{ $t('AwardsPage.bloomText.desc1.regular3') }}
|
||||
<span class="arial-bold">
|
||||
{{ $t('AwardsPage.bloomText.desc1.bold3') }}
|
||||
</span>
|
||||
{{ $t('AwardsPage.bloomText.desc1.regular4') }}
|
||||
<span class="arial-bold">
|
||||
{{ $t('AwardsPage.bloomText.desc1.bold4') }}
|
||||
</span>
|
||||
{{ $t('AwardsPage.bloomText.desc1.regular5') }}
|
||||
</p>
|
||||
<p class="section-2">
|
||||
{{ $t('AwardsPage.bloomText.desc2.regular1') }}
|
||||
<span class="arial-bold">
|
||||
{{ $t('AwardsPage.bloomText.desc2.bold1') }}
|
||||
</span>
|
||||
{{ $t('AwardsPage.bloomText.desc2.regular2') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const titleRef = ref<HTMLElement | null>(null)
|
||||
const subtitleRef = ref<HTMLElement | null>(null)
|
||||
const textRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const hasPlayedBloomAnim = ref(false)
|
||||
let bloomObserver: IntersectionObserver | null = null
|
||||
|
||||
const setupBloomInitialState = () => {
|
||||
const titleEls = [titleRef.value, subtitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
if (titleEls.length) {
|
||||
gsap.set(titleEls, {
|
||||
opacity: 0,
|
||||
// start larger than final size, then animate down to scale:1
|
||||
scale: 1.6,
|
||||
transformOrigin: '50% 50%'
|
||||
})
|
||||
}
|
||||
|
||||
if (textRef.value) {
|
||||
// start below and hidden
|
||||
gsap.set(textRef.value, {
|
||||
opacity: 0,
|
||||
y: 60
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const playBloomAnimation = () => {
|
||||
if (hasPlayedBloomAnim.value) return
|
||||
const titleEls = [titleRef.value, subtitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
const textEl = textRef.value
|
||||
if (!titleEls.length || !textEl) return
|
||||
|
||||
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
|
||||
|
||||
tl.to(titleEls, {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.9,
|
||||
ease: 'back.out(1.6)',
|
||||
stagger: 0.12
|
||||
})
|
||||
|
||||
tl.to(
|
||||
textEl,
|
||||
{
|
||||
opacity: 1,
|
||||
y: -12,
|
||||
scale: 1.05,
|
||||
duration: 0.3,
|
||||
ease: 'power2.out'
|
||||
},
|
||||
'-=0.3'
|
||||
)
|
||||
tl.to(
|
||||
textEl,
|
||||
{
|
||||
y: 0,
|
||||
scale: 1,
|
||||
duration: 0.18,
|
||||
ease: 'bounce.out'
|
||||
},
|
||||
'+=0.08'
|
||||
)
|
||||
|
||||
hasPlayedBloomAnim.value = true
|
||||
bloomObserver?.disconnect()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setupBloomInitialState()
|
||||
if ('IntersectionObserver' in window) {
|
||||
bloomObserver = new IntersectionObserver(
|
||||
entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
playBloomAnimation()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
)
|
||||
if (titleRef.value) {
|
||||
bloomObserver.observe(titleRef.value)
|
||||
}
|
||||
} else {
|
||||
// fallback
|
||||
playBloomAnimation()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
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;
|
||||
background-size: 100% 100%;
|
||||
.title {
|
||||
font-size: 4rem;
|
||||
color: #232323;
|
||||
margin-bottom: 2.4rem;
|
||||
}
|
||||
.logo {
|
||||
margin-bottom: 2.2rem;
|
||||
}
|
||||
.season {
|
||||
font-size: 3rem;
|
||||
color: #c7342c;
|
||||
margin-bottom: 6.6rem;
|
||||
}
|
||||
.desc {
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2.4rem;
|
||||
color: #585858;
|
||||
text-align: center;
|
||||
padding: 0 21.5rem;
|
||||
line-height: 4.5rem;
|
||||
margin-bottom: 12.3rem;
|
||||
white-space: pre-line;
|
||||
.section-2 {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,233 +0,0 @@
|
||||
<template>
|
||||
<div class="judges-container flex flex-col align-center">
|
||||
<div class="title" ref="judgesTitleRef">{{ $t('AwardsPage.panelOfJudges') }}</div>
|
||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||
<div class="sub-title" ref="judgesSubTitleRef">{{ $t('AwardsPage.expertise') }}</div>
|
||||
<div class="judgement-list" ref="judgementListRef">
|
||||
<div
|
||||
class="judgement-item flex flex-col align-center"
|
||||
v-for="item in judgements"
|
||||
:key="item.name"
|
||||
>
|
||||
<img :src="item.picture" class="picture" />
|
||||
<div class="name">{{ $t(item.name) }}</div>
|
||||
<div class="desc">{{ $t(item.desc) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, nextTick, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
import jae from '@/assets/images/award/jae.png'
|
||||
import diego from '@/assets/images/award/diego.png'
|
||||
import gregory from '@/assets/images/award/gregory.png'
|
||||
import vincenzo from '@/assets/images/award/vincenzo.png'
|
||||
import tim from '@/assets/images/award/tim.png'
|
||||
import desmond from '@/assets/images/award/desmond.png'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const judgements = [
|
||||
{
|
||||
picture: jae,
|
||||
name: 'Jae Hyuk Lim',
|
||||
desc: 'AwardsPage.judgesHat.jae'
|
||||
},
|
||||
{
|
||||
picture: diego,
|
||||
name: 'Diego Dultzin Lacoste',
|
||||
desc: 'AwardsPage.judgesHat.diego'
|
||||
},
|
||||
{
|
||||
picture: gregory,
|
||||
name: 'Gregory de la Hogue Moran',
|
||||
desc: 'AwardsPage.judgesHat.gregory'
|
||||
},
|
||||
{
|
||||
picture: vincenzo,
|
||||
name: 'Vincenzo La Torre',
|
||||
desc: 'AwardsPage.judgesHat.vincenzo'
|
||||
},
|
||||
{
|
||||
picture: tim,
|
||||
name: 'Tim Lim',
|
||||
desc: 'AwardsPage.judgesHat.tim'
|
||||
},
|
||||
{
|
||||
picture: desmond,
|
||||
name: 'Desmond Lim',
|
||||
desc: 'AwardsPage.judgesHat.desmond'
|
||||
}
|
||||
]
|
||||
|
||||
const judgesTitleRef = ref<HTMLElement | null>(null)
|
||||
const judgesSubTitleRef = ref<HTMLElement | null>(null)
|
||||
const judgementListRef = ref<HTMLElement | null>(null)
|
||||
const hasPlayedJudgementAnim = ref(false)
|
||||
let judgementObserver: IntersectionObserver | null = null
|
||||
|
||||
const setupJudgementInitialState = () => {
|
||||
const titleEls = [judgesTitleRef.value, judgesSubTitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
if (titleEls.length) {
|
||||
gsap.set(titleEls, {
|
||||
opacity: 0,
|
||||
scale: 0,
|
||||
transformOrigin: '50% 50%'
|
||||
})
|
||||
}
|
||||
const items =
|
||||
judgementListRef.value?.querySelectorAll<HTMLElement>('.judgement-item')
|
||||
if (items?.length) {
|
||||
gsap.set(items, {
|
||||
opacity: 0,
|
||||
clipPath: 'inset(0 0 100% 0)'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const playJudgementAnimation = () => {
|
||||
if (hasPlayedJudgementAnim.value) return
|
||||
const titleEls = [judgesTitleRef.value, judgesSubTitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
const listEl = judgementListRef.value
|
||||
if (!titleEls.length || !listEl) return
|
||||
|
||||
const items = Array.from(
|
||||
listEl.querySelectorAll<HTMLElement>('.judgement-item')
|
||||
)
|
||||
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
|
||||
|
||||
tl.to(titleEls, {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.4,
|
||||
ease: 'back.out(1.6)',
|
||||
stagger: 0.1
|
||||
})
|
||||
if (items.length) {
|
||||
const firstRow = items.slice(0, 3)
|
||||
const secondRow = items.slice(3)
|
||||
|
||||
if (firstRow.length) {
|
||||
tl.to(
|
||||
firstRow,
|
||||
{
|
||||
opacity: 1,
|
||||
clipPath: 'inset(0% 0% 0% 0%)',
|
||||
duration: 0.45,
|
||||
stagger: 0.05
|
||||
},
|
||||
'-=0.2'
|
||||
)
|
||||
}
|
||||
|
||||
if (secondRow.length) {
|
||||
tl.to(
|
||||
secondRow,
|
||||
{
|
||||
opacity: 1,
|
||||
clipPath: 'inset(0% 0% 0% 0%)',
|
||||
duration: 0.45,
|
||||
stagger: 0.05
|
||||
},
|
||||
'+=0.1'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
hasPlayedJudgementAnim.value = true
|
||||
judgementObserver?.disconnect()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setupJudgementInitialState()
|
||||
if ('IntersectionObserver' in window) {
|
||||
judgementObserver = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
playJudgementAnimation()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
)
|
||||
if (judgementListRef.value) {
|
||||
judgementObserver.observe(judgementListRef.value)
|
||||
}
|
||||
} else {
|
||||
// Fallback: play immediately if IntersectionObserver unsupported
|
||||
playJudgementAnimation()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
judgementObserver?.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.judges-container {
|
||||
height: 147.4rem;
|
||||
background: url('@/assets/images/award/judges_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding-top: 12.8rem;
|
||||
.title {
|
||||
color: #232323;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 4rem;
|
||||
}
|
||||
.logo {
|
||||
margin: 2.4rem 0 2.2rem;
|
||||
}
|
||||
.sub-title {
|
||||
color: #b10000;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 3rem;
|
||||
margin-bottom: 12rem;
|
||||
}
|
||||
.judgement-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
column-gap: 23.22rem;
|
||||
row-gap: 8rem;
|
||||
padding: 0 25rem 0 26.6rem;
|
||||
div{
|
||||
text-align: center;
|
||||
}
|
||||
.judgement-item {
|
||||
overflow: hidden;
|
||||
.picture {
|
||||
width: 20.2rem;
|
||||
height: 26rem;
|
||||
border-radius: 0.8rem;
|
||||
}
|
||||
.name {
|
||||
margin: 3rem 0 2.4rem;
|
||||
color: #232323;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
.desc {
|
||||
color: #585858;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2rem;
|
||||
white-space: pre-line;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,276 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="prizes-container container flex align-center space-between"
|
||||
ref="prizesRef"
|
||||
>
|
||||
<div class="left flex flex-col flex-center">
|
||||
<div
|
||||
class="title"
|
||||
ref="prizesTitleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.awardPrizes') }}
|
||||
</div>
|
||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||
<div
|
||||
class="desc"
|
||||
ref="prizesSubTitleRef"
|
||||
>
|
||||
{{ $t('AwardsPage.recognition') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="right"
|
||||
ref="prizesRightRef"
|
||||
>
|
||||
<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">
|
||||
{{ $t(item.money) }}
|
||||
</div>
|
||||
<div class="prize-name">{{ $t(item.name) }}</div>
|
||||
<div class="prize-desc flex flex-col flex-center">
|
||||
<div
|
||||
class="desc-item"
|
||||
v-for="el in item.desc"
|
||||
>
|
||||
{{ $t(el) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
isZh: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const prizes = [
|
||||
{
|
||||
money: 'AwardsPage.grandMoney',
|
||||
name: 'AwardsPage.grandAwards',
|
||||
desc: [
|
||||
'AwardsPage.cashAward',
|
||||
'AwardsPage.awardCertificate',
|
||||
'AwardsPage.globalMediaExposure'
|
||||
]
|
||||
},
|
||||
{
|
||||
money: 'AwardsPage.goldMoney',
|
||||
name: 'AwardsPage.goldAwards',
|
||||
desc: [
|
||||
'AwardsPage.cashAward',
|
||||
'AwardsPage.awardCertificate',
|
||||
'AwardsPage.globalMediaExposure'
|
||||
]
|
||||
},
|
||||
{
|
||||
money: 'AwardsPage.silverMoney',
|
||||
name: 'AwardsPage.silverAwards',
|
||||
desc: [
|
||||
'AwardsPage.cashAward',
|
||||
'AwardsPage.awardCertificate',
|
||||
'AwardsPage.globalMediaExposure'
|
||||
]
|
||||
},
|
||||
{
|
||||
money: 'AwardsPage.awardCertification',
|
||||
name: 'AwardsPage.finalists',
|
||||
desc: ['AwardsPage.TravelAllowance', 'AwardsPage.globalMediaExposure'],
|
||||
smaller: !props.isZh
|
||||
}
|
||||
]
|
||||
|
||||
const prizesRef = ref<HTMLElement | null>(null)
|
||||
const prizesTitleRef = ref<HTMLElement | null>(null)
|
||||
const prizesSubTitleRef = ref<HTMLElement | null>(null)
|
||||
const prizesRightRef = ref<HTMLElement | null>(null)
|
||||
const hasPlayedPrizesAnim = ref(false)
|
||||
let prizesObserver: IntersectionObserver | null = null
|
||||
|
||||
const setupPrizesInitialState = () => {
|
||||
const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
if (titleEls.length) {
|
||||
gsap.set(titleEls, {
|
||||
opacity: 0,
|
||||
scale: 0,
|
||||
transformOrigin: '50% 50%'
|
||||
})
|
||||
}
|
||||
if (prizesRightRef.value) {
|
||||
gsap.set(prizesRightRef.value, {
|
||||
'opacity': 0,
|
||||
'y': 40,
|
||||
'scale': 1.08,
|
||||
'--prize-row-gap': '2rem',
|
||||
'--prize-col-gap': '2rem'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const playPrizesAnimation = () => {
|
||||
if (hasPlayedPrizesAnim.value) return
|
||||
const titleEls = [prizesTitleRef.value, prizesSubTitleRef.value].filter(
|
||||
Boolean
|
||||
) as HTMLElement[]
|
||||
|
||||
const tl = gsap.timeline({ defaults: { ease: 'power2.out' } })
|
||||
if (titleEls.length) {
|
||||
tl.to(titleEls, {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.6,
|
||||
ease: 'back.out(1.6)',
|
||||
stagger: 0.1
|
||||
})
|
||||
}
|
||||
if (prizesRightRef.value) {
|
||||
tl.to(
|
||||
prizesRightRef.value,
|
||||
{
|
||||
'opacity': 1,
|
||||
'y': 0,
|
||||
'scale': 1,
|
||||
'--prize-row-gap': '4.2rem',
|
||||
'--prize-col-gap': '4.4rem',
|
||||
'duration': 0.55,
|
||||
'ease': 'back.out(1.4)'
|
||||
},
|
||||
titleEls.length ? '-=0.15' : 0
|
||||
)
|
||||
}
|
||||
|
||||
hasPlayedPrizesAnim.value = true
|
||||
prizesObserver?.disconnect()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setupPrizesInitialState()
|
||||
if ('IntersectionObserver' in window) {
|
||||
prizesObserver = new IntersectionObserver(
|
||||
entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
playPrizesAnimation()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.25 }
|
||||
)
|
||||
if (prizesRef.value) prizesObserver.observe(prizesRef.value)
|
||||
} else {
|
||||
playPrizesAnimation()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
prizesObserver?.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.prizes-container {
|
||||
background: url('@/assets/images/award/prizes_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding: 0 21.4rem 0 34.2rem;
|
||||
box-sizing: border-box;
|
||||
.left {
|
||||
row-gap: 3.6rem;
|
||||
.title {
|
||||
text-align: center;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 4rem;
|
||||
color: #fff;
|
||||
}
|
||||
.desc {
|
||||
text-align: center;
|
||||
color: #f95750;
|
||||
font-family: 'Poppins';
|
||||
font-weight: 400;
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
.right {
|
||||
// height: 45.4rem;
|
||||
// padding: 4.6rem 6.1rem 4.6rem 0;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
row-gap: var(--prize-row-gap, 4.2rem);
|
||||
column-gap: var(--prize-col-gap, 4.4rem);
|
||||
// flex: 1;
|
||||
.prize-item {
|
||||
width: 35.5rem;
|
||||
height: 32.8rem;
|
||||
color: #fff;
|
||||
padding: 4.5rem 0 4.8rem 0;
|
||||
justify-content: space-between;
|
||||
background: url('@/assets/images/award/first_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
&:nth-of-type(2) {
|
||||
background: url('@/assets/images/award/second_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
&:nth-of-type(3) {
|
||||
background: url('@/assets/images/award/grand_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
&:nth-of-type(4) {
|
||||
background: url('@/assets/images/award/certification_bg.png')
|
||||
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';
|
||||
font-weight: 500;
|
||||
font-size: 2.8rem;
|
||||
}
|
||||
.prize-desc {
|
||||
color: #e0e0e0;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2rem;
|
||||
line-height: 3rem;
|
||||
height: 8.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="selection-container container flex flex-col align-center"
|
||||
ref="selectionRef"
|
||||
>
|
||||
<div class="title">{{ $t('AwardsPage.selectionCriteria') }}</div>
|
||||
<!-- <img src="@/assets/images/award/bloom_logo.png" class="logo" /> -->
|
||||
<div class="sub-title">{{ $t('AwardsPage.evaluation') }}</div>
|
||||
<div class="criteria-list flex" ref="criteriaListRef">
|
||||
<div
|
||||
class="item flex flex-col align-center"
|
||||
v-for="item in criteriaList"
|
||||
:key="item.name"
|
||||
>
|
||||
<img :src="item.icon" class="icon" :style="item.style" />
|
||||
<div class="name">{{ $t(item.name) }}</div>
|
||||
<div class="desc">{{ $t(item.desc) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
import criteria1 from '@/assets/images/award/criteria_1.png'
|
||||
import criteria2 from '@/assets/images/award/criteria_2.png'
|
||||
import criteria3 from '@/assets/images/award/criteria_3.png'
|
||||
import criteria4 from '@/assets/images/award/criteria_4.png'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const criteriaList = ref([
|
||||
{
|
||||
icon: criteria1,
|
||||
name: 'AwardsPage.originality',
|
||||
desc: 'AwardsPage.originalityDesc',
|
||||
style: { width: '13rem', height: '17rem' }
|
||||
},
|
||||
{
|
||||
icon: criteria2,
|
||||
name: 'AwardsPage.creativity',
|
||||
desc: 'AwardsPage.creativityDesc',
|
||||
style: { width: '16rem', height: '18rem' }
|
||||
},
|
||||
{
|
||||
icon: criteria3,
|
||||
name: 'AwardsPage.aidaIntegration',
|
||||
desc: 'AwardsPage.aidaIntegrationDesc',
|
||||
style: { width: '16rem', height: '18rem' }
|
||||
},
|
||||
{
|
||||
icon: criteria4,
|
||||
name: 'AwardsPage.execution',
|
||||
desc: 'AwardsPage.executionDesc',
|
||||
style: { width: '18.8rem', height: '18rem' }
|
||||
}
|
||||
])
|
||||
|
||||
const selectionRef = ref<HTMLElement | null>(null)
|
||||
const criteriaListRef = ref<HTMLElement | null>(null)
|
||||
const hasPlayedSelectionAnim = ref(false)
|
||||
let selectionObserver: IntersectionObserver | null = null
|
||||
|
||||
const setupSelectionInitialState = () => {
|
||||
const items =
|
||||
criteriaListRef.value?.querySelectorAll<HTMLElement>('.item') ?? []
|
||||
if (items.length) {
|
||||
gsap.set(items, {
|
||||
opacity: 0,
|
||||
scale: 0,
|
||||
transformOrigin: '50% 50%'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const playSelectionAnimation = () => {
|
||||
if (hasPlayedSelectionAnim.value) return
|
||||
const items =
|
||||
criteriaListRef.value?.querySelectorAll<HTMLElement>('.item') ?? []
|
||||
if (!items.length) return
|
||||
|
||||
gsap.to(items, {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
duration: 0.6,
|
||||
ease: 'back.out(1.6)',
|
||||
stagger: 0.3
|
||||
})
|
||||
|
||||
hasPlayedSelectionAnim.value = true
|
||||
selectionObserver?.disconnect()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
setupSelectionInitialState()
|
||||
if ('IntersectionObserver' in window) {
|
||||
selectionObserver = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
playSelectionAnimation()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.25 }
|
||||
)
|
||||
if (selectionRef.value) {
|
||||
selectionObserver.observe(selectionRef.value)
|
||||
}
|
||||
} else {
|
||||
playSelectionAnimation()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
selectionObserver?.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.selection-container {
|
||||
background: url('@/assets/images/award/selection_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding-top: 9.3rem;
|
||||
.title {
|
||||
color: #fff;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 4rem;
|
||||
}
|
||||
.logo {
|
||||
margin: 2.3rem 0 2.3rem;
|
||||
}
|
||||
.sub-title {
|
||||
color: #f95750;
|
||||
font-family: 'Popins';
|
||||
font-weight: 400;
|
||||
font-size: 3rem;
|
||||
margin-bottom: 11.8rem;
|
||||
}
|
||||
.criteria-list {
|
||||
column-gap: 6rem;
|
||||
.item {
|
||||
height: 44rem;
|
||||
width: 32.2rem;
|
||||
box-sizing: border-box;
|
||||
&:nth-of-type(3) {
|
||||
background: url('@/assets/images/award/criteria_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.icon {
|
||||
width: 18.8rem;
|
||||
height: 18rem;
|
||||
}
|
||||
.name {
|
||||
font-family: 'PoppinsMedium';
|
||||
font-weight: 500;
|
||||
font-size: 2.8rem;
|
||||
color: #fff;
|
||||
margin: 2rem 0 5rem;
|
||||
}
|
||||
.desc {
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2.4rem;
|
||||
color: #e0e0e0;
|
||||
text-align: center;
|
||||
white-space: pre-line;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<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"
|
||||
:key="item.number"
|
||||
:style="{ '--delay': `${idx * 0.18}s` }"
|
||||
>
|
||||
<div class="number">{{ $t(item.number) }}</div>
|
||||
<div class="label">{{ $t(item.label) }}</div>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const blocksList = ref([
|
||||
{
|
||||
number: 'AwardsPage.totalCashPrizes',
|
||||
label: 'AwardsPage.totalCashPrizesLabel'
|
||||
},
|
||||
{
|
||||
number: 'AwardsPage.globalMediaExpose',
|
||||
label: 'AwardsPage.globalMediaExposeLabel'
|
||||
},
|
||||
{
|
||||
number: 'AwardsPage.networkingOpportunities',
|
||||
label: 'AwardsPage.networkingOpportunitiesLabel'
|
||||
},
|
||||
{
|
||||
number: 'AwardsPage.awardCeremonyHongKong',
|
||||
label: 'AwardsPage.awardCeremonyLabel'
|
||||
}
|
||||
])
|
||||
const root = ref<HTMLElement | null>(null)
|
||||
const inView = ref(false)
|
||||
let io: IntersectionObserver | null = null
|
||||
|
||||
onMounted(() => {
|
||||
io = new IntersectionObserver(
|
||||
entries => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
// 延迟 0.5s 后触发动画并断开观察
|
||||
setTimeout(() => {
|
||||
inView.value = true
|
||||
}, 500)
|
||||
if (io) {
|
||||
io.disconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ threshold: 0.05 }
|
||||
)
|
||||
if (root.value) {
|
||||
io.observe(root.value)
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
io?.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.blocks-list {
|
||||
height: 31.4rem;
|
||||
background: linear-gradient(98.55deg, #232323 18.22%, #898989 101.1%);
|
||||
|
||||
.block-item {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
white-space: pre-line;
|
||||
row-gap: 3rem;
|
||||
/* text scale-in animations */
|
||||
.number {
|
||||
font-size: 3.6rem;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
.label {
|
||||
font-size: 2.4rem;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.05em;
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
/* vertical line grows top -> bottom */
|
||||
.line {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
/* 固定 top 为最终高度的一半位置,这样 height 从 0 -> 27.4rem 时会从上向下增长 */
|
||||
top: calc(50% - 13.7rem);
|
||||
width: 0.1rem;
|
||||
height: 0;
|
||||
background-color: #8d8d8d;
|
||||
will-change: height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 当组件进入视口并且等待 0.5s 后,.in-view 会加入根节点,下面规则触发动画 */
|
||||
.in-view .block-item .number {
|
||||
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(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(0.2, 0.9, 0.2, 1) forwards;
|
||||
animation-delay: calc(var(--delay) + 0.18s);
|
||||
}
|
||||
|
||||
/* keyframes */
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes growLine {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
to {
|
||||
height: 27.4rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<div class="success-container flex flex-col align-center">
|
||||
<img
|
||||
:src="info.icon"
|
||||
alt=""
|
||||
class="icon-img"
|
||||
/>
|
||||
<div class="title">{{ $t(info.title) }}</div>
|
||||
<div class="desc">
|
||||
{{ $t(info.desc) }}
|
||||
<!-- <div>
|
||||
Please review your submitted information in the AiDA in-platform message.
|
||||
</div>
|
||||
<div>
|
||||
You may edit it if needed. Competition updates and results will be sent
|
||||
via email.
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import successIcon from '@/assets/images/award/successful.png'
|
||||
import expiredIcon from '@/assets/images/award/expired.png'
|
||||
|
||||
const { t } = useI18n()
|
||||
const props = defineProps({
|
||||
isExpired: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const info = computed(() => {
|
||||
if (props.isExpired) {
|
||||
return {
|
||||
icon: expiredIcon,
|
||||
title: 'AwardsPage.deadlinePassed',
|
||||
desc: 'AwardsPage.deadlinePassedDesc'
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
icon: successIcon,
|
||||
title: 'AwardsPage.submissionSuccessful',
|
||||
desc: 'AwardsPage.submissionSuccessfulDesc'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.success-container {
|
||||
margin: 0 21.5rem;
|
||||
padding: 10.6rem 27.3rem 0;
|
||||
height: 50rem;
|
||||
position: relative;
|
||||
top: -16.8rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.8rem;
|
||||
.icon-img {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
}
|
||||
.title {
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 3rem;
|
||||
color: #232323;
|
||||
text-align: center;
|
||||
margin: 2rem 0 4rem;
|
||||
}
|
||||
.desc {
|
||||
color: #585858;
|
||||
font-family: Arial;
|
||||
font-weight: 400;
|
||||
font-size: 2.4rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,370 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
ref="containerRef"
|
||||
class="timeline-container container flex flex-col align-center"
|
||||
>
|
||||
<div class="timeline-title">{{ $t('AwardsPage.competitionTimeline') }}</div>
|
||||
<div class="desc">{{ $t('AwardsPage.shapingTheFuture') }}</div>
|
||||
<div
|
||||
class="timeline-point"
|
||||
ref="timelineRef"
|
||||
>
|
||||
<!-- 顶部标签行 -->
|
||||
<div class="grid-row labels-row">
|
||||
<div
|
||||
class="grid-cell label-cell"
|
||||
v-for="item in points"
|
||||
:key="'label-' + item.time"
|
||||
>
|
||||
<div class="main-label">{{ $t(item.label) }}</div>
|
||||
<div
|
||||
class="sub-label"
|
||||
v-if="item.subLabel"
|
||||
>
|
||||
{{ $t(item.subLabel) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 图标行 -->
|
||||
<div class="grid-row icons-row">
|
||||
<div class="timeline-line"></div>
|
||||
<div
|
||||
class="grid-cell icon-cell"
|
||||
v-for="item in points"
|
||||
:key="'icon-' + item.time"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/point.png"
|
||||
class="point-icon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 时间行 -->
|
||||
<div class="grid-row times-row">
|
||||
<div
|
||||
class="grid-cell time-cell"
|
||||
v-for="item in points"
|
||||
:key="'time-' + item.time"
|
||||
>
|
||||
{{ $t(item.time) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 描述行 -->
|
||||
<div class="grid-row descs-row">
|
||||
<div
|
||||
class="grid-cell desc-cell"
|
||||
v-for="item in points"
|
||||
:key="'desc-' + item.time"
|
||||
>
|
||||
<div class="txt">
|
||||
{{ $t(item.desc) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onBeforeUnmount, onMounted, ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { gsap } from 'gsap'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const containerRef = ref<HTMLElement | null>(null)
|
||||
const timelineRef = ref<HTMLElement | null>(null)
|
||||
const hasAnimated = ref(false)
|
||||
|
||||
const points = ref([
|
||||
{
|
||||
label: 'AwardsPage.timelineApplicationLabel',
|
||||
subLabel: 'AwardsPage.timelineDeadlineLabel',
|
||||
time: 'AwardsPage.timeJul15',
|
||||
desc: 'AwardsPage.applicationDeadlineDesc'
|
||||
},
|
||||
{
|
||||
label: 'AwardsPage.twentyFinalistsAnnounced',
|
||||
subLabel: 'AwardsPage.announcedLabel',
|
||||
time: 'AwardsPage.timeAug30',
|
||||
desc: 'AwardsPage.twentyFinalistsDesc'
|
||||
},
|
||||
{
|
||||
label: 'AwardsPage.finalistSubmission',
|
||||
subLabel: 'AwardsPage.submissionLabel',
|
||||
time: 'AwardsPage.timeSept30',
|
||||
desc: 'AwardsPage.finalistSubmissionDesc'
|
||||
},
|
||||
{
|
||||
label: 'AwardsPage.receivingOutfits',
|
||||
subLabel: 'AwardsPage.fromFinalistsLabel',
|
||||
time: 'AwardsPage.timeOctober',
|
||||
desc: 'AwardsPage.receivingOutfitsDesc'
|
||||
},
|
||||
{
|
||||
label: 'AwardsPage.awardCeremony',
|
||||
subLabel: 'AwardsPage.ceremonyLabel',
|
||||
time: 'AwardsPage.timeNov12',
|
||||
desc: 'AwardsPage.awardCeremonyDesc'
|
||||
}
|
||||
])
|
||||
|
||||
const playAnimation = () => {
|
||||
if (!containerRef.value || hasAnimated.value) return
|
||||
const title = containerRef.value.querySelector('.timeline-title')
|
||||
const subtitle = containerRef.value.querySelector('.desc')
|
||||
const line = containerRef.value.querySelector('.timeline-line')
|
||||
const timeline = containerRef.value.querySelector('.timeline-point')
|
||||
|
||||
const tl = gsap.timeline()
|
||||
|
||||
// 我们使用一个统一的开始 label,使横线、timeline 裁剪与所有文字同时启动,
|
||||
// 点图标在它们完成后立即开始。
|
||||
tl.addLabel('start')
|
||||
|
||||
// 整体 timeline 的裁剪展开(与 start 同步)
|
||||
if (timeline) {
|
||||
tl.fromTo(
|
||||
timeline,
|
||||
{
|
||||
clipPath: 'inset(0 100% 0 0)'
|
||||
},
|
||||
{
|
||||
clipPath: 'inset(0 0% 0 0)',
|
||||
duration: 1.3,
|
||||
ease: 'power1.out'
|
||||
},
|
||||
'start'
|
||||
)
|
||||
}
|
||||
|
||||
// 线条动画(与 start 同步)
|
||||
if (line) {
|
||||
tl.from(
|
||||
line,
|
||||
{
|
||||
scaleX: 0,
|
||||
transformOrigin: '0% 50%',
|
||||
duration: 1.3,
|
||||
ease: 'power1.out'
|
||||
},
|
||||
'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('.grid-cell')
|
||||
if (textItems && textItems.length) {
|
||||
tl.from(
|
||||
textItems,
|
||||
{
|
||||
// autoAlpha: 0.5,
|
||||
duration: 0.7,
|
||||
stagger: 0.08,
|
||||
ease: 'power2.out'
|
||||
},
|
||||
'start'
|
||||
)
|
||||
}
|
||||
|
||||
hasAnimated.value = true
|
||||
}
|
||||
|
||||
let observer: IntersectionObserver | null = null
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
if (!containerRef.value) return
|
||||
observer = new IntersectionObserver(
|
||||
entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
playAnimation()
|
||||
}
|
||||
})
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
)
|
||||
observer.observe(containerRef.value)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (observer && containerRef.value) {
|
||||
observer.unobserve(containerRef.value)
|
||||
}
|
||||
observer = null
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.timeline-container {
|
||||
background: url('@/assets/images/award/timeline_bg.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
position: relative;
|
||||
padding: 12.8rem 0 15.9rem;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
.timeline-title {
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 4rem;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.logo {
|
||||
margin: 2.4rem 0 2.2rem 0;
|
||||
}
|
||||
.desc {
|
||||
font-family: 'Arial';
|
||||
font-size: 3rem;
|
||||
font-weight: 400;
|
||||
color: #f95750;
|
||||
}
|
||||
.timeline-point {
|
||||
overflow: hidden;
|
||||
will-change: clip-path;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
margin-top: 11rem;
|
||||
padding: 0 13.8rem;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
// 主网格布局:5列
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-rows: auto auto auto auto;
|
||||
grid-column-gap: 0;
|
||||
grid-row-gap: 0;
|
||||
|
||||
// 所有 grid 子行的通用样式
|
||||
.grid-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// 图标行
|
||||
.icons-row {
|
||||
align-items: center;
|
||||
height: 6.4rem;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-bottom: 1.6rem;
|
||||
|
||||
.timeline-line {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: -22rem;
|
||||
right: -21.2rem;
|
||||
height: 0.15rem;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(199, 52, 44, 0) 0%,
|
||||
rgba(199, 52, 44, 0.719626) 25.96%,
|
||||
#c7342c 51.44%,
|
||||
rgba(199, 52, 44, 0.762376) 75.96%,
|
||||
rgba(199, 52, 44, 0) 100%
|
||||
);
|
||||
transform: translateY(-50%);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.icon-cell {
|
||||
position: relative;
|
||||
.point-icon {
|
||||
width: 6.4rem;
|
||||
height: 6.4rem;
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签行
|
||||
.labels-row {
|
||||
margin-bottom: 8rem;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
.label-cell {
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 2.8rem;
|
||||
white-space: pre-line;
|
||||
justify-content: center;
|
||||
min-height: 6rem;
|
||||
|
||||
// .sub-label {
|
||||
// font-family: 'Arial';
|
||||
// font-weight: 400;
|
||||
// font-size: 1.4rem;
|
||||
// color: rgba(255, 255, 255, 0.8);
|
||||
// margin-top: 0.4rem;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// 时间行
|
||||
.times-row {
|
||||
margin-bottom: 6rem;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
.time-cell {
|
||||
color: #f95750;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2.8rem;
|
||||
line-height: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
// 描述行
|
||||
.descs-row {
|
||||
.desc-cell {
|
||||
.txt {
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 2rem;
|
||||
text-align: center;
|
||||
color: #e0e0e0;
|
||||
width: 100%;
|
||||
max-width: 31.2rem;
|
||||
min-height: 10.2rem;
|
||||
white-space: pre-line;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div class="upload-status">
|
||||
<div class="upload-status-item">
|
||||
<div class="upload-status-item-icon">
|
||||
<img
|
||||
v-if="status === 'uploading'"
|
||||
src="@/assets/images/award/progress.png"
|
||||
alt=""
|
||||
class="progress-icon"
|
||||
/>
|
||||
<img
|
||||
v-if="status === 'success'"
|
||||
src="@/assets/images/award/successful.png"
|
||||
alt=""
|
||||
class="progress-icon successful-icon"
|
||||
/>
|
||||
</div>
|
||||
<div class="text">{{ $t(text) }}</div>
|
||||
<div class="tips">{{ $t(tips) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const props = defineProps<{
|
||||
status: string
|
||||
type: 'pdf' | 'video'
|
||||
}>()
|
||||
|
||||
const textMap: Record<string, string> = {
|
||||
idle: '',
|
||||
uploading: 'AwardsPage.uploadInProgress',
|
||||
success:'AwardsPage.uploadSuccess',
|
||||
error: 'AwardsPage.fileUploadFailed'
|
||||
}
|
||||
|
||||
const tips = computed(() => {
|
||||
if (props.type === 'pdf') {
|
||||
return 'AwardsPage.pdfFileTip'
|
||||
} else if (props.type === 'video') {
|
||||
return 'AwardsPage.videoFileTip'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const text = computed(() => {
|
||||
return textMap[props.status] ?? textMap.uploading
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.upload-status {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.upload-status-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.progress-icon {
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
}
|
||||
.text {
|
||||
font-family: Arial;
|
||||
font-weight: 400;
|
||||
color: #585858;
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
.tips{
|
||||
font-family: Arial;
|
||||
font-weight: 400;
|
||||
font-size: 1.8rem;
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,191 +0,0 @@
|
||||
<template>
|
||||
<div class="captcha">
|
||||
<input
|
||||
v-for="(c, index) in getCtData"
|
||||
:key="index"
|
||||
type="text"
|
||||
v-model="getCtData[index]"
|
||||
ref="inputRefs"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9]*"
|
||||
@input="e => onInput(e.target.value, index)"
|
||||
@keydown="e => onKeydown(e, index)"
|
||||
@keypress="e => onKeypress(e)"
|
||||
@focus="onFocus"
|
||||
@pause="onPause"
|
||||
:disabled="loading"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
|
||||
interface Props {
|
||||
ct: string[]
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'sendCaptcha', password: string): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const loading = ref(false)
|
||||
const timeout = ref<NodeJS.Timeout | null>(null)
|
||||
const inputRefs = ref<HTMLInputElement[]>([])
|
||||
|
||||
const getCtData = computed({
|
||||
get: () => props.ct,
|
||||
set: (value: string[]) => {
|
||||
// 这里需要特殊处理,因为computed通常是只读的
|
||||
// 但原代码中直接修改了getCtData,所以这里需要emit一个事件或者使用其他方式
|
||||
// 由于这是父组件传来的props,我们需要通过emit通知父组件更新
|
||||
props.ct.splice(0, props.ct.length, ...value)
|
||||
}
|
||||
})
|
||||
|
||||
const ctSize = computed(() => getCtData.value.length)
|
||||
|
||||
const cIndex = computed(() => {
|
||||
let i = getCtData.value.findIndex(item => item === '')
|
||||
i = (i + ctSize.value) % ctSize.value
|
||||
return i
|
||||
})
|
||||
|
||||
const lastCode = computed(() => getCtData.value[ctSize.value - 1])
|
||||
|
||||
watch(cIndex, () => {
|
||||
resetCaret()
|
||||
})
|
||||
|
||||
watch(lastCode, (newVal, oldVal) => {
|
||||
if (newVal && newVal !== oldVal) {
|
||||
inputRefs.value[ctSize.value - 1]?.blur()
|
||||
sendCaptcha()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
resetCaret()
|
||||
})
|
||||
|
||||
const onInput = (val: string, index: number) => {
|
||||
if (timeout.value) {
|
||||
clearTimeout(timeout.value)
|
||||
}
|
||||
timeout.value = setTimeout(() => {
|
||||
val = String(val).replace(/\D/g, '')
|
||||
getCtData.value[index] = val
|
||||
if (index === ctSize.value - 1) {
|
||||
getCtData.value[ctSize.value - 1] = val[0] // 最后一个码,只允许输入一个字符。
|
||||
} else if (val.length > 1) {
|
||||
let i = index
|
||||
for (i = index; i < ctSize.value && i - index < val.length; i++) {
|
||||
getCtData.value[i] = val[i - index]
|
||||
}
|
||||
resetCaret()
|
||||
} else if (!(val + '')) {
|
||||
getCtData.value[index] = ''
|
||||
}
|
||||
}, 10)
|
||||
}
|
||||
|
||||
const onPause = () => {}
|
||||
|
||||
const resetCaret = () => {
|
||||
inputRefs.value[ctSize.value - 1]?.focus()
|
||||
}
|
||||
|
||||
const onFocus = () => {
|
||||
// 监听 focus 事件,将光标重定位到"第一个空白符的位置"。
|
||||
let index = getCtData.value.findIndex(item => item === '')
|
||||
index = (index + ctSize.value) % ctSize.value
|
||||
inputRefs.value[index]?.focus()
|
||||
}
|
||||
|
||||
const onKeypress = (e: KeyboardEvent) => {
|
||||
// 只允许输入数字0-9
|
||||
const char = String.fromCharCode((e as any).which)
|
||||
if (!/[0-9]/.test(char)) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
const onKeydown = (e: KeyboardEvent, index: number) => {
|
||||
// 处理删除键
|
||||
if (e.key === 'Backspace' || e.key === 'Delete') {
|
||||
const val = (e.target as HTMLInputElement).value
|
||||
if (val === '') {
|
||||
// 删除上一个input里的值,并对其focus。
|
||||
if (index > 0) {
|
||||
getCtData.value[index - 1] = ''
|
||||
inputRefs.value[index - 1]?.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
// 阻止其他非数字字符
|
||||
else if (
|
||||
e.key &&
|
||||
!/[0-9]/.test(e.key) &&
|
||||
![
|
||||
'Backspace',
|
||||
'Delete',
|
||||
'Tab',
|
||||
'Enter',
|
||||
'ArrowLeft',
|
||||
'ArrowRight',
|
||||
'ArrowUp',
|
||||
'ArrowDown'
|
||||
].includes(e.key)
|
||||
) {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
const sendCaptcha = () => {
|
||||
const password = getCtData.value.map(item => item).join('')
|
||||
emit('sendCaptcha', password)
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
// 重置。一般是验证码错误时触发。
|
||||
getCtData.value = getCtData.value.map(() => '')
|
||||
resetCaret()
|
||||
}
|
||||
|
||||
// 暴露reset方法给父组件使用
|
||||
defineExpose({
|
||||
reset
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.captcha {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
input {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
border: 0.2rem solid #e6e6e6;
|
||||
border-radius: 0.8rem;
|
||||
text-align: center;
|
||||
font-size: 2.4rem;
|
||||
line-height: 6rem;
|
||||
outline: none;
|
||||
background-color: #f6f6f4;
|
||||
}
|
||||
input:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
input:disabled {
|
||||
color: #000;
|
||||
background-color: #f6f6f4;
|
||||
}
|
||||
.msg {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,268 +0,0 @@
|
||||
<template>
|
||||
<div class="award-container">
|
||||
<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">
|
||||
<div class="social-list flex">
|
||||
<a
|
||||
href="https://xhslink.com/m/5Ony2FapizV"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/xiaohongshu.svg"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/company/code-create-limited"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/linkdin.svg"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.facebook.com/CodeCreateAI"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/facebook.svg"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="https://www.tiktok.com/@aida_codecreate"
|
||||
target="_blank"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/tiktok.svg"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
@click="showQRcode = true"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/award/weichat.svg"
|
||||
alt=""
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="copyright">© Code-Create 2026</div>
|
||||
</div>
|
||||
<div
|
||||
class="qrcode-mask flex flex-center"
|
||||
v-if="showQRcode"
|
||||
>
|
||||
<div class="code-wrapper flex flex-col align-center">
|
||||
<img
|
||||
src="@/assets/images/award/close.svg"
|
||||
class="close-icon"
|
||||
@click="handleCloseQRcode"
|
||||
/>
|
||||
<div class="code-title">{{ $t('AwardsPage.wechatTitle') }}</div>
|
||||
<img
|
||||
src="@/assets/images/award/qrcode.jpg"
|
||||
class="qrcode"
|
||||
/>
|
||||
<div class="tips">{{ $t('AwardsPage.wechatDesc') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { getCookie } from '@/tool/cookie'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { locale } = useI18n()
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化语言设置
|
||||
const loginLanguage = localStorage.getItem('loginLanguage')
|
||||
if (loginLanguage) {
|
||||
locale.value = loginLanguage
|
||||
} else {
|
||||
const userLanguage = getCookie('language')
|
||||
if (userLanguage) {
|
||||
locale.value = userLanguage
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const showQRcode = ref(false)
|
||||
const handleCloseQRcode = () => {
|
||||
showQRcode.value = false
|
||||
}
|
||||
|
||||
type BtnType = 'index' | 'form'
|
||||
const btnType = ref<BtnType>('index')
|
||||
const btnText = computed(() => {
|
||||
if (btnType.value === 'index') {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED' ? '提交申请' : 'Submit your Application'
|
||||
}
|
||||
if (btnType.value === 'form') {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED' ? '赛事介绍' : 'Back to Introduction'
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
val => {
|
||||
if (val.includes('contestants')) {
|
||||
btnType.value = 'form'
|
||||
} else {
|
||||
btnType.value = 'index'
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
const handleBtnClick = () => {
|
||||
if (btnType.value === 'index') {
|
||||
router.push('/award/contestants')
|
||||
} else {
|
||||
router.push('/award/index')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.award-container {
|
||||
overflow: auto;
|
||||
height: 100vh;
|
||||
// 隐藏滚动条箭头,只显示滚动条本体
|
||||
box-sizing: border-box;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
.header-wrapper {
|
||||
.header-placeholder {
|
||||
height: 8rem;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
.header-right {
|
||||
column-gap: 1rem;
|
||||
cursor: pointer;
|
||||
.text {
|
||||
font-size: 1.6rem;
|
||||
color: #fff;
|
||||
}
|
||||
.arrow {
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
height: 10rem;
|
||||
padding-left: 21.5rem;
|
||||
box-sizing: border-box;
|
||||
padding-right: 22rem;
|
||||
background-color: #232323;
|
||||
.social-list {
|
||||
column-gap: 2rem;
|
||||
img {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
color: #fff;
|
||||
font-family: 'Arial';
|
||||
font-weight: 400;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
.qrcode-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.45);
|
||||
.code-wrapper {
|
||||
width: 60rem;
|
||||
height: 49.4rem;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
border-radius: 0.8rem;
|
||||
padding-top: 6rem;
|
||||
.close-icon {
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
position: absolute;
|
||||
top: 2rem;
|
||||
right: 2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.code-title {
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 3rem;
|
||||
color: #232323;
|
||||
}
|
||||
.qrcode {
|
||||
width: 25.8rem;
|
||||
height: 25.8rem;
|
||||
margin: 3rem 0 1rem;
|
||||
}
|
||||
.tips {
|
||||
font-family: Arial;
|
||||
font-weight: 400;
|
||||
font-size: 1.4rem;
|
||||
color: #585858;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,143 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="award-page"
|
||||
:class="{ 'is-zh': isZh }"
|
||||
>
|
||||
<div class="banner">
|
||||
<video
|
||||
:src="bannerUrl"
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
class="banner-video"
|
||||
playsinline
|
||||
webkit-playsinline
|
||||
x5-playsinline
|
||||
></video>
|
||||
<div
|
||||
class="submit-btn flex flex-center"
|
||||
@click="handleSubmitApplication"
|
||||
>
|
||||
<div>{{ $t('AwardsPage.submitApplication') }}</div>
|
||||
<img
|
||||
src="@/assets/images/award/arrow_right.png"
|
||||
alt=""
|
||||
class="arrow"
|
||||
/>
|
||||
<div class="ddl">{{ $t('AwardsPage.applicationDeadline') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Slogan />
|
||||
<Bloom />
|
||||
<TimeLine />
|
||||
<JudgesSection />
|
||||
<PrizesSection :is-zh="isZh" />
|
||||
<ApplySection />
|
||||
<SelectionSection />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import JudgesSection from './components/JudgesSection.vue'
|
||||
import SelectionSection from './components/SelectionSection.vue'
|
||||
import ApplySection from './components/ApplySection.vue'
|
||||
import PrizesSection from './components/PrizesSection.vue'
|
||||
import TimeLine from './components/TimeLine.vue'
|
||||
import Bloom from './components/Bloom.vue'
|
||||
import Slogan from './components/Slogan.vue'
|
||||
|
||||
import banner from '@/assets/images/award/banner.mp4'
|
||||
import bannerZh from '@/assets/images/award/banner_chinese.mp4'
|
||||
|
||||
const router = useRouter()
|
||||
const { locale } = useI18n()
|
||||
|
||||
const isZh = computed(() => {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED'
|
||||
})
|
||||
|
||||
const bannerUrl = computed(() => {
|
||||
return isZh.value ? bannerZh : banner
|
||||
})
|
||||
|
||||
const handleSubmitApplication = () => {
|
||||
router.push('/award/contestants')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
height: 97rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
}
|
||||
.banner {
|
||||
height: 100rem;
|
||||
// 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;
|
||||
line-height: 6.394rem;
|
||||
text-align: center;
|
||||
border-radius: 3.2rem;
|
||||
background-color: rgba(35, 35, 35, 0.7);
|
||||
box-shadow: inset 0 0 1119px 0 rgba(255, 255, 255, 0.3),
|
||||
inset -0.8px -2.4px 1.6px 0.4px rgba(255, 255, 255, 0.1),
|
||||
inset 0.8px 2.4px 1.6px 0 rgba(255, 255, 255, 0.3);
|
||||
color: #fff;
|
||||
font-family: 'PoppinsBold';
|
||||
font-weight: 600;
|
||||
font-size: 2.4rem;
|
||||
column-gap: 3.2rem;
|
||||
position: absolute;
|
||||
left: 42.1rem;
|
||||
bottom: 15.7rem;
|
||||
backdrop-filter: blur(5px);
|
||||
cursor: pointer;
|
||||
.arrow {
|
||||
width: 3.83rem;
|
||||
height: 3.83rem;
|
||||
}
|
||||
.ddl {
|
||||
position: absolute;
|
||||
bottom: -4rem;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
width: 41rem;
|
||||
font-family: 'ArialBold';
|
||||
font-weight: 700;
|
||||
font-size: 2rem;
|
||||
line-height: 2.2rem;
|
||||
color: #232323e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-zh {
|
||||
.submit-btn {
|
||||
padding: 0 7.5rem;
|
||||
height: 7.8rem;
|
||||
border-radius: 7.74rem;
|
||||
column-gap: 3.8rem;
|
||||
// justify-content: space-between;
|
||||
&,
|
||||
.ddl {
|
||||
width: 35.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,12 +2,11 @@
|
||||
<div class="brand-profile-index">brand-profile-index</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
<script lang="ts" setup></script>
|
||||
<style scoped lang="less">
|
||||
.seller-dashboard-index {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.seller-dashboard-index {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
88
src/views/SellerDashboard/MyListings/EditDetail/index.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div class="edit-detail-wrapper">
|
||||
<seller-header
|
||||
title="Edit Listing Details"
|
||||
:breadcrumbs="[
|
||||
{ title: 'My Listings', name: 'myListingsIndex' },
|
||||
{ title: 'Select Collection', name: 'myListingsSelect' },
|
||||
{ title: 'Select Sketch', name: 'myListingsSelectItem' },
|
||||
{ title: 'Edit Listing Details', name: 'EditDetail' }
|
||||
]"
|
||||
>
|
||||
<template #right>
|
||||
<div class="operate-menu flex">
|
||||
<div class="menu-btn flex align-center save">
|
||||
<span>Save Draft</span>
|
||||
<SvgIcon name="CSave" color="#000000" size="16" />
|
||||
</div>
|
||||
<div class="menu-btn flex align-center publish">
|
||||
<span>Publish</span>
|
||||
<SvgIcon name="CPublish" color="#ffffff" size="16" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</seller-header>
|
||||
<div class="edit-detail-content flex space-between">
|
||||
<div class="left">
|
||||
<div class="main-image-container flex">
|
||||
<div class="sketch"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import SellerHeader from "../../seller-header.vue"
|
||||
|
||||
const currentIndex = ref(0)
|
||||
const selectList = ref([
|
||||
{
|
||||
sketch: "",
|
||||
mainProductImage: "",
|
||||
cover: "",
|
||||
productImage: [],
|
||||
apparelSketch: [],
|
||||
productName: "",
|
||||
price: "",
|
||||
desc: '',
|
||||
gender: '',
|
||||
category:''
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.c-svg {
|
||||
width: initial;
|
||||
}
|
||||
|
||||
.edit-detail-wrapper {
|
||||
.menu-btn {
|
||||
height: 6rem;
|
||||
border: 0.15rem solid #000000;
|
||||
border-radius: 4rem;
|
||||
text-align: center;
|
||||
line-height: 6rem;
|
||||
padding: 0 2rem;
|
||||
font-weight: 400;
|
||||
font-size: 1.6rem;
|
||||
column-gap: 0.8rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.operate-menu {
|
||||
column-gap: 2rem;
|
||||
|
||||
.publish {
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-detail-content {
|
||||
padding-right: 6.4rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||