Compare commits

...

4 Commits

Author SHA1 Message Date
李志鹏
4587a59a89 Merge branch 'main' of http://18.167.251.121:10003/aidlab/Code-Create 2026-05-15 17:32:55 +08:00
李志鹏
d237dab098 aaa 2026-05-15 17:31:43 +08:00
6fc1da2884 Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/Code-Create 2026-05-15 16:42:08 +08:00
5158b63ddd feat: solutions/aida 2026-05-15 16:41:52 +08:00
17 changed files with 1234 additions and 244 deletions

View File

@@ -154,3 +154,28 @@ button[custom="black-box"] {
--button-click-color: #fff;
--button-font-size: 1.6rem;
}
.hover-bottom-animation {
position: relative;
cursor: pointer;
}
.hover-bottom-animation::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
.hover-bottom-animation:hover::before {
width: 100%;
left: 0;
right: auto;
}
.hover-bottom-animation.active:before,
.hover-bottom-animation.router-link-exact-active:before {
width: 100%;
}

View File

@@ -15,12 +15,19 @@ p {
* {
box-sizing: border-box;
}
h1, h2, h3, h4, h5, h6, .products-title{
h1,
h2,
h3,
h4,
h5,
h6,
.products-title {
font-family: Poppins, sans-serif;
font-weight: 600;
letter-spacing: 2px;
color: #222222;
text-transform: capitalize;
font-weight: 600;
letter-spacing: 2px;
color: #222222;
text-transform: capitalize;
}
@keyframes loading {
@@ -175,4 +182,33 @@ button[custom="black-box"] {
--button-click-bgcolor: #979797;
--button-click-color: #fff;
--button-font-size: 1.6rem;
}
.hover-bottom-animation {
position: relative;
cursor: pointer;
&::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.active:before,
&.router-link-exact-active:before {
width: 100%;
}
}

View File

@@ -7,7 +7,7 @@
transition: 'stroke-dashoffset 10ms linear',
strokeDasharray: `${progress}, ${max}`,
stroke: '#222',
strokeWidth: 4,
strokeWidth: 4
}"
fill="none"
></path>
@@ -17,15 +17,15 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { ref } from "vue";
const max = ref(98 * Math.PI);
const progress = ref(0);
const handleScroll = (e: number) => {
progress.value = (e / 100) * max.value;
};
progress.value = (e / 100) * max.value
}
const handleClick = () => {
document.documentElement.scrollTo({ top: 0, behavior: "smooth" });
};
document.documentElement.scrollTo({ top: 0, behavior: 'smooth' })
}
</script>
<style scoped lang="less">
.back-top {
@@ -52,6 +52,20 @@
transition: stroke-dashoffset 10ms linear;
}
}
&:hover > .iconfont {
animation: animArrow 1s infinite;
}
@keyframes animArrow {
0% {
transform: rotate(0deg);
}
50% {
transform: translateY(-3px);
}
100% {
transform: rotate(0deg);
}
}
animation: back-top-hidden 0.2s linear both;
&.active {

View File

@@ -0,0 +1,100 @@
<template>
<div class="down-menu">
<div class="title hover-bottom-animation" to="#">
{{ title }}
<span class="iconfont icon-arrow-down-bold"></span>
</div>
<div class="child">
<slot></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
const props = defineProps({
title: {
type: String,
default: ''
}
})
</script>
<style scoped lang="less">
.down-menu {
position: relative;
> .title {
margin: 0 14px;
color: #fff;
font-size: 15px;
text-decoration: none;
line-height: 37px;
display: inline-block;
position: relative;
cursor: pointer;
&::before {
content: '';
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.router-link-exact-active:not(.parent):before {
width: 100%;
}
> .iconfont {
opacity: 0.5;
font-size: 10px;
margin-left: 5px;
}
}
> .child {
position: absolute;
bottom: 0;
visibility: hidden;
width: 250px;
height: auto;
padding: 10px 0;
box-sizing: border-box;
border: 1px solid #e1e1e1;
background-color: #fff;
display: flex;
flex-direction: column;
transform: translateY(calc(100% + 5px));
> * {
display: inline-block;
padding: 10px 15px;
color: #000;
font-size: 15px;
text-decoration: none;
text-align: left;
&:hover {
opacity: 0.5;
}
}
}
&:hover > .child {
animation: child-show 0.2s linear both;
}
@keyframes child-show {
0% {
visibility: hidden;
// opacity: 0;
}
100% {
// opacity: 1;
transform: translateY(100%);
visibility: visible;
}
}
}
</style>

View File

@@ -1,25 +1,78 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<header class="header">
</header>
<footer class="main-footer">
<div class="left">
<span>©2025 Code-Create Limited</span>
</div>
<div class="right">
<div v-for="item in nav" :key="item.path">
<router-link class="link" :to="item.path">{{ item.name }}</router-link>
</div>
</div>
</footer>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from 'vue'
const nav = ref([
{
name: 'Privacy Policy',
path: '/privacy-policy'
},
{
name: 'Terms of Use',
path: '/terms-of-use'
},
{
name: 'Disclaimer',
path: '/disclaimer'
},
{
name: 'Site Map',
path: '/site-map'
}
])
</script>
<style lang="less" scoped>
.header{
position: relative;
.main-footer {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 15px 0;
min-height: 140px;
display: flex;
justify-content: space-between;
font-family: Poppins, sans-serif;
> .left {
font-size: 13px;
font-weight: normal;
line-height: 24px;
color: #000000b3;
}
> .right {
display: flex;
align-items: flex-start;
> div {
display: flex;
align-items: center;
justify-content: center;
padding-left: 20px;
border-left: 1px solid #0a0a0a;
margin-left: 20px;
&:first-child {
border-left: none;
padding-left: 0;
margin-left: 0;
}
> .link {
font-weight: 400;
font-size: 12px;
transition: all 0.2s ease-out;
box-sizing: border-box;
box-shadow: none;
text-decoration: none;
display: inline-block;
color: #0a0a0a;
}
}
}
}
</style>
</style>

View File

@@ -1,86 +1,90 @@
<template>
<header class="main-header" v-scroll-progress>
<img class="logo" src="../assets/logo-full.png" alt="code-create" />
<a href="/" class="logo"><img src="../assets/logo-full.png" alt="code-create" /></a>
<div class="center-nav">
<div class="nav-item" v-for="item in navList" :key="item.path">
<router-link class="link" :to="item.path" v-if="item.path">
{{ item.name }}
</router-link>
<span v-else class="link">{{ item.name }}</span>
<div
class="child"
v-if="item.children && item.children.length > 0"
>
<router-link
class="child-link"
:to="child.path"
v-for="child in item.children"
:key="child.path"
>
<div class="nav-item" v-for="item in navList" :key="item.name">
<down-menu :title="item.name" v-if="item.children">
<router-link :to="child.path" v-for="child in item.children" :key="child.path">
{{ child.name }}
</router-link>
</div>
</down-menu>
<router-link class="link hover-bottom-animation" :to="item.path" v-else>
{{ item.name }}
<span v-show="item.children" class="iconfont icon-arrow-down-bold"></span>
</router-link>
</div>
</div>
<div class="right">
<span>English</span>
<span>My Account</span>
<down-menu title="English">
<router-link class="link" to="/">English</router-link>
<router-link class="link" to="/zh-cn">简体中文</router-link>
<router-link class="link" to="/zh-tw">繁體中文</router-link>
</down-menu>
<span class="">
<span class="iconfont icon-wode"></span>
<span>My Account</span>
</span>
</div>
</header>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
console.log(route);
import { ref, onMounted, onUnmounted, computed } from 'vue'
import DownMenu from './down-menu.vue'
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route)
const navList = ref([
{
name: "Home",
path: "/",
name: 'Home',
path: '/'
},
{
name: "About Us",
path: "/about-us",
name: 'About Us',
path: '/about-us'
},
{
name: "Our Solutions",
name: 'Our Solutions',
path: '',
children: [
{
name: "AiDA 3.1",
path: "/aida",
name: 'AiDA 3.1',
path: '/aida'
},
{
name: "Mixi",
path: "/mixi",
},
],
name: 'Mixi',
path: '/mixi'
}
]
},
{
name: "Communities",
name: 'Communities',
path: '',
children: [
{
name: "Events",
path: "/events",
name: 'Events',
path: '/events'
},
{
name: "User Stories",
path: "/user-stories",
name: 'User Stories',
path: '/user-stories'
},
{
name: "Help Centre",
path: "/help-centre",
},
],
name: 'Help Centre',
path: '/help-centre'
}
]
},
{
name: "Media",
path: "/media",
name: 'Media',
path: '/media'
},
{
name: "Contact Us",
path: "/contact-us",
},
]);
name: 'Contact Us',
path: '/contact-us'
}
])
</script>
<style lang="less" scoped>
.main-header {
@@ -102,6 +106,10 @@
> .logo {
height: 100%;
width: auto;
img {
width: auto;
height: 100%;
}
}
> .center-nav {
display: flex;
@@ -116,27 +124,11 @@
text-decoration: none;
line-height: 37px;
display: inline-block;
position: relative;
cursor: pointer;
&::before {
content: "";
position: absolute;
height: 2px;
width: 0;
right: 0;
left: auto;
bottom: 0;
transition: width 0.2s ease-in-out;
-webkit-transition: width 0.2s ease-in-out;
background-color: #fff;
}
&:hover::before {
width: 100%;
left: 0;
right: auto;
}
&.router-link-exact-active:before {
width: 100%;
> .iconfont {
opacity: 0.5;
font-size: 10px;
margin-left: 5px;
}
}
> .child {
@@ -195,4 +187,4 @@
}
}
}
</style>
</style>

View File

@@ -40,7 +40,6 @@ const T = {
rotateZ: 'rotate-z',
opacity_s: 'opacity-s',
opacity: 'opacity',
once: 'once',
}
const types = Object.values(T)
const typesStr = types.map(v => `[${v}]`).join(',')

View File

@@ -33,7 +33,7 @@ export default {
rootMap.set(obj.root, [obj])
obj.root.addEventListener('scroll', handleScroll)
},
beforeUnmount(el: HTMLElement, binding: any) {
beforeUnmount(el: HTMLElement) {
rootMap.forEach((objs, root) => {
if (objs.some((v: any) => v.el === el)) {
objs = objs.filter((v_: any) => v_.el !== el)
@@ -60,4 +60,4 @@ function handleScroll(e: any) {
obj.el.classList.toggle('active', isActive)
}
})
};
};

View File

@@ -2,7 +2,7 @@ import { gsap, } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
export default {
name: 'tween-animation',
mounted(el: HTMLElement, binding: any) {
mounted(el: HTMLElement) {
// if(!binding.value.isGsap)return
let dom = document.querySelector('body')
gsap.registerPlugin(ScrollTrigger);
@@ -26,4 +26,4 @@ export default {
// }
});
},
};
};

View File

@@ -1,19 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { gsap, TweenMax, TweenLite } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<section class="ecosystem">
@@ -64,4 +50,4 @@ const {} = toRefs(data);
padding: 100px 0;
}
}
</style>
</style>

View File

@@ -1,19 +1,7 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import Ecosystem from './ecosystem.vue'
import Title from './title.vue'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<div class="about-us">
@@ -39,4 +27,4 @@ const {} = toRefs(data);
}
}
}
</style>
</style>

View File

@@ -1,19 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
import { gsap, TweenMax, TweenLite } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
//const props = defineProps({
//})
//const emit = defineEmits([
//])
let data = reactive({
})
onMounted(()=>{
})
onUnmounted(()=>{
})
defineExpose({})
const {} = toRefs(data);
</script>
<template>
<section class="title-section">
@@ -42,4 +28,4 @@ const {} = toRefs(data);
}
}
}
</style>
</style>

View File

@@ -0,0 +1,819 @@
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { shallowRef, useTemplateRef } from 'vue'
import aidaIntroBg from '@/assets/images/home/aida-intro-bg.png'
import aidaPanel from '@/assets/images/home/aida-panel.png'
import aidaBanner from '@/assets/images/aida/aida-banner.jpg'
import demoVideo from '@/assets/images/aida/aida-demo-video.mp4'
import diamondIcon from '@/assets/images/aida/diamond.svg'
import industryOne from '@/assets/images/aida/industry-1.png'
import industryTwo from '@/assets/images/aida/industry-2.png'
import industryThree from '@/assets/images/aida/industry-3.png'
import timeIcon from '@/assets/images/aida/time.svg'
const keyFeatures = [
"The world's first AI system in fashion design emphasizing user control, ensuring AI-generated designs align seamlessly with the designer's unique vision and brand identity.",
'Excels in synthesizing diverse inputs, such as moodboards, fabric prints, color choices, and sketches, into a cohesive collection quickly, harmoniously, and efficiently.',
'Significantly speeds up the design process by over 60%, quickly generating unlimited designs based on user input.',
'Incorporates cutting-edge AIGC technology to generate innovative designs and provide comprehensive assistance in the creative process.'
] as const
const benefits = [
{
image: industryOne,
alt: 'Light bulb icon',
text: 'Provides speedy ideation for fashion brands and individual designers'
},
{
image: industryTwo,
alt: 'Stopwatch icon',
text: 'Speeds up the whole fashion design process to strive for the goal of sustainability and cost-saving'
},
{
image: industryThree,
alt: 'Drawing brush icon',
text: 'Allows fashion novices who do not have drawing or sketching skills to create their own designs in a simple and easy mode'
}
] as const
const subscriptionHighlights = [
'Easily create your fashion collections in around 10 seconds based on your creative inspirations and Brand DNA',
'Upload mood boards, colour choices, fabric prints and sketches for generating unlimited design proposals',
'Save and retrieve your own designs with just a few clicks',
'A Cloud-based system by subscription for accessing anytime and anywhere',
'Easy to use, can learn in 10 minutes',
'Contact us for AiDA trial at info@code-create.com.hk'
] as const
const plans = [
{
icon: timeIcon,
name: 'Trial',
description: '7 days free trial',
action: 'Start Trial',
href: 'mailto:info@code-create.com.hk?subject=AiDA%203.1%20Trial'
},
{
icon: diamondIcon,
name: 'Corporate',
description: 'Customised plan',
action: 'Contact Us',
href: 'mailto:info@code-create.com.hk?subject=AiDA%203.1%20Corporate%20Plan'
}
] as const
const demoVideoRef = useTemplateRef<HTMLVideoElement>('demoVideoRef')
const isVideoPlaying = shallowRef(false)
async function toggleDemoVideo() {
const video = demoVideoRef.value
if (!video) {
return
}
if (video.paused) {
await video.play()
isVideoPlaying.value = true
return
}
video.pause()
isVideoPlaying.value = false
}
function handleVideoStateChange() {
const video = demoVideoRef.value
isVideoPlaying.value = Boolean(video && !video.paused && !video.ended)
}
useHead({
title: 'AiDA 3.1 | Code Create',
meta: [
{
name: 'description',
content:
'AiDA 3.1 is an AI-based interactive design assistant for fashion designers.'
}
]
})
</script>
<template>
<main class="aida-page">
<section class="aida-hero" aria-labelledby="aida-title">
<img class="aida-hero-image" :src="aidaBanner" alt="AiDA 3.1 purple silk banner" />
<h1 id="aida-title" class="aida-hero-title">AiDA 3.1</h1>
</section>
<section class="intro-section" aria-labelledby="intro-title">
<div class="intro-inner" v-custom-animation.scroll>
<h2 id="intro-title" class="intro-title">
AI-Based Interactive Design Assistant For Fashion
</h2>
<p class="intro-copy">
AiDA 3.1, a first-to-market technology that empowers fashion designers, based on
their creative inspirations, to work with AI to create original designs. With
just a few clicks, designers can choose or refine options to develop fashion
collections, bringing agility, efficiency and flexibility to conventional and
intensive studio processes.
</p>
<p class="pricing-copy">
Annual Subscription Fee: $5,000 HKD / Year (50000 Credits)<br />
Monthly Subscription Fee: $500 HKD / Month (3500 Credits)<br />
Monthly Subscription Fee: $100 HKD / Month (500 Credits)
</p>
<p class="academic-copy">
Special Academic rate available, please contact us for details.
</p>
<a
class="primary-button"
href="mailto:info@code-create.com.hk?subject=AiDA%203.1%20Subscription"
>
Subscribe Now
</a>
<a class="manual-link" href="#subscription">User Manual</a>
</div>
</section>
<section class="features-section" aria-labelledby="features-title">
<div class="features-inner" v-custom-animation.scroll>
<div class="feature-art">
<img
class="feature-bg"
:src="aidaIntroBg"
alt="Fashion design sketches on paper"
loading="lazy"
/>
<img
class="feature-panel"
:src="aidaPanel"
alt="AiDA design workspace preview"
loading="lazy"
/>
</div>
<div class="feature-copy">
<h2 id="features-title" class="section-title">Key Features</h2>
<ul class="feature-list">
<li v-for="feature in keyFeatures" :key="feature">
{{ feature }}
</li>
</ul>
</div>
</div>
</section>
<section class="benefits-section" aria-labelledby="benefits-title">
<div class="benefits-inner">
<h2 id="benefits-title" class="section-title benefits-title">
Benefits to Industry
</h2>
<div class="benefits-grid">
<article v-for="benefit in benefits" :key="benefit.text" class="benefit-card">
<img
class="benefit-icon"
:src="benefit.image"
:alt="benefit.alt"
loading="lazy"
/>
<p class="benefit-copy">{{ benefit.text }}</p>
</article>
</div>
</div>
</section>
<section class="demo-section" aria-labelledby="demo-title">
<div class="demo-inner">
<h2 id="demo-title" class="demo-title">Demo</h2>
<div class="demo-video-wrap">
<video
ref="demoVideoRef"
class="demo-video"
:class="{ 'is-playing': isVideoPlaying }"
preload="metadata"
playsinline
@click="toggleDemoVideo"
@pause="handleVideoStateChange"
@play="handleVideoStateChange"
@ended="handleVideoStateChange"
>
<source :src="demoVideo" type="video/mp4" />
</video>
<button
v-show="!isVideoPlaying"
class="video-play-button"
type="button"
aria-label="Play AiDA demo video"
@click="toggleDemoVideo"
>
Click to play
<span class="play-dot" aria-hidden="true"></span>
</button>
</div>
</div>
</section>
<section
id="subscription"
class="subscription-section"
aria-labelledby="subscription-title"
>
<div class="subscription-inner">
<h2 id="subscription-title" class="section-title subscription-title">
Choose Your Subscription Plan
</h2>
<ul class="subscription-list">
<li v-for="item in subscriptionHighlights" :key="item">
{{ item }}
</li>
</ul>
<div class="plans-grid">
<article v-for="plan in plans" :key="plan.name" class="plan-card">
<img
class="plan-icon"
:src="plan.icon"
:alt="`${plan.name} plan icon`"
loading="lazy"
/>
<h3 class="plan-title">{{ plan.name }}</h3>
<p class="plan-copy">{{ plan.description }}</p>
<a class="plan-button" :href="plan.href">{{ plan.action }}</a>
</article>
</div>
<div class="legal-links">
<a href="#subscription">Terms &amp; Conditions</a>
<a href="#subscription">Subscription Agreement</a>
</div>
</div>
</section>
</main>
</template>
<style scoped lang="less">
.aida-page {
width: 100%;
min-height: 100vh;
overflow: hidden;
background: #f0f0f0;
color: #333333;
font-family: Poppins, Arial, sans-serif;
}
.aida-hero {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: clamp(280px, 36vw, 520px);
min-height: 280px;
background: #241023;
overflow: hidden;
}
.aida-hero-image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.aida-hero-title {
position: relative;
z-index: 1;
margin: 0;
padding-top: 34px;
color: #ffffff;
font-size: clamp(40px, 5.2vw, 72px);
font-weight: 700;
line-height: 1;
letter-spacing: 0;
text-transform: none;
text-align: center;
}
.intro-section {
display: flex;
align-items: center;
justify-content: center;
min-height: 735px;
padding: 110px 24px 122px;
background: #ebebeb;
}
.intro-inner {
width: min(100%, 720px);
text-align: center;
}
.intro-title,
.section-title,
.demo-title,
.subscription-title,
.plan-title {
margin: 0;
color: #333333;
font-family: Poppins, Arial, sans-serif;
font-weight: 700;
letter-spacing: 1.4px;
text-transform: none;
}
.intro-title {
margin-bottom: 32px;
font-size: clamp(18px, 1.55vw, 24px);
line-height: 1.35;
}
.intro-copy,
.pricing-copy,
.academic-copy {
margin: 0 auto;
color: #555555;
font-size: 12px;
line-height: 1.5;
letter-spacing: 0;
}
.intro-copy {
max-width: 610px;
margin-bottom: 20px;
}
.pricing-copy {
max-width: 520px;
margin-bottom: 14px;
color: #3f3f3f;
font-weight: 700;
line-height: 1.32;
letter-spacing: 1.1px;
}
.academic-copy {
margin-bottom: 25px;
}
.primary-button,
.plan-button {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 43px;
padding: 0 34px;
border-radius: 999px;
background: #a51f28;
color: #ffffff;
font-size: 10px;
font-weight: 700;
line-height: 1;
letter-spacing: 1.8px;
text-decoration: none;
text-transform: uppercase;
transition:
background-color 0.2s ease,
transform 0.2s ease;
}
.primary-button:hover,
.primary-button:focus-visible,
.plan-button:hover,
.plan-button:focus-visible {
background: #8f1720;
transform: translateY(-1px);
}
.primary-button:focus-visible,
.plan-button:focus-visible,
.manual-link:focus-visible,
.legal-links a:focus-visible,
.video-play-button:focus-visible {
outline: 2px solid #a51f28;
outline-offset: 4px;
}
.manual-link {
display: table;
margin: 23px auto 0;
color: #333333;
font-size: 10px;
font-weight: 700;
line-height: 1.4;
text-decoration: underline;
text-underline-offset: 3px;
}
.features-section,
.benefits-section,
.subscription-section {
background: #f4f4f4;
}
.features-section {
padding: clamp(82px, 9vw, 132px) 24px 70px;
}
.features-inner {
display: grid;
grid-template-columns: minmax(300px, 520px) minmax(320px, 620px);
align-items: center;
gap: clamp(56px, 7vw, 112px);
width: min(100%, 1180px);
margin: 0 auto;
}
.feature-art {
position: relative;
min-height: clamp(440px, 38vw, 565px);
}
.feature-bg {
display: block;
width: min(75%, 430px);
border-radius: 24px;
user-select: none;
}
.feature-panel {
position: absolute;
right: 0;
bottom: 32px;
width: min(75%, 445px);
filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.12));
user-select: none;
}
.feature-copy {
max-width: 610px;
padding-top: 12px;
}
.section-title {
font-size: clamp(26px, 2.35vw, 42px);
line-height: 1.18;
}
.feature-list {
margin: 32px 0 0;
padding-left: 18px;
color: #444444;
font-size: 13px;
line-height: 1.55;
}
.feature-list li + li {
margin-top: 12px;
}
.benefits-section {
padding: 78px 24px 112px;
}
.benefits-inner {
width: min(100%, 1160px);
margin: 0 auto;
text-align: center;
}
.benefits-title {
margin-bottom: clamp(56px, 7vw, 95px);
}
.benefits-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: clamp(40px, 8vw, 118px);
align-items: start;
}
.benefit-card {
display: flex;
flex-direction: column;
align-items: center;
min-width: 0;
}
.benefit-icon {
width: 84px;
height: 84px;
object-fit: contain;
margin-bottom: 48px;
user-select: none;
}
.benefit-copy {
max-width: 248px;
margin: 0;
color: #555555;
font-size: 12px;
line-height: 1.45;
letter-spacing: 0;
}
.demo-section {
padding: 78px 24px 104px;
background: #372b28;
}
.demo-inner {
width: min(100%, 1060px);
margin: 0 auto;
text-align: center;
}
.demo-title {
margin-bottom: 14px;
color: #ffffff;
font-size: clamp(24px, 2.15vw, 34px);
line-height: 1.2;
}
.demo-video-wrap {
position: relative;
width: min(100%, 960px);
margin: 0 auto;
background: #202020;
aspect-ratio: 16 / 9;
overflow: hidden;
}
.demo-video {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
filter: grayscale(1);
}
.demo-video.is-playing {
filter: none;
}
.video-play-button {
position: absolute;
top: 50%;
left: 50%;
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 32px;
padding: 0 16px;
border: 0;
border-radius: 999px;
background: #a51f28;
color: #ffffff;
font-family: Poppins, Arial, sans-serif;
font-size: 10px;
font-weight: 700;
line-height: 1;
letter-spacing: 0;
cursor: pointer;
transform: translate(-50%, -50%);
transition:
background-color 0.2s ease,
transform 0.2s ease;
}
.video-play-button:hover {
background: #8f1720;
transform: translate(-50%, calc(-50% - 1px));
}
.play-dot {
display: block;
width: 0;
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 8px solid #ffffff;
}
.subscription-section {
padding: clamp(76px, 8vw, 104px) 24px 86px;
}
.subscription-inner {
width: min(100%, 930px);
margin: 0 auto;
}
.subscription-title {
margin-bottom: 27px;
font-size: clamp(28px, 3vw, 43px);
line-height: 1.2;
text-align: left;
}
.subscription-list {
margin: 0 auto 52px;
padding: 0;
list-style: none;
color: #333333;
font-size: 13px;
line-height: 1.48;
}
.subscription-list li {
position: relative;
padding-left: 24px;
}
.subscription-list li + li {
margin-top: 14px;
}
.subscription-list li::before {
content: '';
position: absolute;
top: 0.55em;
left: 0;
width: 10px;
height: 5px;
border-left: 2px solid #333333;
border-bottom: 2px solid #333333;
transform: rotate(-45deg);
}
.plans-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 36px;
}
.plan-card {
display: flex;
flex-direction: column;
align-items: center;
min-height: 324px;
padding: 34px 28px 30px;
border-radius: 12px;
background: #ffffff;
text-align: center;
}
.plan-icon {
width: 86px;
height: 86px;
object-fit: contain;
margin-bottom: 30px;
}
.plan-title {
margin-bottom: 34px;
color: #a51f28;
font-size: 22px;
line-height: 1.2;
}
.plan-copy {
margin: 0 0 44px;
color: #555555;
font-size: 12px;
line-height: 1.45;
}
.plan-button {
min-height: 39px;
margin-top: auto;
padding: 0 27px;
}
.legal-links {
display: flex;
flex-direction: column;
align-items: center;
gap: 18px;
margin-top: 45px;
}
.legal-links a {
color: #333333;
font-size: 10px;
font-weight: 700;
line-height: 1.2;
text-decoration: underline;
text-underline-offset: 3px;
}
@media (max-width: 980px) {
.intro-section {
min-height: 620px;
padding: 84px 24px 94px;
}
.features-inner {
grid-template-columns: 1fr;
gap: 34px;
width: min(100%, 680px);
}
.feature-art {
min-height: clamp(390px, 78vw, 560px);
}
.feature-copy {
max-width: 100%;
}
.benefits-grid {
gap: 40px;
}
.subscription-inner {
width: min(100%, 760px);
}
}
@media (max-width: 720px) {
.aida-hero {
height: 292px;
}
.aida-hero-title {
padding-top: 24px;
font-size: 42px;
}
.intro-section {
min-height: 520px;
padding: 72px 20px 78px;
}
.intro-title {
margin-bottom: 24px;
}
.features-section {
padding: 64px 20px 44px;
}
.feature-bg {
width: 72%;
}
.feature-panel {
width: 78%;
bottom: 24px;
}
.benefits-section {
padding: 52px 20px 76px;
}
.benefits-grid,
.plans-grid {
grid-template-columns: 1fr;
}
.benefit-icon {
margin-bottom: 24px;
}
.demo-section {
padding: 58px 20px 76px;
}
.subscription-section {
padding: 62px 20px 70px;
}
.subscription-title {
text-align: center;
}
.subscription-list {
margin-bottom: 40px;
}
}
@media (max-width: 480px) {
.aida-hero {
height: 250px;
min-height: 250px;
}
.aida-hero-title {
font-size: 34px;
}
.intro-copy,
.pricing-copy,
.academic-copy,
.feature-list,
.subscription-list {
font-size: 12px;
}
.feature-art {
min-height: 320px;
}
.plan-card {
min-height: 292px;
padding: 30px 22px;
}
}
</style>

View File

@@ -18,7 +18,11 @@
</script>
<template>
<section class="product-feature" :class="{ 'product-feature-reversed': reversed }" v-custom-animation.scroll>
<section
class="product-feature"
:class="{ 'product-feature-reversed': reversed }"
v-custom-animation.scroll
>
<div class="product-feature-art">
<img
class="product-feature-bg"
@@ -28,13 +32,27 @@
translate-x-s="-100"
translate-x="100"
/>
<img class="product-feature-panel" :src="panelImage" :alt="panelAlt" loading="lazy" />
<img
class="product-feature-panel"
:src="panelImage"
:alt="panelAlt"
loading="lazy"
translate-y-s="-100"
translate-y="20"
/>
</div>
<div class="product-feature-copy">
<p class="product-feature-name">{{ name }}</p>
<h2 class="product-feature-title">{{ title }}</h2>
<RouterLink class="product-feature-link" to="/products"> View More </RouterLink>
<RouterLink
class="product-feature-link"
to="/products"
translate-y-s="100"
translate-y="0"
>
View More
</RouterLink>
</div>
</section>
</template>

View File

@@ -1,47 +1,45 @@
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import aidaIntroBg from '@/assets/images/home/aida-intro-bg.png'
import aidaPanel from '@/assets/images/home/aida-panel.png'
import homeAiLogo from '@/assets/images/home/home-ai-logo.png'
import mixiIntroBg from '@/assets/images/home/mixi-intro-bg.png'
import mixiPanel from '@/assets/images/home/mixi-panel.png'
import HomeCarousel from './components/Carousel.vue'
import ProductFeature from './components/ProductFeature.vue'
import ProjectCta from './components/ProjectCta.vue'
import { useHead } from '@unhead/vue'
import aidaIntroBg from '@/assets/images/home/aida-intro-bg.png'
import aidaPanel from '@/assets/images/home/aida-panel.png'
import homeAiLogo from '@/assets/images/home/home-ai-logo.png'
import mixiIntroBg from '@/assets/images/home/mixi-intro-bg.png'
import mixiPanel from '@/assets/images/home/mixi-panel.png'
import HomeCarousel from './components/Carousel.vue'
import ProductFeature from './components/ProductFeature.vue'
import ProjectCta from './components/ProjectCta.vue'
const productFeatures = [
{
name: 'AiDA 3.1',
title:
'Empowers fashion designers to create a collection with just a few clicks based on their creative inspirations.',
backgroundImage: aidaIntroBg,
backgroundAlt: 'Fashion design sketches on paper',
panelImage: aidaPanel,
panelAlt: 'AiDA design workspace preview',
reversed: false
},
{
name: 'Mixi',
title:
"Drives sales by improving shoppers' experience through precise and fast search.",
backgroundImage: mixiIntroBg,
backgroundAlt: 'Layered fabric texture',
panelImage: mixiPanel,
panelAlt: 'Mixi visual search interface preview',
reversed: true
}
] as const
useHead({
title: 'Home | Code Create',
meta: [
const productFeatures = [
{
name: 'description',
content:
'Code Create revitalises the fashion ecosystem through artificial intelligence.'
name: 'AiDA 3.1',
title: 'Empowers fashion designers to create a collection with just a few clicks based on their creative inspirations.',
backgroundImage: aidaIntroBg,
backgroundAlt: 'Fashion design sketches on paper',
panelImage: aidaPanel,
panelAlt: 'AiDA design workspace preview',
reversed: false
},
{
name: 'Mixi',
title: "Drives sales by improving shoppers' experience through precise and fast search.",
backgroundImage: mixiIntroBg,
backgroundAlt: 'Layered fabric texture',
panelImage: mixiPanel,
panelAlt: 'Mixi visual search interface preview',
reversed: true
}
]
})
] as const
useHead({
title: 'Home | Code Create',
meta: [
{
name: 'description',
content:
'Code Create revitalises the fashion ecosystem through artificial intelligence.'
}
]
})
</script>
<template>
@@ -49,17 +47,30 @@ useHead({
<HomeCarousel />
<div class="home-content">
<section class="ecosystem-intro" aria-labelledby="ecosystem-title">
<section
class="ecosystem-intro"
aria-labelledby="ecosystem-title"
v-custom-animation.scroll
>
<img
class="ecosystem-logo"
:src="homeAiLogo"
alt="Code Create"
loading="lazy"
translate-y-s="80"
translate-y="0"
/>
<h1 id="ecosystem-title" class="ecosystem-title">
<h1
id="ecosystem-title"
class="ecosystem-title"
translate-y-s="-60"
translate-y="0"
>
Revitalise The Fashion Ecosystem
</h1>
<p class="ecosystem-subtitle">Through Artificial Intelligence (AI)</p>
<p translate-y-s="-60" translate-y="0" class="ecosystem-subtitle">
Through Artificial Intelligence (AI)
</p>
</section>
<ProductFeature
@@ -76,15 +87,6 @@ useHead({
</div>
<ProjectCta />
<section class="home-next" aria-labelledby="home-next-title">
<p class="home-next-kicker">Subheading Text</p>
<h2 id="home-next-title" class="home-next-title">Headline</h2>
<p class="home-next-copy">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit
tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
</p>
</section>
</main>
</template>
@@ -142,42 +144,6 @@ useHead({
letter-spacing: 2.5px;
}
.home-next {
padding: 18px 20px 34px;
background: #ffffff;
text-align: center;
}
.home-next-kicker {
margin: 0 0 2px;
color: #222222;
font-family: Poppins, sans-serif;
font-size: 12px;
font-weight: 400;
line-height: 1.4;
}
.home-next-title {
margin: 0 0 12px;
color: #1455ff;
font-family: Poppins, sans-serif;
font-size: 30px;
font-weight: 700;
line-height: 1.1;
letter-spacing: 0;
text-transform: none;
}
.home-next-copy {
max-width: 720px;
margin: 0 auto;
color: #202020;
font-family: Poppins, sans-serif;
font-size: 12px;
font-weight: 400;
line-height: 1.55;
}
@media (max-width: 980px) {
.home-content {
padding: 96px 0 64px;

View File

@@ -6,12 +6,11 @@ import ProductsView from './pages/ProductsView.vue'
export const routes: RouteRecordRaw[] = [
{
path: '/:lang?',
path: '/:lang(en|zh-cn|zh-tw)?',
children: [
{
path: '',
component: HomeView,
alias: ['/:lang?', '/:lang?/home']
},
{
path: 'about',
@@ -35,3 +34,4 @@ export const routes: RouteRecordRaw[] = [
]
}
]

8
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<Record<string, never>, Record<string, never>, unknown>
export default component
}