This commit is contained in:
李志鹏
2026-05-20 15:54:42 +08:00
parent 8cf3a2177c
commit 28cb492aca
9 changed files with 294 additions and 81 deletions

View File

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

Before

Width:  |  Height:  |  Size: 411 KiB

After

Width:  |  Height:  |  Size: 411 KiB

View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -0,0 +1,82 @@
<template>
<div class="email-box">
<h3 class="title">{{ title }}</h3>
<div class="tip">{{ tip }}</div>
<input
v-model="email"
@keydown.enter.prevent="submit"
type="email"
:placeholder="$t('EmailAddress')"
/>
<div v-show="error" class="error">{{ error }}</div>
<button custom @click="submit">{{ $t('Submit') }}</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const emit = defineEmits(['submit'])
const props = defineProps({
title: { type: String },
tip: { type: String }
})
const email = ref('')
const error = ref('')
const submit = () => {
if (!validateEmail(email.value)) return
emit('submit', email.value)
}
// 验证邮箱
const validateEmail = (email: string) => {
if (email === '') {
error.value = 'Please fill out this field.'
return false
} else if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) {
error.value = 'Please enter a valid email address.'
return false
}
error.value = ''
return true
}
</script>
<style scoped lang="less">
.email-box {
width: 100%;
padding: 80px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0px 0px 40px 0px rgba(0, 0, 0, 0.2);
border-radius: 40px;
> .title {
font-size: 40px;
color: #222;
margin-bottom: 10px;
}
> .tip {
color: #4d4d4d;
margin-bottom: 20px;
}
> input {
width: 100%;
border-radius: 40px;
height: 40px;
padding: 0 20px;
border: 1px solid #e1e1e1;
outline: none;
color: #222;
}
> .error {
font-size: 14px;
color: #dc3232;
}
> button {
margin-top: 10px;
width: 100%;
border-radius: 50px;
height: 50px;
font-weight: bold;
text-transform: uppercase;
--hover-backcolor: #000;
}
}
</style>

View File

@@ -204,18 +204,18 @@ function setDocumentStyles(parent, el, p = 0) {
`opacity ${oDuration} ${oDelay} ${oEasing}`, `opacity ${oDuration} ${oDelay} ${oEasing}`,
] ]
el.style.transition = transitionArr.join(', ') el.style.transition = transitionArr.join(', ')
const tX = getCurrentValue(el, T.translateX_s, T.translateX, p) const { num: tX, unit: tXUnit } = getCurrentValue(el, T.translateX_s, T.translateX, p)
const tY = getCurrentValue(el, T.translateY_s, T.translateY, p) const { num: tY, unit: tYUnit } = getCurrentValue(el, T.translateY_s, T.translateY, p)
const sx = getCurrentValue(el, T.scaleX_s, T.scaleX, p, T.scale_s, T.scale, 1) const { num: sx } = getCurrentValue(el, T.scaleX_s, T.scaleX, p, T.scale_s, T.scale, 1)
const sy = getCurrentValue(el, T.scaleY_s, T.scaleY, p, T.scale_s, T.scale, 1) const { num: sy } = getCurrentValue(el, T.scaleY_s, T.scaleY, p, T.scale_s, T.scale, 1)
const r = getCurrentValue(el, T.rotate_s, T.rotate, p) const { num: r } = getCurrentValue(el, T.rotate_s, T.rotate, p)
const rx = getCurrentValue(el, T.rotateX_s, T.rotateX, p) const { num: rx } = getCurrentValue(el, T.rotateX_s, T.rotateX, p)
const ry = getCurrentValue(el, T.rotateY_s, T.rotateY, p) const { num: ry } = getCurrentValue(el, T.rotateY_s, T.rotateY, p)
const rz = getCurrentValue(el, T.rotateZ_s, T.rotateZ, p) const { num: rz } = getCurrentValue(el, T.rotateZ_s, T.rotateZ, p)
const transform = `translate(${tX}px, ${tY}px) scale(${sx}, ${sy}) rotate(${r}deg) rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)` const transform = `translate(${tX}${tXUnit || 'px'}, ${tY}${tYUnit || 'px'}) scale(${sx}, ${sy}) rotate(${r}deg) rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`
el.style.transform = transform el.style.transform = transform
if (hasAttr(el, [T.opacity_s, T.opacity])) { if (hasAttr(el, [T.opacity_s, T.opacity])) {
el.style.opacity = getCurrentValue(el, T.opacity_s, T.opacity, p, T.opacity_s, T.opacity, 1) el.style.opacity = getCurrentValue(el, T.opacity_s, T.opacity, p, T.opacity_s, T.opacity, 1).num
} }
} }
function getAttrs(el, attrs = {}) { function getAttrs(el, attrs = {}) {
@@ -227,9 +227,16 @@ function getAttrs(el, attrs = {}) {
return obj return obj
} }
function getCurrentValue(el, start, end, progress, bStart, bEnd, defaultValue = 0) { function getCurrentValue(el, start, end, progress, bStart, bEnd, defaultValue = 0) {
const startNum = hasAttr(el, start) ? Number(el.getAttribute(start)) : hasAttr(el, bStart) ? Number(el.getAttribute(bStart)) : defaultValue const startStr = hasAttr(el, start) ? el.getAttribute(start) : hasAttr(el, bStart) ? el.getAttribute(bStart) : String(defaultValue)
const endNum = hasAttr(el, end) ? Number(el.getAttribute(end)) : hasAttr(el, bEnd) ? Number(el.getAttribute(bEnd)) : defaultValue const endStr = hasAttr(el, end) ? el.getAttribute(end) : hasAttr(el, bEnd) ? el.getAttribute(bEnd) : String(defaultValue)
return startNum + (endNum - startNum) * progress const startNum = parseInt(startStr)
const endNum = parseInt(endStr)
const starUnit = startStr.match(/(px|deg|%|rem|em|vh|vw|pt|pc|mm|cm|in)$/i)?.[1] || ''
const endUnit = endStr.match(/(px|deg|%|rem|em|vh|vw|pt|pc|mm|cm|in)$/i)?.[1] || ''
return {
num: startNum + (endNum - startNum) * progress,
unit: starUnit || endUnit
}
} }
function hasAttr(el, attr) { function hasAttr(el, attr) {
if (Array.isArray(attr)) { if (Array.isArray(attr)) {

View File

@@ -2,7 +2,7 @@
<div class="contact-us"> <div class="contact-us">
<img class="bg" src="@/assets/images/contact-us/bg.jpg" alt="" /> <img class="bg" src="@/assets/images/contact-us/bg.jpg" alt="" />
<section class="header"> <section class="header">
<h1 v-custom-animation.once duration="1s" translate-y-s="-100" opacity-s="0"> <h1 v-custom-animation.once duration="1s" translate-y-s="-100%" opacity-s="0">
{{ $t('MainHeader.ContactUs') }} {{ $t('MainHeader.ContactUs') }}
</h1> </h1>
</section> </section>
@@ -12,40 +12,16 @@
<a class="email" href="mailto:info@code-create.com.hk">info@code-create.com.hk</a> <a class="email" href="mailto:info@code-create.com.hk">info@code-create.com.hk</a>
</section> </section>
<section class="contact-input"> <section class="contact-input">
<div class="box"> <EmailBox @submit="submit" :title="$t('GetInTouch')" :tip="$t('StayUpToDate')" />
<h3 class="title">{{ $t('GetInTouch') }}</h3>
<div class="tip">{{ $t('StayUpToDate') }}</div>
<input
v-model="email"
@keydown.enter.prevent="submit"
type="email"
:placeholder="$t('EmailAddress')"
/>
<div v-show="error" class="error">{{ error }}</div>
<button custom @click="submit">{{ $t('Submit') }}</button>
</div>
</section> </section>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
const email = ref('') import EmailBox from '@/components/email-box.vue'
const error = ref('')
const submit = () => { const submit = (email: string) => {
if (!validateEmail(email.value)) return console.log(email)
console.log(email.value)
}
// 验证邮箱
const validateEmail = (email: string) => {
if (email === '') {
error.value = 'Please fill out this field.'
return false
} else if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)) {
error.value = 'Please enter a valid email address.'
return false
}
error.value = ''
return true
} }
</script> </script>
@@ -104,44 +80,8 @@
> .contact-input { > .contact-input {
padding: 100px; padding: 100px;
background-color: #faf8f8; background-color: #faf8f8;
> .box { > .email-box {
max-width: 860px; max-width: 860px;
width: 100%;
padding: 80px;
margin: 0 auto;
background-color: #fff;
box-shadow: 0px 0px 40px 0px rgba(0, 0, 0, 0.2);
border-radius: 40px;
> .title {
font-size: 40px;
color: #222;
margin-bottom: 10px;
}
> .tip {
color: #4d4d4d;
margin-bottom: 20px;
}
> input {
width: 100%;
border-radius: 40px;
height: 40px;
padding: 0 20px;
border: 1px solid #e1e1e1;
outline: none;
color: #222;
}
> .error {
font-size: 14px;
color: #dc3232;
}
> button {
margin-top: 10px;
width: 100%;
border-radius: 50px;
height: 50px;
font-weight: bold;
--hover-backcolor: #000;
}
} }
} }
} }

View File

@@ -2,7 +2,7 @@
<div class="media"> <div class="media">
<img class="bg" src="@/assets/images/media/bg.jpg" alt="" /> <img class="bg" src="@/assets/images/media/bg.jpg" alt="" />
<section class="header"> <section class="header">
<h1 v-custom-animation.once duration="1s" translate-y-s="-100" opacity-s="0"> <h1 v-custom-animation.once duration="1s" translate-y-s="-100%" opacity-s="0">
{{ $t('MainHeader.Media') }} {{ $t('MainHeader.Media') }}
</h1> </h1>
</section> </section>

179
src/pages/mixi/index.vue Normal file
View File

@@ -0,0 +1,179 @@
<template>
<div class="mixi">
<img class="bg" src="@/assets/images/mixi/bg.jpg" alt="" />
<section class="header">
<img
src="@/assets/images/mixi/logo-mixi.png"
alt=""
v-custom-animation.once
duration="1s"
translate-y-s="100%"
opacity-s="0"
/>
</section>
<section class="introduce">
<div class="box" v-custom-animation.once="{ duration: '1.25s' }">
<h2 class="title">
Best-in-class Precise Fashion Attribute and Colour Recognition System
</h2>
<p class="tip" translate-y-s="100%" opacity-s="0">
Mixi is an AI-based fine-grained fashion attribute and colour recognition tool
that can be used for both online shopping platforms and bricks and mortar
stores. Mixi allows the customer to easily find fashion items that possess
his/her preferred fashion attributes and colours.
</p>
<button custom @click="scrollToJoin" translate-y-s="100%" opacity-s="0">
CONTACT US
</button>
</div>
</section>
<section class="video">
<div class="content" @click="playVideo">
<img
src="https://code-create.com.hk/wp-content/uploads/2022/11/mixi_video_thumb.jpg"
alt=""
/>
<span class="iconfont icon-bofang"></span>
</div>
</section>
<section class="email-input" ref="joinRef">
<EmailBox
@submit="submit"
:title="$t('Interested in Mixi?')"
:tip="$t('We will contact you for customized plan.')"
/>
</section>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import EmailBox from '@/components/email-box.vue'
import MyEvent from '@/directives/myEvents'
const playVideo = () => {
MyEvent.emit('playVideo', {
url: 'https://code-create.com.hk/wp-content/uploads/2022/11/mixi_video.mp4',
poster: 'https://code-create.com.hk/wp-content/uploads/2022/11/mixi_video_thumb.jpg'
})
}
const joinRef = ref(null)
const scrollToJoin = () => {
window.scrollTo({
top: joinRef.value.offsetTop,
behavior: 'smooth'
})
}
const submit = (email: string) => {
console.log(email)
}
</script>
<style scoped lang="less">
.mixi {
> * {
position: relative;
z-index: 1;
background-color: #f9f9f9;
}
> .bg {
height: 500px;
width: 100%;
object-fit: cover;
position: fixed;
top: 0;
z-index: 0;
}
> .header {
height: 500px;
display: flex;
align-items: center;
justify-content: center;
background-color: transparent;
> img {
max-width: 200px;
width: 90%;
height: auto;
}
}
> .introduce {
padding: 200px 0;
background-color: #eeeeee;
> .box {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
width: 100%;
max-width: 730px;
text-align: center;
> .title {
color: #222;
font-size: 24px;
margin-bottom: 30px;
text-transform: capitalize;
}
> .tip {
color: #555;
font-size: 16px;
line-height: 25px;
margin-bottom: 50px;
}
> button {
width: auto;
height: auto;
border-radius: 40px;
padding: 20px 40px;
letter-spacing: 2px;
text-transform: uppercase;
font-weight: bold;
}
}
}
> .video {
width: 100%;
background-color: #463a37;
padding: 100px 0;
> .content {
max-width: 1120px;
margin: 0 auto;
position: relative;
cursor: pointer;
> img {
width: 100%;
height: auto;
}
> .icon-bofang {
font-size: 100px;
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: identifier 2s ease-in-out infinite;
transition: 0.3s all;
@keyframes identifier {
0% {
transform: translate(-50%, -50%) scale(1);
filter: drop-shadow(0px 0px 8px rgba(255, 255, 255, 1));
}
50% {
transform: translate(-50%, -50%) scale(0.95);
filter: drop-shadow(0px 0px 0px rgba(255, 255, 255, 1));
}
100% {
transform: translate(-50%, -50%) scale(1);
filter: drop-shadow(0px 0px 8px rgba(255, 255, 255, 1));
}
}
}
}
}
> .email-input {
padding: 100px;
> .email-box {
max-width: 860px;
}
}
}
</style>

View File

@@ -37,6 +37,11 @@ export const routes: RouteRecordRaw[] = [
name: 'Aida', name: 'Aida',
component: () => import('./pages/aida/index.vue') component: () => import('./pages/aida/index.vue')
}, },
{
path: 'mixi',
name: 'mixi',
component: () => import('./pages/mixi/index.vue')
},
{ path: 'events', { path: 'events',
name: 'events', name: 'events',
component: () => import('./pages/events/index.vue') component: () => import('./pages/events/index.vue')