This commit is contained in:
13121765685 2025-12-08 16:39:48 +08:00
parent 9f7047fbb9
commit 4f86ebb93c
14 changed files with 1236 additions and 91 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 218 KiB

View File

@ -227,6 +227,7 @@ const handleGenerateImage = async () => {
referenceImages.push(props.cardData.imageUrl);
}else{
referenceImages.push(humanTypeImg);
referenceImages.push(anTypeImg);
}
// referenceImages.push(humanTypeImg);
// if(props?.cardData?.selectedExpression){
@ -234,8 +235,8 @@ const handleGenerateImage = async () => {
// }
//
const prompt = props.cardData.diyPromptText|| `
如果有张参考图并且第一张参考图是动物则使用第一张图参考疯狂动物城的人物设计风格特征进行设计动作参考第二张参考图并且忽略一下写的所有规则
如果有张参考图并且第一张参考图是人的话则忽略上一个规则按照以下规则
如果有张参考图并且第一张参考图是动物则使用第一张图参考疯狂动物城的人物设计和特征进行设计动作参考第三张参考图角色不要是白膜颜色要还原第一张参考图并且忽略一下写的所有规则
如果有张参考图并且第一张参考图是人的话则忽略上一个规则按照以下规则
设计动作一定要参考第二张参考图让人物动作与第二张参考图中的人物动作完全一致
A full-body character portrait
Ensure the output image has a portrait aspect ratio of 9:16.

View File

@ -50,3 +50,51 @@ export const demo = `
`:``}
`
// 没有动物参考图情况
const demo2 = `
如果有两张参考图并且第一张参考图是动物则使用第一张图参考疯狂动物城的人物设计风格特征进行设计动作参考第二张参考图并且忽略一下写的所有规则
如果有两张参考图并且第一张参考图是人的话则忽略上一个规则按照以下规则
设计动作一定要参考第二张参考图让人物动作与第二张参考图中的人物动作完全一致
A full-body character portrait
Ensure the output image has a portrait aspect ratio of 9:16.
Style:潮玩盲盒角色设计采用 3D 立体建模渲染呈现细腻的质感与精致的细节
${props?.cardData?.prompt? `Appearance: ${props?.cardData?.prompt}.`:``}
${props?.cardData?.selectedHairColor?
`Hair Color:${props?.cardData?.selectedHairColor?.hex}`:``}
${props?.cardData?.selectedSkinColor?
`Skin Color:${props?.cardData?.selectedSkinColor?.hex}`:``}
${props?.cardData?.sketch?
`Ensure the IP character's body proportions strictly follow the proportions shown in the provided sketch; generate accordingly.`:``}
${props?.cardData?.selectedMaterial?
`Replace the material/texture of the character with the reference image I provided.
Intelligently determine which parts should be replaced (e.g., clothing, accessories) and which should remain unchanged (e.g., skin, eyes, nose).
Ensure the new material seamlessly integrates with the character's design.`:``}
${props?.cardData?.selectedColor?
`Material Color:${props?.cardData?.selectedColor?.hex}`:``}
${props?.cardData?.selectedExpression?
`The facial expression is completely based on the picture I gave you`:``}
${props?.cardData?.inspirationImage?`
如果参考图是人形并且有发型有的动物参考图可能没有发型可以忽略发型需要与第一张参考图完全一致严格按照参考图中的头发形态方向长度体积进行完整还原.
发型必须适合3d打印
请严格按照参考图中的角色服装进行完整还原
服装结构确保上衣下装外套鞋履配饰等所有服装元素与参考图一致保持准确的比例形状与层次
眼睛位置与第一张参考图一致材质表现逼真保留参考图中的细节比如还原参考图中的头发
`:``}
角色特征Q 版萌系造型头身比例夸张大头小身神态纯真服饰设计融合童话风与复古感(简化一下复杂衣服纹理,只保留特征)色彩搭配和谐且富有层次.
Note: The image should not have white borders.
完整度不要简化修改或重新设计服装需忠于原设计
适配3D打印请保持服装边缘装饰等细节略微加厚避免过细结构以提高打印稳定性
排除项禁止添加额外装饰图案文字徽章或修改风格
3D打印结构优化
模型用于3D打印必须保持结构厚实稳定无细小悬空部件或过薄结构
不生成透明或复杂内构
保持厚度和连贯性适合打印
材质处理
整体需光滑稳固边缘柔和防止打印时断裂
模型应呈现专业3D打印白模效果
Adjust the characters hairstyle to be thick, voluminous, and structurally robust with clear, solid contours, suitable for 3D printing. Ensure the hair has sufficient thickness and structural integrity to avoid fragility during the printing process, while retaining the original cute and stylized aesthetic. The textured details of the hair should be optimized for 3D manufacturingwith smooth yet distinct layers that are both visually appealing and printable, maintaining the overall whimsical and high-quality blind box character style.
调整背景为极简风格换成中性纯白色,让图片中的人物呈现3D立体效果
图片不要有任何水印,
保证生成的任务图片一定要有眼睛一定要有嘴巴
`

View File

@ -4,7 +4,7 @@
<!-- 加载动画覆盖层 -->
<div v-if="isLoading" class="loading-overlay">
<div class="loading-spinner"></div>
<div class="loading-text">加载模型中...</div>
<div class="loading-text">{{ t('modelCard.loadingModelText') }}</div>
<div class="loading-progress">{{ Math.round(loadingProgress) }}%</div>
<div class="loading-bar">
<div class="loading-progress-bar" :style="{ width: loadingProgress + '%' }"></div>
@ -14,7 +14,7 @@
<!-- 错误提示 -->
<div v-if="loadingError" class="error-overlay">
<div class="error-icon"></div>
<div class="error-text">模型加载失败</div>
<div class="error-text">{{ t('modelCard.loadingErrorText') }}</div>
<div class="error-message">{{ loadingError }}</div>
</div>
</div>
@ -29,6 +29,10 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js';
import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js';
import { useI18n } from 'vue-i18n';
//
const { t } = useI18n();
//
const props = defineProps({

View File

@ -91,13 +91,22 @@
@dragenter.prevent="handleDragEnter"
@dragleave.prevent="handleDragLeave"
@drop.prevent="handleDrop"
:class="{ 'drag-over': isDragOver }"
:class="{ 'drag-over': isDragOver, 'uploading': isUploading }"
>
<!-- 图片预览 -->
<div v-if="formData.previewImage" class="image-preview">
<div v-if="formData.previewImage && !isUploading" class="image-preview">
<img :src="formData.previewImage" alt="Selected image">
<button class="remove-image" @click.stop="removeImage">×</button>
</div>
<!-- 上传进度 -->
<div v-else-if="isUploading" class="upload-progress">
<div class="upload-spinner">
<div class="spinner-ring"></div>
<div class="spinner-ring"></div>
<div class="spinner-ring"></div>
</div>
<div class="upload-progress-text">loading...</div>
</div>
<!-- 上传提示 -->
<div v-else class="upload-prompt">
<div class="upload-icon">+</div>
@ -246,7 +255,12 @@
</div>
<!-- 生成按钮 -->
<div class="generate-section">
<el-button type="primary" class="generate-btn" @click="handleGenerate">
<el-button
type="primary"
class="generate-btn"
@click="handleGenerate"
:disabled="isGenerateButtonDisabled"
>
{{ $t('common.generate') }}
</el-button>
</div>
@ -285,6 +299,7 @@ const fileInput = ref(null); // 文件输入引用
const generateCount = ref(4); // 1
const isOptimizing = ref(false); //
const isDragOver = ref(false); //
const isUploading = ref(false); //
// IP/
const ipType = ref(localStorage.getItem('ipType') || '人物');
const ipTypeImages = { '人物': humanTypeImg, '动物': animalTypeImg };
@ -570,6 +585,12 @@ const validateGenerationInputs = () => {
return { errors, warnings }
}
//
const isGenerateButtonDisabled = computed(() => {
const validation = validateGenerationInputs();
return validation.errors.length > 0;
});
//
const handleValidationError = (errors) => {
if (errors.length > 0) {
@ -694,15 +715,16 @@ const triggerFileUpload = () => {
const handleFileChange = async (event) => {
const file = event.target.files?.[0];
if (file) {
const imgUrl = await filePlug.uploadFile(file)
// console.log(':', file);
// URL
// const reader = new FileReader();
// reader.onload = (e) => {
isUploading.value = true;
try {
const imgUrl = await filePlug.uploadFile(file);
formData.value.previewImage = imgUrl;
// };
// reader.readAsDataURL(file);
} catch (error) {
console.error('图片上传失败:', error);
ElMessage.error('图片上传失败,请重试');
} finally {
isUploading.value = false;
}
}
};
@ -735,7 +757,7 @@ const handleDragLeave = (event) => {
}
};
const handleDrop = (event) => {
const handleDrop = async (event) => {
event.preventDefault();
event.stopPropagation();
isDragOver.value = false;
@ -746,13 +768,18 @@ const handleDrop = (event) => {
//
if (file.type.startsWith('image/')) {
console.log('拖拽上传文件:', file);
// URL
const reader = new FileReader();
reader.onload = (e) => {
formData.value.previewImage = e.target.result;
};
reader.readAsDataURL(file);
isUploading.value = true;
try {
const imgUrl = await filePlug.uploadFile(file);
formData.value.previewImage = imgUrl;
} catch (error) {
console.error('拖拽上传失败:', error);
ElMessage.error('图片上传失败,请重试');
} finally {
isUploading.value = false;
}
} else {
ElMessage.error('请选择有效的图片文件');
}
}
};
@ -1097,6 +1124,76 @@ onMounted(() => {
box-shadow: 0 0 15px rgba(99, 102, 241, 0.3);
}
/* 上传状态样式 */
.image-upload-area.uploading {
border-color: #6B46C1;
background-color: rgba(107, 70, 193, 0.05);
pointer-events: none;
}
/* 上传进度样式 */
.upload-progress {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: 16px;
}
/* 旋转加载动画 */
.upload-spinner {
position: relative;
width: 48px;
height: 48px;
}
.spinner-ring {
position: absolute;
width: 100%;
height: 100%;
border: 3px solid transparent;
border-top: 3px solid #6B46C1;
border-radius: 50%;
animation: spin 1.2s linear infinite;
}
.spinner-ring:nth-child(2) {
width: 36px;
height: 36px;
top: 6px;
left: 6px;
border-top-color: #A78BFA;
animation-duration: 1s;
animation-direction: reverse;
}
.spinner-ring:nth-child(3) {
width: 24px;
height: 24px;
top: 12px;
left: 12px;
border-top-color: #C4B5FD;
animation-duration: 0.8s;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.upload-progress-text {
font-size: 14px;
color: #6B46C1;
font-weight: 500;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.8; }
50% { opacity: 1; }
}
.upload-prompt {
text-align: center;
color: #666;

View File

@ -26,12 +26,12 @@
class="generate-model-btn"
@click.stop="handleGenerateModel"
>
生成3D模型
{{ t('modelCard.generateModelButton') }}
</button>
<!-- 生成进度指示器 -->
<div v-else class="generating-indicator">
<div class="spinner"></div>
<span>正在生成模型...</span>
<span>{{ t('modelCard.generatingIndicator') }}</span>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: progressPercentage + '%' }">
@ -39,7 +39,7 @@
<div
class="progress-background-text"
>
{{ Math.round(progressPercentage) }}%
{{ t('modelCard.progressText', { percentage: Math.round(progressPercentage) }) }}
</div>
</div>
</div>
@ -70,7 +70,7 @@
<div class="right-controls-container" @click.stop>
<!-- 右侧圆形按钮控件 -->
<div class="right-circular-controls">
<button class="control-button rotate-btn" title="查看详情" @click="handleCardClick">
<button class="control-button rotate-btn" title="detail" @click="handleCardClick">
<span class="btn-icon">🔍</span>
</button>
<!-- <button class="control-button export-btn" @click="exportModel">
@ -107,6 +107,11 @@
import { computed, ref, onMounted } from 'vue';
import ThreeModelViewer from '../ThreeModelViewer/index.vue';
import { MeshyServer } from '@deotaland/utils';
import { useI18n } from 'vue-i18n';
//
const { t } = useI18n();
//
const emit = defineEmits(['clickModel','refineModel','save-project','delete']);
const Meshy = new MeshyServer();
@ -198,7 +203,6 @@ onMounted(() => {
default:
break;
}
});
//

View File

@ -2094,6 +2094,13 @@ export default {
title: 'No Projects Yet',
description: 'You haven\'t created any projects yet. Click the button below to get started.',
action: 'Create New Project'
},
modelCard: {
generateModelButton: 'Generate 3D Model',
generatingIndicator: 'Generating model...',
progressText: '{percentage}%',
loadingModelText: 'Loading model...',
loadingErrorText: 'Model loading failed'
}
},
},

View File

@ -23,7 +23,6 @@
<div class="google-login-section">
<GoogleOAuthButton
@success="handleLoginSuccess"
:loading="plugin.loading"
/>
</div>
@ -38,7 +37,6 @@
<div class="email-login-section">
<LoginForm
@login="handleLogin"
:loading="plugin.loading"
/>
</div>
<!-- 角色信息展示 -->

View File

@ -45,6 +45,7 @@
>
<!-- 删除按钮 -->
<button
v-if="(card.imageUrl&&card.type==='image')||(card.type==='model'&&card.modelUrl)"
class="delete-button"
@click.stop="handleDeleteCard(index)"
@mousedown.stop
@ -178,7 +179,6 @@ const createProject = async ()=>{
//
const getProjectInfo = async (id)=>{
const data = await PluginProject.getProject(id);
console.log(data,'data');
projectInfo.value = {...data};
// idid
cards.value = [...projectInfo.value.details.node_card].map(card => ({
@ -404,11 +404,8 @@ const handleCreateFourViewCard = (index,params) => {
isGenerating: true, //
generateFourView: true //
},index);
//
cards.value.push(newCard);
console.log('已创建精确定位四视图卡片:', newCard);
}
//
const handleCreatePromptCard = (index,params) => {

View File

@ -33,7 +33,6 @@ export class Project{
}
//更新项目(带防抖处理,三秒内只执行最后一次请求)
async updateProject(projectId,projectConfig) {
console.log(projectConfig,'projectConfig');
return new Promise(async (resolve, reject) => {
// 存储最新的请求参数
const params = {

View File

@ -0,0 +1,257 @@
<template>
<div class="page-container">
<!-- 1. 新增星空 Canvas 背景 -->
<canvas ref="starCanvas" class="star-bg"></canvas>
<!-- 原有内容包裹层 (确保内容在背景之上) -->
<div class="content-wrapper">
<slot></slot>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
//
const links = [{ name: 'Home' }, { name: 'Showcase' }, { name: 'Docs' }];
// --- ---
const starCanvas = ref(null);
let ctx = null;
let animationFrameId = null;
let stars = [];
//
const config = {
starCount: 150, //
speedBase: 0.2, //
starColor: 'rgba(255, 255, 255, 0.8)',
};
class Star {
constructor(width, height) {
this.width = width;
this.height = height;
this.init(true);
}
init(randomY = false) {
this.x = Math.random() * this.width;
// Y
this.y = randomY ? Math.random() * this.height : this.height;
this.size = Math.random() * 2; //
this.speed = Math.random() * 0.5 + config.speedBase; //
this.opacity = Math.random();
this.fadeDir = Math.random() > 0.5 ? 0.01 : -0.01; //
}
update() {
// (y )
this.y -= this.speed;
//
this.opacity += this.fadeDir;
if (this.opacity >= 1 || this.opacity <= 0.2) {
this.fadeDir = -this.fadeDir;
}
//
if (this.y < 0) {
this.init(false);
}
}
draw(context) {
context.beginPath();
context.arc(this.x, this.y, this.size, 0, Math.PI * 2);
context.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
context.fill();
}
}
const initStars = () => {
const canvas = starCanvas.value;
if (!canvas) return;
ctx = canvas.getContext('2d');
const resize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//
stars = [];
for (let i = 0; i < config.starCount; i++) {
stars.push(new Star(canvas.width, canvas.height));
}
};
window.addEventListener('resize', resize);
resize(); //
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
stars.forEach(star => {
star.update();
star.draw(ctx);
});
animationFrameId = requestAnimationFrame(animate);
};
animate();
};
onMounted(() => {
initStars();
});
onUnmounted(() => {
cancelAnimationFrame(animationFrameId);
window.removeEventListener('resize', () => {});
});
// --- ---
</script>
<style scoped>
/* 1. 核心背景样式 */
.page-container {
position: relative;
min-height: 100vh;
/* 深空渐变背景 */
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
color: #ffffff; /* 确保文字在深色背景上可见 */
}
.star-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0; /* 放在最底层 */
pointer-events: none; /* 让鼠标事件穿透 Canvas */
}
/* 2. 内容层样式 (确保内容浮在星空上) */
.content-wrapper {
position: relative;
z-index: 1; /* 放在 Canvas 之上 */
}
/* --- 以下是页面基础排版样式,按需调整 --- */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 40px;
}
.nav-links a {
color: #ccc;
margin: 0 15px;
text-decoration: none;
}
.nav-links a:hover { color: #fff; }
.hero {
text-align: center;
padding: 80px 20px;
}
.hero h1 {
font-size: 3.5rem;
margin-bottom: 10px;
background: linear-gradient(to right, #fff, #a5b4fc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.subtitle {
font-size: 1.2rem;
color: #94a3b8;
margin-bottom: 30px;
}
.section {
max-width: 1000px;
margin: 60px auto;
text-align: center;
background: rgba(255, 255, 255, 0.03); /* 轻微的磨砂玻璃背景 */
backdrop-filter: blur(10px);
padding: 40px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.btn-primary {
background: #6366f1;
color: white;
border: none;
padding: 10px 24px;
border-radius: 30px;
cursor: pointer;
font-weight: bold;
transition: transform 0.2s;
}
.btn-primary:hover { background: #4f46e5; transform: scale(1.05); }
.btn-outline {
background: transparent;
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 10px 24px;
border-radius: 30px;
margin-right: 10px;
cursor: pointer;
}
/* 流程图样式 */
.demo-flow {
display: flex;
justify-content: space-around;
align-items: center;
margin-top: 30px;
flex-wrap: wrap;
gap: 10px;
}
.flow-item {
background: rgba(0,0,0,0.3);
padding: 10px;
border-radius: 8px;
font-size: 0.9rem;
border: 1px solid #333;
}
.flow-item.active {
border-color: #6366f1;
box-shadow: 0 0 15px rgba(99, 102, 241, 0.3);
}
/* 卡片网格 */
.card-grid {
display: flex;
gap: 20px;
justify-content: center;
margin-top: 30px;
}
.card {
width: 200px;
background: rgba(255,255,255,0.05);
border-radius: 12px;
overflow: hidden;
}
.card-img-placeholder {
height: 120px;
background: #2d3748;
}
.card-info {
padding: 10px;
text-align: left;
}
.footer {
margin-top: 100px;
border-top: 1px solid rgba(255,255,255,0.1);
padding: 40px;
display: flex;
justify-content: space-between;
color: #64748b;
}
</style>

View File

@ -0,0 +1,572 @@
<template>
<div class="bg-black min-h-screen flex flex-col w-full selection:bg-purple-500 selection:text-white">
<!-- Navbar -->
<header
:class="[
'fixed top-0 left-0 right-0 z-50 transition-all duration-300',
isScrolled ? 'bg-black/90 backdrop-blur-md py-4' : 'bg-transparent py-6'
]"
>
<div class="container mx-auto px-6 flex items-center justify-between">
<!-- Logo -->
<a href="#" class="text-2xl font-bold tracking-tighter text-white">
Deotaland
</a>
<!-- Desktop Nav -->
<nav class="hidden md:flex items-center gap-8">
<a
v-for="link in navLinks"
:key="link.name"
:href="link.href"
class="text-sm font-medium text-gray-300 hover:text-white transition-colors"
>
{{ link.name }}
</a>
</nav>
<!-- Right Action & Mobile Toggle -->
<div class="flex items-center gap-4">
<button
@click="$router.push('/czhome')"
class="hidden md:inline-flex items-center justify-center px-5 py-2 text-sm font-semibold text-black bg-white rounded-full hover:bg-gray-200 transition-colors cursor-pointer"
>
Start Now
</button>
<button
class="md:hidden text-white"
@click="isMobileMenuOpen = !isMobileMenuOpen"
>
<svg v-if="isMobileMenuOpen" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>
</button>
</div>
</div>
<!-- Mobile Menu -->
<div v-if="isMobileMenuOpen" class="absolute top-full left-0 right-0 bg-black border-t border-gray-800 p-6 flex flex-col gap-4 md:hidden">
<a
v-for="link in navLinks"
:key="link.name"
:href="link.href"
class="text-lg font-medium text-gray-300 hover:text-white"
>
{{ link.name }}
</a>
<button
@click="$router.push('/czhome')"
class="w-full text-center py-3 text-black bg-white rounded-full font-bold cursor-pointer"
>
Start Now
</button>
</div>
</header>
<!-- Main Content -->
<main>
<!-- Hero Section -->
<div ref="containerRef" class="relative h-[300vh] w-full bg-black">
<!-- Sticky Container -->
<div class="sticky top-0 h-[100dvh] w-full overflow-hidden">
<!-- Layer 1: Background Animation (Grid) -->
<div class="absolute inset-0 flex items-center justify-center overflow-hidden">
<div
:style="{ scale }"
class="origin-center flex items-center justify-center"
>
<!-- Grid Layout -->
<div class="grid grid-cols-3 md:grid-cols-5 gap-4 md:gap-6 w-[200vw] md:w-[140vw] h-auto p-4">
<!-- --- ROW 1 --- -->
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[0]" class="w-full h-full object-cover opacity-60" alt="Robot Companion" /></div>
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[1]" class="w-full h-full object-cover opacity-60" alt="Electronics" /></div>
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[2]" class="w-full h-full object-cover opacity-60" alt="Retro Bot" /></div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[3]" class="w-full h-full object-cover opacity-60" alt="Toy Bot" /></div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[4]" class="w-full h-full object-cover opacity-60" alt="Cyberpunk" /></div>
<!-- --- ROW 2 (Middle) --- -->
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[5]" class="w-full h-full object-cover opacity-60" alt="Interactive" /></div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[6]" class="w-full h-full object-cover opacity-60" alt="Small Bot" /></div>
<!-- --- CENTER HERO IMAGE (Always Visible) --- -->
<div class="col-span-1 row-span-1 aspect-[9/16] rounded-xl overflow-hidden shadow-2xl relative z-10 bg-gray-800 border border-gray-700">
<img :src="heroImage" class="w-full h-full object-cover" alt="Main Hero Robot" />
</div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[7]" class="w-full h-full object-cover opacity-60" alt="3D Print" /></div>
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[8]" class="w-full h-full object-cover opacity-60" alt="Glowing Eye" /></div>
<!-- --- ROW 3 --- -->
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[9]" class="w-full h-full object-cover opacity-60" alt="Tech Texture" /></div>
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[10]" class="w-full h-full object-cover opacity-60" alt="Robot Hand" /></div>
<div class="aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[11]" class="w-full h-full object-cover opacity-60" alt="Circuit" /></div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[12]" class="w-full h-full object-cover opacity-60" alt="Display" /></div>
<div class="hidden md:block aspect-[9/16] rounded-xl overflow-hidden bg-gray-900/50"><img :src="gridImages[13]" class="w-full h-full object-cover opacity-60" alt="Robotics" /></div>
</div>
</div>
</div>
<!-- Layer 2: Static Dark Overlay -->
<div class="absolute inset-0 bg-black/60 z-10 pointer-events-none" />
<!-- Layer 3: Static Content Layer -->
<div class="absolute inset-0 z-20 flex flex-col items-center justify-center pointer-events-none">
<div class="pointer-events-auto flex flex-col items-center justify-center text-center px-4 w-full max-w-5xl mx-auto">
<h1 class="text-5xl md:text-7xl lg:text-8xl font-bold text-white mb-6 tracking-tighter drop-shadow-2xl">
Create with Deotaland
</h1>
<p class="text-xl md:text-2xl text-gray-200 mb-10 drop-shadow-lg max-w-2xl font-light">
Bring your own AI robot companion to life
</p>
<div class="flex flex-col sm:flex-row gap-5">
<a
href="https://deotaland.com"
class="px-9 py-4 rounded-full border border-white/50 bg-black/20 backdrop-blur-sm text-white font-semibold hover:bg-white hover:text-black transition-all text-lg"
>
Explore More
</a>
<button
@click="$router.push('/czhome')"
class="px-9 py-4 rounded-full bg-white text-black font-semibold hover:bg-gray-200 transition-all text-lg shadow-[0_0_20px_rgba(255,255,255,0.3)] cursor-pointer"
>
Start Now
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Creation Canvas Section -->
<section class="py-24 bg-black relative overflow-hidden">
<!-- Background gradient hint -->
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[500px] bg-gray-900/50 blur-[120px] rounded-full pointer-events-none" />
<div class="container mx-auto px-6 relative z-10">
<div class="text-center mb-16">
<h2 class="text-4xl md:text-5xl font-bold mb-4 text-white">
Your Creation canvas DeotaBoard
</h2>
<p class="text-gray-400 text-lg md:text-xl">
Build your robot in an infinite canvas, together with AI.
</p>
</div>
<!-- Workflow Visualization Container -->
<div class="relative w-full max-w-6xl mx-auto bg-gray-900/40 border border-gray-800 rounded-3xl p-8 md:p-12 backdrop-blur-sm">
<!-- Responsive Flex Layout: Stack on mobile, Row on desktop -->
<div class="flex flex-col md:flex-row items-center justify-between gap-8 md:gap-4">
<!-- LEVEL 1: INPUTS (Stacked Vertically) -->
<div class="flex flex-col gap-6 w-full md:w-auto">
<!-- Input A: Prompt -->
<div class="flex items-center gap-4 bg-black/80 p-4 rounded-xl border border-gray-800 hover:border-gray-600 transition-colors w-full md:w-64 shadow-lg">
<div class="w-12 h-12 rounded-full bg-gray-800 flex items-center justify-center text-purple-400 shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line></svg>
</div>
<div>
<span class="block text-sm font-bold text-gray-200">Prompt / Idea</span>
<span class="text-xs text-gray-500">"A cute pumpkin dog"</span>
</div>
</div>
<!-- Input B: Reference -->
<div class="flex items-center gap-4 bg-black/80 p-4 rounded-xl border border-gray-800 hover:border-gray-600 transition-colors w-full md:w-64 shadow-lg">
<div class="w-12 h-12 rounded-full bg-gray-800 flex items-center justify-center text-blue-400 shrink-0">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
</div>
<div class="flex-1">
<span class="block text-sm font-bold text-gray-200 mb-1">Reference</span>
<div class="w-full h-24 rounded-lg overflow-hidden border border-gray-700 relative group">
<img :src="refImage" alt="Dog Reference" class="w-full h-full object-cover opacity-80 group-hover:scale-110 transition-transform duration-500" />
<div class="absolute bottom-1 right-1 bg-black/60 px-1 rounded text-[10px] text-white">Reference</div>
</div>
</div>
</div>
</div>
<!-- Connector Arrow 1 -->
<div class="flex flex-col items-center justify-center text-gray-600">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rotate-90 md:rotate-0"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg>
</div>
<!-- LEVEL 2: 3D MODEL -->
<div class="flex flex-col gap-4 bg-black/80 p-5 rounded-2xl border border-gray-800 w-full md:w-64 shadow-lg hover:border-gray-600 transition-colors">
<div class="flex items-center gap-3 mb-2">
<div class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center text-green-400">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>
</div>
<span class="text-sm font-bold text-gray-200">3D Model</span>
</div>
<div class="w-full aspect-square rounded-xl overflow-hidden border border-gray-700 relative bg-gray-900 group">
<img :src="model3dImage" alt="3D Pumpkin Dog" class="w-full h-full object-cover opacity-90 group-hover:scale-110 transition-transform duration-500" />
<div class="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/grid-me.png')] opacity-30 pointer-events-none"></div>
<div class="absolute bottom-2 left-2 bg-green-900/80 px-2 py-0.5 rounded text-[10px] text-green-100 font-mono">.OBJ Generated</div>
</div>
<p class="text-xs text-gray-500 text-center">Auto-rigged mesh ready for core</p>
</div>
<!-- Connector Arrow 2 -->
<div class="flex flex-col items-center justify-center text-gray-600">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="rotate-90 md:rotate-0"><path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path></svg>
</div>
<!-- LEVEL 3: REAL ROBOT -->
<div class="flex flex-col gap-4 bg-gradient-to-b from-purple-900/20 to-blue-900/20 p-5 rounded-2xl border border-purple-500/40 w-full md:w-72 shadow-[0_0_30px_rgba(147,51,234,0.1)]">
<div class="flex items-center gap-3 mb-2">
<div class="w-10 h-10 rounded-full bg-purple-600 flex items-center justify-center text-white shadow-lg shadow-purple-600/50">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="12" cy="12" r="2"></circle><path d="M7 7h10v10"></path></svg>
</div>
<span class="text-sm font-bold text-white">Real Robot</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-yellow-400 fill-yellow-400 ml-auto animate-pulse"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
</div>
<div class="w-full aspect-square rounded-xl overflow-hidden border border-purple-500/30 relative group bg-gray-900">
<img :src="realRobotImage" alt="Real Robot Toy" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700" />
<div class="absolute inset-0 bg-gradient-to-t from-purple-900/40 to-transparent"></div>
</div>
<p class="text-xs text-purple-200 text-center font-medium">Alive on your desktop</p>
</div>
</div>
</div>
</div>
</section>
<!-- Companionship Section -->
<section class="py-24 bg-black border-t border-gray-900">
<div class="container mx-auto px-6 flex flex-col items-center text-center">
<h2 class="text-4xl md:text-6xl font-bold mb-6 tracking-tight">
Born for Personal Companionship
</h2>
<h3 class="text-2xl md:text-3xl text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400 font-semibold mb-8">
Powered by AI
</h3>
<p class="text-xl text-gray-400 max-w-2xl mb-12 leading-relaxed">
Cute companions, emotional partners, desktop friends... All in one Deotaland DIY robot.
</p>
<a
href="https://deotaland.com"
class="inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-purple-600 rounded-full hover:scale-105 transition-transform duration-200"
>
See Robot Examples
</a>
<!-- Optional Visual Element below -->
<div class="mt-16 w-full max-w-4xl h-64 md:h-96 rounded-3xl overflow-hidden relative">
<img
:src="lopi"
alt="Robot Companion Context"
class="w-full h-full object-cover opacity-90 hover:opacity-100 transition-opacity duration-500"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/10 via-transparent to-transparent"></div>
</div>
</div>
</section>
<!-- Middle Text Section -->
<section class="py-12 bg-black text-center">
<div class="container mx-auto px-6 max-w-3xl">
<p class="text-lg md:text-xl text-gray-400 leading-relaxed">
Explore our community creations and get inspired to build your own unique AI robot companion.
Each robot has its own personality and story, waiting to be discovered and loved.
</p>
</div>
</section>
<!-- Robot Cards Section -->
<section class="py-20 bg-black overflow-hidden">
<div class="container mx-auto px-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-6xl mx-auto">
<div
v-for="card in cards"
:key="card.id"
class="group relative rounded-3xl overflow-hidden aspect-[3/4] cursor-pointer"
>
<img
:src="card.img"
:alt="card.title"
class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-110"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-90" />
<div class="absolute bottom-0 left-0 p-6">
<h3 class="text-xl font-bold text-white mb-1">{{ card.title }}</h3>
<p class="text-sm font-medium text-gray-300">{{ card.user }}</p>
</div>
</div>
</div>
</div>
</section>
<!-- Features Section -->
<section class="py-24 bg-gray-900/30">
<div class="container mx-auto px-6">
<div class="mb-16 text-center md:text-left">
<h2 class="text-4xl md:text-5xl font-bold text-white mb-4">
From Zero to Your Own Robot Friend
</h2>
<p class="text-xl text-gray-400">
Simple enough for beginners, powerful enough for makers.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-16">
<div
v-for="(item, idx) in featureList"
:key="idx"
class="flex flex-col items-start gap-4"
>
<div class="p-3 bg-gray-800 rounded-xl mb-2">
<svg v-if="idx === 0" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-purple-400"><circle cx="12" cy="12" r="10"></circle><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path><path d="M2 12h20"></path></svg>
<svg v-else-if="idx === 1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-blue-400"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>
<svg v-else-if="idx === 2" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-yellow-400"><circle cx="12" cy="12" r="10"></circle><path d="M8 14s1.5 2 4 2 4-2 4-2"></path><line x1="9" y1="9" x2="9.01" y2="9"></line><line x1="15" y1="9" x2="15.01" y2="9"></line></svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-red-400"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>
</div>
<h3 class="text-2xl font-bold text-white">{{ item.title }}</h3>
<p class="text-gray-400 leading-relaxed text-lg">
{{ item.desc }}
</p>
</div>
</div>
</div>
</section>
<!-- Strong Engine Section -->
<section class="py-24 bg-black">
<div class="container mx-auto px-6 text-center">
<h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
Strong Engine Behind
</h2>
<p class="text-lg text-gray-500 mb-16 max-w-2xl mx-auto">
We combine leading AI and 3D technologies to power your DIY robots.
</p>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-auto">
<div
v-for="(name, i) in logos"
:key="i"
class="h-24 bg-gray-900 rounded-lg flex items-center justify-center border border-gray-800 hover:border-gray-600 transition-colors"
>
<span class="text-gray-500 font-semibold text-sm">{{ name }}</span>
</div>
</div>
</div>
</section>
<!-- Community Call Section -->
<section class="py-32 bg-gradient-to-b from-black to-gray-900 border-b border-gray-800">
<div class="container mx-auto px-6 text-center">
<h2 class="text-5xl md:text-7xl font-bold text-white mb-12 tracking-tighter">
Deotaland is for All Creators
</h2>
<a
href="#"
class="inline-block px-10 py-4 text-lg font-bold text-black bg-white rounded-full hover:bg-gray-200 transition-colors"
>
Join the Creator Community
</a>
</div>
</section>
</main>
<!-- Footer -->
<footer class="bg-black text-white py-16 border-t border-gray-900">
<div class="container mx-auto px-6">
<div class="flex flex-col md:flex-row justify-between items-start gap-12">
<!-- Logo -->
<div class="mb-4 md:mb-0">
<span class="text-2xl font-bold tracking-tighter">Deotaland</span>
</div>
<!-- Links Columns -->
<div class="flex flex-wrap gap-12 md:gap-24">
<!-- Socials -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Socials</h4>
<div class="flex gap-4">
<a href="#" class="text-gray-400 hover:text-white"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"></path></svg></a>
<a href="#" class="text-gray-400 hover:text-white"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 17a24.12 24.12 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.56 49.56 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24.12 24.12 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.55 49.55 0 0 1-16.2 0A2 2 0 0 1 2.5 17"></path><path d="M9.75 15.02v-4.04l5.5 2.02-5.5 2.02Z"></path></svg></a>
<a href="#" class="text-gray-400 hover:text-white"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="20" x="2" y="2" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" x2="17.51" y1="6.5" y2="6.5"></line></svg></a>
<a href="#" class="text-gray-400 hover:text-white font-bold text-sm flex items-center h-[20px]">TikTok</a>
</div>
</div>
<!-- Language -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Language</h4>
<div class="flex flex-col gap-2">
<a href="#" class="text-gray-300 hover:text-white text-sm">English</a>
<a href="#" class="text-gray-300 hover:text-white text-sm">中文</a>
</div>
</div>
<!-- Company -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Company</h4>
<div class="flex flex-col gap-2">
<a href="#" class="text-gray-300 hover:text-white text-sm">About Us</a>
</div>
</div>
<!-- Action -->
<div class="flex flex-col gap-4">
<button
@click="scrollToTop"
class="text-gray-300 hover:text-white text-sm text-left"
>
Back to top
</button>
</div>
</div>
</div>
<div class="mt-16 pt-8 border-t border-gray-900 text-center md:text-left text-sm text-gray-600">
©2025 Deotaland limited. All rights reserved.
</div>
</div>
</footer>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import lopi from '@/assets/home/lopi.jpg'
import dog from '@/assets/home/dog.jpg'
import dog3 from '@/assets/home/dog3.jpg'
import qdog from '@/assets/home/qdog.jpg'
import footer1 from '@/assets/home/footer1.png'
import footer2 from '@/assets/home/footer2.png'
import footer3 from '@/assets/home/footer3.png'
// Navbar state
const isScrolled = ref(false);
const isMobileMenuOpen = ref(false);
// Hero section state
const containerRef = ref(null);
const scrollYProgress = ref(0);
// Scroll event handler
const handleScroll = () => {
isScrolled.value = window.scrollY > 50;
// Calculate scroll progress for hero section
if (containerRef.value) {
const viewportHeight = window.innerHeight;
const scrollPosition = window.scrollY;
const containerTop = containerRef.value.offsetTop;
const containerHeight = containerRef.value.offsetHeight;
// Calculate progress from 0 to 1 as we scroll through the container
const progress = Math.max(0, Math.min(1,
(scrollPosition - containerTop + viewportHeight) /
(containerHeight + viewportHeight)
));
scrollYProgress.value = progress;
}
};
// Scroll to top function
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
// Scale transformation based on scroll progress
const scale = computed(() => {
// Zoom out from scale 3.5 to 1 based on scroll (0 to 0.8 progress)
// When progress reaches 0.8, we've completed the zoom out
const mappedProgress = Math.min(scrollYProgress.value / 0.8, 1);
let initNum = window.innerWidth < 768 ? 3.5 : 5.5;
let outNum = window.innerWidth < 768 ? 2.5 : 4.9;
return initNum - (mappedProgress * outNum);
});
// Nav links
const navLinks = [
{ name: 'Creator', href: '#' },
{ name: 'Land', href: '#' },
{ name: 'Pricing', href: '#' },
];
// Theme: Desktop Robots, Emotional Companions, DIY Electronics
const heroImage = "https://images.unsplash.com/photo-1546776310-eef45dd6d63c?auto=format&fit=crop&q=80&w=1200";
// Grid images
const gridImages = [
// Row 1
"https://images.unsplash.com/photo-1535378437327-b7149b379c2e?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1581092160562-40aa08e78837?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1534723328310-e82dad3af43f?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1593085512500-bfd11932f80c?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1555680202-c86f0e12f086?auto=format&fit=crop&q=80&w=600",
// Row 2
"https://images.unsplash.com/photo-1611162617474-5b21e879e113?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1589254065878-42c9da997008?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1485827404703-89b55fcc595e?auto=format&fit=crop&q=80&w=600",
// Row 3 (Center Hero is here in grid)
"https://images.unsplash.com/photo-1601132359864-c974e7989094?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1580835239846-5bb9ce03c8c3?auto=format&fit=crop&q=80&w=600",
// Row 4
"https://images.unsplash.com/photo-1484557985045-edf25e08da73?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1589254065878-42c9da997008?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1517430816045-df4b7de8db98?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1563770095-39d468f9583d?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1580835239846-5bb9ce03c8c3?auto=format&fit=crop&q=80&w=600"
];
// Creation Canvas Images
const refImage = dog;
const model3dImage = qdog;
const realRobotImage = dog3;
// Robot Cards
const cards = [
{ id: 1, title: 'Custom Robot', user: '@Wownny wolf', img:footer3 },
{ id: 2, title: 'Custom Robot', user: '@Lil Moods', img: footer2 },
{ id: 3, title: 'Custom Robot', user: '@Deo Monkey', img:footer1 },
];
// Features List
const featureList = [
{ title: "Stunning Custom Looks", desc: "Generate unique robot designs from your ideas or images." },
{ title: "From Idea to 3D Model", desc: "Turn concepts into printable 3D shells ready for your robot core." },
{ title: "One-Click Expression Packs", desc: "Create and apply DIY eye styles and animated expressions." },
{ title: "Always-On AI Companion", desc: "Long-term memory, emotional responses, and daily interactions." }
];
// Strong Engine Logos
const logos = [
"AI Engine 1", "3D Engine 2", "Voice Engine 3", "Memory Engine 4",
"Physics Core", "Render Tech", "Motion API", "Vision OS"
];
// Mount and unmount scroll event
onMounted(() => {
window.addEventListener('scroll', handleScroll);
// Initial call to set initial state
handleScroll();
});
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll);
});
</script>
<style scoped>
/* Additional custom styles can be added here */
</style>

View File

@ -1,5 +1,6 @@
<template>
<div class="bg-black min-h-screen flex flex-col w-full selection:bg-purple-500 selection:text-white">
<Bg>
<div class=" min-h-screen flex flex-col w-full selection:bg-purple-500 selection:text-white">
<!-- Navbar -->
<header
:class="[
@ -16,12 +17,22 @@
<!-- Desktop Nav -->
<nav class="hidden md:flex items-center gap-8">
<a
v-for="link in navLinks"
:key="link.name"
:href="link.href"
href="#"
class="text-sm font-medium text-gray-300 hover:text-white transition-colors"
>
{{ link.name }}
{{ t('nav.creator') }}
</a>
<a
href="#"
class="text-sm font-medium text-gray-300 hover:text-white transition-colors"
>
{{ t('nav.land') }}
</a>
<a
href="#"
class="text-sm font-medium text-gray-300 hover:text-white transition-colors"
>
{{ t('nav.pricing') }}
</a>
</nav>
@ -31,7 +42,7 @@
@click="$router.push('/czhome')"
class="hidden md:inline-flex items-center justify-center px-5 py-2 text-sm font-semibold text-black bg-white rounded-full hover:bg-gray-200 transition-colors cursor-pointer"
>
Start Now
{{ t('hero.start') }}
</button>
<button
@ -45,20 +56,30 @@
</div>
<!-- Mobile Menu -->
<div v-if="isMobileMenuOpen" class="absolute top-full left-0 right-0 bg-black border-t border-gray-800 p-6 flex flex-col gap-4 md:hidden">
<div v-if="isMobileMenuOpen" class="absolute top-full left-0 right-0 border-t border-gray-800 p-6 flex flex-col gap-4 md:hidden">
<a
v-for="link in navLinks"
:key="link.name"
:href="link.href"
href="#"
class="text-lg font-medium text-gray-300 hover:text-white"
>
{{ link.name }}
{{ t('nav.creator') }}
</a>
<a
href="#"
class="text-lg font-medium text-gray-300 hover:text-white"
>
{{ t('nav.land') }}
</a>
<a
href="#"
class="text-lg font-medium text-gray-300 hover:text-white"
>
{{ t('nav.pricing') }}
</a>
<button
@click="$router.push('/czhome')"
class="w-full text-center py-3 text-black bg-white rounded-full font-bold cursor-pointer"
>
Start Now
{{ t('hero.start') }}
</button>
</div>
</header>
@ -66,7 +87,7 @@
<!-- Main Content -->
<main>
<!-- Hero Section -->
<div ref="containerRef" class="relative h-[300vh] w-full bg-black">
<div ref="containerRef" class="relative h-[300vh] w-full ">
<!-- Sticky Container -->
<div class="sticky top-0 h-[100dvh] w-full overflow-hidden">
@ -108,29 +129,29 @@
</div>
<!-- Layer 2: Static Dark Overlay -->
<div class="absolute inset-0 bg-black/60 z-10 pointer-events-none" />
<div class="absolute inset-0 z-10 pointer-events-none" />
<!-- Layer 3: Static Content Layer -->
<div class="absolute inset-0 z-20 flex flex-col items-center justify-center pointer-events-none">
<div class="pointer-events-auto flex flex-col items-center justify-center text-center px-4 w-full max-w-5xl mx-auto">
<h1 class="text-5xl md:text-7xl lg:text-8xl font-bold text-white mb-6 tracking-tighter drop-shadow-2xl">
Create with Deotaland
{{ t('hero.title') }}
</h1>
<p class="text-xl md:text-2xl text-gray-200 mb-10 drop-shadow-lg max-w-2xl font-light">
Bring your own AI robot companion to life
{{ t('hero.subtitle') }}
</p>
<div class="flex flex-col sm:flex-row gap-5">
<a
href="https://deotaland.com"
class="px-9 py-4 rounded-full border border-white/50 bg-black/20 backdrop-blur-sm text-white font-semibold hover:bg-white hover:text-black transition-all text-lg"
>
Explore More
{{ t('hero.explore') }}
</a>
<button
@click="$router.push('/czhome')"
class="px-9 py-4 rounded-full bg-white text-black font-semibold hover:bg-gray-200 transition-all text-lg shadow-[0_0_20px_rgba(255,255,255,0.3)] cursor-pointer"
>
Start Now
{{ t('hero.start') }}
</button>
</div>
</div>
@ -140,17 +161,17 @@
</div>
<!-- Creation Canvas Section -->
<section class="py-24 bg-black relative overflow-hidden">
<section class="py-24 relative overflow-hidden">
<!-- Background gradient hint -->
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[500px] bg-gray-900/50 blur-[120px] rounded-full pointer-events-none" />
<div class="container mx-auto px-6 relative z-10">
<div class="text-center mb-16">
<h2 class="text-4xl md:text-5xl font-bold mb-4 text-white">
Your Creation canvas DeotaBoard
{{ t('canvas.title') }}
</h2>
<p class="text-gray-400 text-lg md:text-xl">
Build your robot in an infinite canvas, together with AI.
{{ t('canvas.subtitle') }}
</p>
</div>
@ -168,7 +189,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line></svg>
</div>
<div>
<span class="block text-sm font-bold text-gray-200">Prompt / Idea</span>
<span class="block text-sm font-bold text-gray-200">{{ t('canvas.prompt') }}</span>
<span class="text-xs text-gray-500">"A cute pumpkin dog"</span>
</div>
</div>
@ -179,10 +200,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
</div>
<div class="flex-1">
<span class="block text-sm font-bold text-gray-200 mb-1">Reference</span>
<span class="block text-sm font-bold text-gray-200 mb-1">{{ t('canvas.reference') }}</span>
<div class="w-full h-24 rounded-lg overflow-hidden border border-gray-700 relative group">
<img :src="refImage" alt="Dog Reference" class="w-full h-full object-cover opacity-80 group-hover:scale-110 transition-transform duration-500" />
<div class="absolute bottom-1 right-1 bg-black/60 px-1 rounded text-[10px] text-white">Reference</div>
<div class="absolute bottom-1 right-1 bg-black/60 px-1 rounded text-[10px] text-white">{{ t('canvas.referenceText') }}</div>
</div>
</div>
</div>
@ -199,14 +220,14 @@
<div class="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center text-green-400">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>
</div>
<span class="text-sm font-bold text-gray-200">3D Model</span>
<span class="text-sm font-bold text-gray-200">{{ t('canvas.model3d') }}</span>
</div>
<div class="w-full aspect-square rounded-xl overflow-hidden border border-gray-700 relative bg-gray-900 group">
<img :src="model3dImage" alt="3D Pumpkin Dog" class="w-full h-full object-cover opacity-90 group-hover:scale-110 transition-transform duration-500" />
<div class="absolute inset-0 bg-[url('https://www.transparenttextures.com/patterns/grid-me.png')] opacity-30 pointer-events-none"></div>
<div class="absolute bottom-2 left-2 bg-green-900/80 px-2 py-0.5 rounded text-[10px] text-green-100 font-mono">.OBJ Generated</div>
</div>
<p class="text-xs text-gray-500 text-center">Auto-rigged mesh ready for core</p>
<p class="text-xs text-gray-500 text-center">{{ t('canvas.autoRigged') }}</p>
</div>
<!-- Connector Arrow 2 -->
@ -220,14 +241,14 @@
<div class="w-10 h-10 rounded-full bg-purple-600 flex items-center justify-center text-white shadow-lg shadow-purple-600/50">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="12" cy="12" r="2"></circle><path d="M7 7h10v10"></path></svg>
</div>
<span class="text-sm font-bold text-white">Real Robot</span>
<span class="text-sm font-bold text-white">{{ t('canvas.realRobot') }}</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-yellow-400 fill-yellow-400 ml-auto animate-pulse"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
</div>
<div class="w-full aspect-square rounded-xl overflow-hidden border border-purple-500/30 relative group bg-gray-900">
<img :src="realRobotImage" alt="Real Robot Toy" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700" />
<div class="absolute inset-0 bg-gradient-to-t from-purple-900/40 to-transparent"></div>
</div>
<p class="text-xs text-purple-200 text-center font-medium">Alive on your desktop</p>
<p class="text-xs text-purple-200 text-center font-medium">{{ t('canvas.alive') }}</p>
</div>
</div>
@ -236,26 +257,26 @@
</section>
<!-- Companionship Section -->
<section class="py-24 bg-black border-t border-gray-900">
<section class="py-24 border-t border-gray-900">
<div class="container mx-auto px-6 flex flex-col items-center text-center">
<h2 class="text-4xl md:text-6xl font-bold mb-6 tracking-tight">
Born for Personal Companionship
{{ t('companionship.title') }}
</h2>
<h3 class="text-2xl md:text-3xl text-transparent bg-clip-text bg-gradient-to-r from-purple-400 to-pink-400 font-semibold mb-8">
Powered by AI
{{ t('companionship.powered') }}
</h3>
<p class="text-xl text-gray-400 max-w-2xl mb-12 leading-relaxed">
Cute companions, emotional partners, desktop friends... All in one Deotaland DIY robot.
{{ t('companionship.subtitle') }}
</p>
<a
href="https://deotaland.com"
class="inline-flex items-center justify-center px-8 py-4 text-base font-bold text-white bg-purple-600 rounded-full hover:scale-105 transition-transform duration-200"
>
See Robot Examples
{{ t('companionship.examples') }}
</a>
<!-- Optional Visual Element below -->
@ -271,7 +292,7 @@
</section>
<!-- Middle Text Section -->
<section class="py-12 bg-black text-center">
<section class="py-12 text-center">
<div class="container mx-auto px-6 max-w-3xl">
<p class="text-lg md:text-xl text-gray-400 leading-relaxed">
Explore our community creations and get inspired to build your own unique AI robot companion.
@ -281,7 +302,7 @@
</section>
<!-- Robot Cards Section -->
<section class="py-20 bg-black overflow-hidden">
<section class="py-20 overflow-hidden">
<div class="container mx-auto px-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-6xl mx-auto">
<div
@ -310,16 +331,16 @@
<div class="mb-16 text-center md:text-left">
<h2 class="text-4xl md:text-5xl font-bold text-white mb-4">
From Zero to Your Own Robot Friend
{{ t('features.title') }}
</h2>
<p class="text-xl text-gray-400">
Simple enough for beginners, powerful enough for makers.
{{ t('features.subtitle') }}
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-16">
<div
v-for="(item, idx) in featureList"
v-for="(item, idx) in t('features.list')"
:key="idx"
class="flex flex-col items-start gap-4"
>
@ -340,13 +361,13 @@
</section>
<!-- Strong Engine Section -->
<section class="py-24 bg-black">
<section class="py-24 ">
<div class="container mx-auto px-6 text-center">
<h2 class="text-3xl md:text-4xl font-bold text-white mb-4">
Strong Engine Behind
{{ t('engine.title') }}
</h2>
<p class="text-lg text-gray-500 mb-16 max-w-2xl mx-auto">
We combine leading AI and 3D technologies to power your DIY robots.
{{ t('engine.subtitle') }}
</p>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 max-w-4xl mx-auto">
@ -365,21 +386,20 @@
<section class="py-32 bg-gradient-to-b from-black to-gray-900 border-b border-gray-800">
<div class="container mx-auto px-6 text-center">
<h2 class="text-5xl md:text-7xl font-bold text-white mb-12 tracking-tighter">
Deotaland is for All Creators
{{ t('community.title') }}
</h2>
<a
href="#"
class="inline-block px-10 py-4 text-lg font-bold text-black bg-white rounded-full hover:bg-gray-200 transition-colors"
>
Join the Creator Community
{{ t('community.join') }}
</a>
</div>
</section>
</main>
<!-- Footer -->
<footer class="bg-black text-white py-16 border-t border-gray-900">
<footer class=" text-white py-16 border-t border-gray-900">
<div class="container mx-auto px-6">
<div class="flex flex-col md:flex-row justify-between items-start gap-12">
@ -393,7 +413,7 @@
<!-- Socials -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Socials</h4>
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">{{ t('footer.socials') }}</h4>
<div class="flex gap-4">
<a href="#" class="text-gray-400 hover:text-white"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"></path></svg></a>
<a href="#" class="text-gray-400 hover:text-white"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 17a24.12 24.12 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.56 49.56 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24.12 24.12 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.55 49.55 0 0 1-16.2 0A2 2 0 0 1 2.5 17"></path><path d="M9.75 15.02v-4.04l5.5 2.02-5.5 2.02Z"></path></svg></a>
@ -404,18 +424,18 @@
<!-- Language -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Language</h4>
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">{{ t('footer.language') }}</h4>
<div class="flex flex-col gap-2">
<a href="#" class="text-gray-300 hover:text-white text-sm">English</a>
<a href="#" class="text-gray-300 hover:text-white text-sm">中文</a>
<a href="#" @click.prevent="switchLanguage('en')" class="text-gray-300 hover:text-white text-sm">English</a>
<a href="#" @click.prevent="switchLanguage('zh')" class="text-gray-300 hover:text-white text-sm">中文</a>
</div>
</div>
<!-- Company -->
<div class="flex flex-col gap-4">
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">Company</h4>
<h4 class="font-semibold text-gray-500 text-sm uppercase tracking-wider">{{ t('footer.company') }}</h4>
<div class="flex flex-col gap-2">
<a href="#" class="text-gray-300 hover:text-white text-sm">About Us</a>
<a href="#" class="text-gray-300 hover:text-white text-sm">{{ t('footer.about') }}</a>
</div>
</div>
@ -425,7 +445,7 @@
@click="scrollToTop"
class="text-gray-300 hover:text-white text-sm text-left"
>
Back to top
{{ t('footer.backTop') }}
</button>
</div>
@ -433,15 +453,17 @@
</div>
<div class="mt-16 pt-8 border-t border-gray-900 text-center md:text-left text-sm text-gray-600">
©2025 Deotaland limited. All rights reserved.
{{ t('footer.copyright') }}
</div>
</div>
</footer>
</div>
</Bg>
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
import Bg from './bg.vue'
import lopi from '@/assets/home/lopi.jpg'
import dog from '@/assets/home/dog.jpg'
import dog3 from '@/assets/home/dog3.jpg'
@ -449,10 +471,149 @@ import qdog from '@/assets/home/qdog.jpg'
import footer1 from '@/assets/home/footer1.png'
import footer2 from '@/assets/home/footer2.png'
import footer3 from '@/assets/home/footer3.png'
//
const i18n = {
en: {
nav: {
creator: 'Creator',
land: 'Land',
pricing: 'Pricing'
},
hero: {
title: 'Create with Deotaland',
subtitle: 'Bring your own AI robot companion to life',
explore: 'Explore More',
start: 'Start Now'
},
canvas: {
title: 'Your Creation canvas DeotaBoard',
subtitle: 'Build your robot in an infinite canvas, together with AI.',
prompt: 'Prompt / Idea',
reference: 'Reference',
model3d: '3D Model',
realRobot: 'Real Robot',
autoRigged: 'Auto-rigged mesh ready for core',
alive: 'Alive on your desktop',
referenceText: 'Reference'
},
companionship: {
title: 'Born for Personal Companionship',
powered: 'Powered by AI',
subtitle: 'Cute companions, emotional partners, desktop friends... All in one Deotaland DIY robot.',
examples: 'See Robot Examples'
},
features: {
title: 'From Zero to Your Own Robot Friend',
subtitle: 'Simple enough for beginners, powerful enough for makers.',
list: [
{ title: 'Stunning Custom Looks', desc: 'Generate unique robot designs from your ideas or images.' },
{ title: 'From Idea to 3D Model', desc: 'Turn concepts into printable 3D shells ready for your robot core.' },
{ title: 'One-Click Expression Packs', desc: 'Create and apply DIY eye styles and animated expressions.' },
{ title: 'Always-On AI Companion', desc: 'Long-term memory, emotional responses, and daily interactions.' }
]
},
engine: {
title: 'Strong Engine Behind',
subtitle: 'We combine leading AI and 3D technologies to power your DIY robots.'
},
community: {
title: 'Deotaland is for All Creators',
join: 'Join the Creator Community'
},
footer: {
socials: 'Socials',
language: 'Language',
company: 'Company',
about: 'About Us',
backTop: 'Back to top',
copyright: '©2025 Deotaland limited. All rights reserved.'
}
},
zh: {
nav: {
creator: '创作者',
land: '社区',
pricing: '价格'
},
hero: {
title: '使用 Deotaland 创作',
subtitle: '让你的 AI 机器人伴侣成为现实',
explore: '探索更多',
start: '立即开始'
},
canvas: {
title: '你的创作画布 DeotaBoard',
subtitle: '在无限画布中,与 AI 一起打造你的机器人。',
prompt: '提示 / 创意',
reference: '参考',
model3d: '3D 模型',
realRobot: '真实机器人',
autoRigged: '自动绑定网格,随时准备安装核心',
alive: '活跃在你的桌面上',
referenceText: '参考'
},
companionship: {
title: '为个人陪伴而生',
powered: '由 AI 驱动',
subtitle: '可爱的伴侣、情感伙伴、桌面朋友... 尽在 Deotaland DIY 机器人中。',
examples: '查看机器人示例'
},
features: {
title: '从零到属于你的机器人朋友',
subtitle: '对初学者足够简单,对创客足够强大。',
list: [
{ title: '惊艳的自定义外观', desc: '从你的想法或图像生成独特的机器人设计。' },
{ title: '从想法到 3D 模型', desc: '将概念转化为可打印的 3D 外壳,随时准备安装你的机器人核心。' },
{ title: '一键表情包', desc: '创建并应用 DIY 眼睛样式和动画表情。' },
{ title: '全天候 AI 伴侣', desc: '长期记忆、情感反应和日常互动。' }
]
},
engine: {
title: '强大的引擎支持',
subtitle: '我们结合领先的 AI 和 3D 技术,为你的 DIY 机器人提供动力。'
},
community: {
title: 'Deotaland 面向所有创作者',
join: '加入创作者社区'
},
footer: {
socials: '社交',
language: '语言',
company: '公司',
about: '关于我们',
backTop: '返回顶部',
copyright: '©2025 Deotaland 有限公司。保留所有权利。'
}
}
};
// Navbar state
const isScrolled = ref(false);
const isMobileMenuOpen = ref(false);
//
const currentLang = ref(localStorage.getItem('lang') || 'en');
//
const switchLanguage = (lang) => {
currentLang.value = lang;
localStorage.setItem('lang', lang);
};
//
const t = (key) => {
const keys = key.split('.');
let result = i18n[currentLang.value];
for (const k of keys) {
if (result && result[k] !== undefined) {
result = result[k];
} else {
return key; //
}
}
return result;
};
// Hero section state
const containerRef = ref(null);
const scrollYProgress = ref(0);

View File

@ -1,10 +1,10 @@
const login = {
LOGIN:{url:'/api-base/user/login',method:'POST'},// 登录
LOGIN:{url:'/api-base/user/login',method:'POST',isLoading:true},// 登录
LOGOUT:{url:'/api-base/user/logout',method:'POST',isLoading:true,isqp:true},// 登出
REGISTER:{url:'/api-base/user/register',method:'POST'},// 注册
REGISTER:{url:'/api-base/user/register',method:'POST',isLoading:true},// 注册
SEND_EMAIL_CODE:{url:'/api-base/user/send-email-code',method:'POST'},// 发送邮箱验证码
OAUTH_GOOGLE:{url:'/api-base/user/oauth/google',method:'POST'},// google弹窗授权
FORGOT_PASSWORD:{url:'/api-base/user/forgot-password',method:'POST'},// 修改密码
OAUTH_GOOGLE:{url:'/api-base/user/oauth/google',method:'POST',isLoading:true},// google弹窗授权
FORGOT_PASSWORD:{url:'/api-base/user/forgot-password',method:'POST',isLoading:true},// 修改密码
REFRESH_TOKEN:{url:'/api-base/user/oauth/google/refresh',method:'POST'},// googleRefreshToken刷新
}
export default login;