优化项目配置并更新文档
- 更新 README 文档,增加项目介绍和说明 - 优化 Vite 配置,支持多页面入口和路径别名 - 移除未使用的 MyProject.vue 组件 - 更新项目依赖包版本 - 添加 Tailwind CSS 相关配置 - 优化编辑器布局和样式 - 添加 UI 组件库支持 - 更新 Logo 和加载动画 - 修复国际化配置 Made-with: Cursor
This commit is contained in:
@@ -1,113 +1,65 @@
|
||||
# <img src="https://editor.astraljs.com/static/images/logo/logo.png" width="30" height="30"> Astral 3D Editor
|
||||
# NeonVision 3D Editor
|
||||
|
||||
🌍 [简体中文](README.md) | English
|
||||
[简体中文](README.md) | English
|
||||
|
||||
## Core Features
|
||||
|
||||
Link:
|
||||
[](https://github.com/mlt131220/Astral3D)
|
||||
[](https://gitee.com/mlt131220/Astral3D)
|
||||
[](https://editor.astraljs.com)
|
||||
- Multi-format support: 30+ model formats (GLTF/OBJ/FBX/GLB/RVT/IFC, etc.)
|
||||
- BIM Model Lightweight Display (RVT/IFC)
|
||||
- CAD Drawing Analysis (DWG/DXF)
|
||||
- Scene Subpackage Storage and Loading
|
||||
- Animation Editor
|
||||
|
||||
> Modern Web 3D editor based on Vue3 + Three.js
|
||||
## Extended Capabilities
|
||||
|
||||
<div align="center">
|
||||
<img src="http://editor-doc.astraljs.com/images/home/thumbnailDark.png?t=20250518" width="800" alt="Editor City Preview">
|
||||
<img src="http://editor-doc.astraljs.com/images/home/industryDark.png?t=20250318" width="800" alt="Editor Preview">
|
||||
</div>
|
||||
- Plugin System
|
||||
- Script Runtime
|
||||
- Particle System
|
||||
- Weather System
|
||||
- Cloud Storage Integration
|
||||
- Resource Center
|
||||
|
||||
## 💬 Join the community
|
||||
## Technology Stack
|
||||
|
||||
Get the latest news and technical support in the following ways:
|
||||
- Vue 3.5+
|
||||
- Three.js r176+
|
||||
- Cesium 1.107+
|
||||
- Naive UI 2.43+
|
||||
- UnoCSS 0.46+
|
||||
|
||||
|  | -07C160?logo=wechat&logoColor=white) |
|
||||
|---------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img src="https://fs.mhbdng.cn/temp/4851677b-661d-4e60-884d-414316290425.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=6TE7OKPZN15R380TGT1V%2F20260111%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260111T135452Z&X-Amz-Expires=3600&X-Amz-Security-Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJwYXJlbnQiOiJtbHQxMzEyMjAiLCJleHAiOjE3NjgxODExNTV9.RAvlAnLKtG-9rNIZMrO5lrSJc_N1VqHf3yF3-slD59b-miNqdorqsI9Zmaz6_imBe_uw1u5KMt_OGE7No-vxfA&X-Amz-Signature=4868484133727ab3881d0f7eb65a52db07ee91bc154b4bf4b88d19a91446188e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject" width="200"> | <img src="https://fs.mhbdng.cn/temp/c1c7ecef-d655-4bb3-97e8-54402e3a48ef.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=6TE7OKPZN15R380TGT1V%2F20260111%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260111T135514Z&X-Amz-Expires=3600&X-Amz-Security-Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJwYXJlbnQiOiJtbHQxMzEyMjAiLCJleHAiOjE3NjgxODExNTV9.RAvlAnLKtG-9rNIZMrO5lrSJc_N1VqHf3yF3-slD59b-miNqdorqsI9Zmaz6_imBe_uw1u5KMt_OGE7No-vxfA&X-Amz-Signature=7005038e2ded3dbad425f6a23341002bf79c3ffe9f2166af18348dcaeb61dca0&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject" width="200"> |
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js ≥ 20.x
|
||||
- PNPM
|
||||
|
||||
## 🚀 Core competence
|
||||
### Local Development
|
||||
|
||||
### Core function
|
||||
- ✅ Multi-format support: 30+ model format (GLTF/OBJ/FBX/GLB/RVT/IFC, etc.)
|
||||
- ✅ BIM Model Lightweight Demonstration (RVT/IFC)
|
||||
- ✅ CAD drawing analysis (DWG/DXF)
|
||||
- ✅ Scenario subcontract storage and loading
|
||||
- ✅ Animation editor
|
||||
|
||||
### Expansion capability
|
||||
- 🧩 plug-in system
|
||||
- 📜 When the script is running
|
||||
- 💫 Particle system
|
||||
- ❄️ Weather system
|
||||
- ☁️ Cloud Storage Integration (USS again)
|
||||
- 🎠 Resource center
|
||||
|
||||
### Coming soon
|
||||
- 🚧 Physical engine support
|
||||
- 🚧 WebGPU support
|
||||
- 🚧 Data components (API/WebSocket)
|
||||
- 🚧 low code data large screen
|
||||
- 🚧 WebSocket Multi-party collaboration
|
||||
|
||||
## 🛠️ Technology stack
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## ⚡ Quick start
|
||||
|
||||
### pre-demand
|
||||
- Node.js ≥ 23.11.x
|
||||
- Yarn
|
||||
|
||||
### Local run
|
||||
```bash
|
||||
git clone https://github.com/mlt131220/Astral3D.git
|
||||
# Clone the project
|
||||
git clone <your-repo-url>
|
||||
|
||||
cd Astral3D
|
||||
pnpm install
|
||||
pnpm run sdk:build
|
||||
pnpm run editor:dev
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Build SDK
|
||||
pnpm run sdk:build
|
||||
|
||||
# Start dev server
|
||||
pnpm run editor:dev
|
||||
```
|
||||
|
||||
### Production construction
|
||||
### Production Build
|
||||
|
||||
```bash
|
||||
pnpm run editor:build
|
||||
pnpm run editor:build
|
||||
```
|
||||
|
||||
## 📚 Ecological correlation
|
||||
## License
|
||||
|
||||
### Back-end implementation
|
||||
[](https://github.com/yx8663/astral-service)
|
||||
Open source under Apache 2.0 License.
|
||||
|
||||
### Document center
|
||||
[](http://editor-doc.astraljs.com/)
|
||||
---
|
||||
|
||||
## ☕ Support project
|
||||
|
||||
If this project is helpful to you, please feel free to:
|
||||
|
||||
1. In case wall [user] (https://github.com/mlt131220/Astral3D/issues/2) leave your usage scenario
|
||||
2. Scan code support developers:
|
||||
|
||||
| AliPay | WeChat |
|
||||
|---------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||
| <img src="https://editor-doc.astraljs.com/images/AliPay.png" width="200"> | <img src="https://editor-doc.astraljs.com/images/WeChatPay.png" width="200"> |
|
||||
|
||||
## ⚖️ License agreement
|
||||
|
||||
This project adopts the [![Apache License] (https://img.shields.io/badge/License-Apache_2.0-blue.svg)] (License) open source licenses, please comply with the terms of the agreement and the following supplementary conditions:
|
||||
|
||||
- ✅ allows: individual learning/secondary development
|
||||
- ⚠️ A copyright notice is required
|
||||
- ⚠️ commercial use requires authorization
|
||||
- ❌ Prohibited: using this project for business or illegal purposes that are competitive with **hangzhou xingluan digital technology**
|
||||
|
||||
**[Full legal notice](LEGAL.md)** | **[Contribution guide](CONTRIBUTING.md)**
|
||||
|
||||
## 🌟 Star trend
|
||||
|
||||
[](https://star-history.com/#mlt131220/Astral3D&Date)
|
||||
*More content to be added*
|
||||
|
||||
@@ -1,126 +1,65 @@
|
||||
# <img src="https://editor.astraljs.com/static/images/logo/logo.png" width="30" height="30"> Astral 3D Editor
|
||||
# NeonVision 3D Editor
|
||||
|
||||
🌍 简体中文 | [English](README.en.md)
|
||||
简体中文 | [English](README.en.md)
|
||||
|
||||
直达:
|
||||
[](https://github.com/mlt131220/Astral3D)
|
||||
[](https://gitee.com/mlt131220/Astral3D)
|
||||
[](https://editor.astraljs.com)
|
||||
## 核心功能
|
||||
|
||||
> 基于 Vue3 + Three.js 的现代 Web 3D 编辑器
|
||||
- 多格式支持:30+ 模型格式(GLTF/OBJ/FBX/GLB/RVT/IFC等)
|
||||
- BIM模型轻量化展示(RVT/IFC)
|
||||
- CAD图纸解析(DWG/DXF)
|
||||
- 场景分包存储与加载
|
||||
- 动画编辑器
|
||||
|
||||
<div align="center">
|
||||
<img src="http://editor-doc.astraljs.com/images/home/thumbnailDark.png?t=20250518" width="800" alt="Editor City Preview">
|
||||
<img src="http://editor-doc.astraljs.com/images/home/industryDark.png?t=20250318" width="800" alt="Editor Preview">
|
||||
</div>
|
||||
## 扩展能力
|
||||
|
||||
## 💬 加入社区
|
||||
- 插件系统
|
||||
- 脚本运行时
|
||||
- 粒子系统
|
||||
- 天气系统
|
||||
- 云存储集成
|
||||
- 资源中心
|
||||
|
||||
通过以下方式获取最新动态和技术支持:
|
||||
## 技术栈
|
||||
|
||||
|  | -07C160?logo=wechat&logoColor=white)
|
||||
|---------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img src="https://fs.mhbdng.cn/temp/4851677b-661d-4e60-884d-414316290425.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=6TE7OKPZN15R380TGT1V%2F20260111%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260111T135452Z&X-Amz-Expires=3600&X-Amz-Security-Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJwYXJlbnQiOiJtbHQxMzEyMjAiLCJleHAiOjE3NjgxODExNTV9.RAvlAnLKtG-9rNIZMrO5lrSJc_N1VqHf3yF3-slD59b-miNqdorqsI9Zmaz6_imBe_uw1u5KMt_OGE7No-vxfA&X-Amz-Signature=4868484133727ab3881d0f7eb65a52db07ee91bc154b4bf4b88d19a91446188e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject" width="200"> | <img src="https://fs.mhbdng.cn/temp/c1c7ecef-d655-4bb3-97e8-54402e3a48ef.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=6TE7OKPZN15R380TGT1V%2F20260111%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260111T135514Z&X-Amz-Expires=3600&X-Amz-Security-Token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJwYXJlbnQiOiJtbHQxMzEyMjAiLCJleHAiOjE3NjgxODExNTV9.RAvlAnLKtG-9rNIZMrO5lrSJc_N1VqHf3yF3-slD59b-miNqdorqsI9Zmaz6_imBe_uw1u5KMt_OGE7No-vxfA&X-Amz-Signature=7005038e2ded3dbad425f6a23341002bf79c3ffe9f2166af18348dcaeb61dca0&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject" width="200">
|
||||
- Vue 3.5+
|
||||
- Three.js r176+
|
||||
- Cesium 1.107+
|
||||
- Naive UI 2.43+
|
||||
- UnoCSS 0.46+
|
||||
|
||||
|
||||
|
||||
|
||||
## 🚀 核心能力
|
||||
|
||||
### 核心功能
|
||||
- ✅ 多格式支持:[30+ 模型格式(GLTF/OBJ/FBX/GLB/RVT/IFC等)](http://editor-doc.astraljs.com/guide/f7smai4w/#%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C%E5%8C%BA)
|
||||
- ✅ BIM模型轻量化展示(RVT/IFC)
|
||||
- ✅ CAD图纸解析(DWG/DXF)
|
||||
- ✅ 场景分包存储与加载
|
||||
- ✅ 动画编辑器
|
||||
|
||||
### 扩展能力
|
||||
- 🧩 插件系统
|
||||
- 📜 脚本运行时
|
||||
- 💫 粒子系统
|
||||
- ❄️ 天气系统
|
||||
- ☁️ 云存储集成(又拍云 USS)
|
||||
- 🎠 资源中心
|
||||
|
||||
### 即将到来
|
||||
- 🚧 物理引擎支持
|
||||
- 🚧 WebGPU 支持
|
||||
- 🚧 数据组件(API/WebSocket)
|
||||
- 🚧 低代码数据大屏
|
||||
- 🚧 WebSocket 多人协作
|
||||
|
||||
## 🛠️ 技术栈
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## ⚡ 快速开始
|
||||
## 快速开始
|
||||
|
||||
### 前置需求
|
||||
- Node.js ≥ 23.11.x
|
||||
- PNPM
|
||||
```
|
||||
# 进入项目时
|
||||
nvm use 23.11.0
|
||||
# 或者如果 .nvmrc 已存在,直接:
|
||||
nvm use
|
||||
|
||||
# 如果还是不行,手动修复 PATH 顺序:
|
||||
$env:PATH = "E:\nvm4w\nodejs;$env:PATH"
|
||||
nvm version # 应显示 1.1.12
|
||||
nvm install 23.11.0
|
||||
nvm use 23.11.0
|
||||
node --version
|
||||
```
|
||||
- Node.js ≥ 20.x
|
||||
- PNPM
|
||||
|
||||
### 本地运行
|
||||
```bash
|
||||
git clone https://github.com/mlt131220/Astral3D.git
|
||||
|
||||
cd Astral3D
|
||||
pnpm install
|
||||
pnpm run sdk:build
|
||||
pnpm run editor:dev
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone <your-repo-url>
|
||||
|
||||
# 安装依赖
|
||||
pnpm install
|
||||
|
||||
# 构建 SDK
|
||||
pnpm run sdk:build
|
||||
|
||||
# 启动开发服务器
|
||||
pnpm run editor:dev
|
||||
```
|
||||
|
||||
### 生产构建
|
||||
|
||||
```bash
|
||||
pnpm run editor:build
|
||||
pnpm run editor:build
|
||||
```
|
||||
|
||||
## 📚 生态相关
|
||||
## 许可协议
|
||||
|
||||
### 后端实现
|
||||
[](https://github.com/yx8663/astral-service)
|
||||
基于 Apache 2.0 许可证开源。
|
||||
|
||||
### 文档中心
|
||||
[](http://editor-doc.astraljs.com/)
|
||||
---
|
||||
|
||||
## ☕ 支持项目
|
||||
|
||||
如果本项目对您有帮助,欢迎:
|
||||
|
||||
1. 在 [用户案例墙](https://github.com/mlt131220/Astral3D/issues/2) 留下您的使用场景
|
||||
2. 扫码支持开发者:
|
||||
|
||||
| 支付宝 | 微信 |
|
||||
|---------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||
| <img src="https://editor-doc.astraljs.com/images/AliPay.png" width="200"> | <img src="https://editor-doc.astraljs.com/images/WeChatPay.png" width="200"> |
|
||||
|
||||
## ⚖️ 许可协议
|
||||
|
||||
本项目采用 [](LICENSE) 开源协议,使用时请遵守协议条款及以下补充条款:
|
||||
|
||||
- ✅ 允许:个人学习/二次开发
|
||||
- ⚠️ 需要版权声明
|
||||
- ⚠️ 商业用途需要授权
|
||||
- ❌ 禁止:将本项目用于与**杭州星孪数字科技**有竞争性的业务或非法用途
|
||||
|
||||
**[完整法律声明](LEGAL.md)** | **[贡献指南](CONTRIBUTING.md)**
|
||||
|
||||
## 🌟 Star 趋势
|
||||
|
||||
[](https://star-history.com/#mlt131220/Astral3D&Date)
|
||||
*更多内容待补充*
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
{
|
||||
"name": "astral3d",
|
||||
"version": "1.0.0",
|
||||
"description": "Astral3D Engine",
|
||||
"author": "ErSan <mlt131220@163.com>",
|
||||
"scripts": {
|
||||
"docs:dev": "pnpm run -C packages/docs docs:dev",
|
||||
"docs:dev-clean": "pnpm run -C packages/docs docs:dev-clean",
|
||||
"docs:build": "pnpm run -C packages/docs docs:build",
|
||||
"docs:preview": "pnpm run -C packages/docs docs:preview",
|
||||
"editor:dev": "pnpm run -C packages/editor dev",
|
||||
"editor:build": "pnpm run sdk:build && pnpm run -C packages/editor build",
|
||||
"editor:tsc": "pnpm run -C packages/editor tsc",
|
||||
"editor:preview": "pnpm run -C packages/editor preview",
|
||||
"sdk:dev": "pnpm run -C packages/sdk dev",
|
||||
"sdk:build": "pnpm run -C packages/sdk build",
|
||||
"examples:dev": "pnpm run -C packages/examples dev",
|
||||
"examples:build": "pnpm run -C packages/examples build"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=23.0.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"devDependencies": {
|
||||
"prettier": "^3.7.4"
|
||||
},
|
||||
"packageManager": "pnpm@10.8.1"
|
||||
{
|
||||
"name": "astral3d",
|
||||
"version": "1.0.0",
|
||||
"description": "Astral3D Engine",
|
||||
"author": "ErSan <mlt131220@163.com>",
|
||||
"scripts": {
|
||||
"docs:dev": "pnpm run -C packages/docs docs:dev",
|
||||
"docs:dev-clean": "pnpm run -C packages/docs docs:dev-clean",
|
||||
"docs:build": "pnpm run -C packages/docs docs:build",
|
||||
"docs:preview": "pnpm run -C packages/docs docs:preview",
|
||||
"editor:dev": "pnpm run -C packages/editor dev",
|
||||
"editor:build": "pnpm run sdk:build && pnpm run -C packages/editor build",
|
||||
"editor:tsc": "pnpm run -C packages/editor tsc",
|
||||
"editor:preview": "pnpm run -C packages/editor preview",
|
||||
"sdk:dev": "pnpm run -C packages/sdk dev",
|
||||
"sdk:build": "pnpm run -C packages/sdk build",
|
||||
"examples:dev": "pnpm run -C packages/examples dev",
|
||||
"examples:build": "pnpm run -C packages/examples build"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=23.0.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4.2.1",
|
||||
"prettier": "^3.7.4"
|
||||
},
|
||||
"packageManager": "pnpm@10.8.1"
|
||||
}
|
||||
13
Astral3D/packages/editor/components.d.ts
vendored
13
Astral3D/packages/editor/components.d.ts
vendored
@@ -8,8 +8,15 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
AssetPreview: typeof import('./src/components/preview/AssetPreview.vue')['default']
|
||||
Button: typeof import('./src/components/ui/Button/Button.vue')['default']
|
||||
CAD: typeof import('./src/components/drawing/toolbar/CAD.vue')['default']
|
||||
CadLayers: typeof import('./src/components/drawing/toolbar/CadLayers.vue')['default']
|
||||
Card: typeof import('./src/components/ui/Card/Card.vue')['default']
|
||||
CardContent: typeof import('./src/components/ui/Card/CardContent.vue')['default']
|
||||
CardDescription: typeof import('./src/components/ui/Card/CardDescription.vue')['default']
|
||||
CardFooter: typeof import('./src/components/ui/Card/CardFooter.vue')['default']
|
||||
CardHeader: typeof import('./src/components/ui/Card/CardHeader.vue')['default']
|
||||
CardTitle: typeof import('./src/components/ui/Card/CardTitle.vue')['default']
|
||||
CesiumConfig: typeof import('./src/components/project/CesiumConfig.vue')['default']
|
||||
Clear: typeof import('./src/components/header/navigation/Clear.vue')['default']
|
||||
CodeEditor: typeof import('./src/components/code/CodeEditor.vue')['default']
|
||||
@@ -18,6 +25,11 @@ declare module 'vue' {
|
||||
CommonPreview_backup: typeof import('./src/components/preview/CommonPreview_backup.vue')['default']
|
||||
Copy: typeof import('./src/components/header/navigation/Copy.vue')['default']
|
||||
Delete: typeof import('./src/components/header/navigation/Delete.vue')['default']
|
||||
Dialog: typeof import('./src/components/ui/Dialog/Dialog.vue')['default']
|
||||
DialogClose: typeof import('./src/components/ui/Dialog/DialogClose.vue')['default']
|
||||
DialogDescription: typeof import('./src/components/ui/Dialog/DialogDescription.vue')['default']
|
||||
DialogHeader: typeof import('./src/components/ui/Dialog/DialogHeader.vue')['default']
|
||||
DialogTitle: typeof import('./src/components/ui/Dialog/DialogTitle.vue')['default']
|
||||
Do: typeof import('./src/components/header/navigation/Do.vue')['default']
|
||||
Drawing: typeof import('./src/components/drawing/Drawing.vue')['default']
|
||||
EarthGenerator: typeof import('./src/components/es/plugin/builtin/EarthGenerator.vue')['default']
|
||||
@@ -41,6 +53,7 @@ declare module 'vue' {
|
||||
HtmlPanelCode: typeof import('./src/components/code/HtmlPanelCode.vue')['default']
|
||||
Image: typeof import('./src/components/drawing/toolbar/Image.vue')['default']
|
||||
ImportExport: typeof import('./src/components/header/navigation/ImportExport.vue')['default']
|
||||
Input: typeof import('./src/components/ui/Input/Input.vue')['default']
|
||||
JSONEditor: typeof import('./src/components/code/JSONEditor.vue')['default']
|
||||
Locale: typeof import('./src/components/setting/common/Locale.vue')['default']
|
||||
Logo: typeof import('./src/components/header/Logo.vue')['default']
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" sizes="any" type="image/svg+xml" href="/static/images/logo/logo.svg"/>
|
||||
<link rel="mask-icon" href="/static/images/logo/logo.svg" color="#63E2B7" />
|
||||
<link rel="apple-touch-icon" href="/static/images/logo/pwa/pwa-180x180.png" sizes="180x180" />
|
||||
<meta name="theme-color" content="#63E2B7" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="author" content="ErSan,mlt131220@163.com">
|
||||
<meta name="copyright" content="ErSan,mlt131220@163.com">
|
||||
<meta name="keywords" content="threejs,editor,threeeditor,三维,三维可视化,3D,3D编辑器,编辑器,模型,网页设计工具,低代码,lowcode, WebGL,WebGPU,BIM,rvt,ifc,CAD,dwg,dxf">
|
||||
<meta name="description" content="一款基于THREE.JS开发的专业的面相浏览器端(webgl/webgpu)的三维可视化编辑器,包含BIM轻量化,CAD解析预览等特色功能">
|
||||
<!-- 百度seo -->
|
||||
<meta name="baidu-site-verification" content="codeva-AVKCbnEhHf" />
|
||||
<!-- bing seo -->
|
||||
<meta name="msvalidate.01" content="51C05441E591099C88B3C1975F9B9D73" />
|
||||
<!-- google seo -->
|
||||
<meta name="google-site-verification" content="_hU0qCzBII0F3mupE17AaGpLznXbpQ89WGNaxrhVqfE" />
|
||||
<title>Astral 3D Editor - 高效的三维可视化编辑工具</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" sizes="any" type="image/svg+xml" href="/static/images/logo/logo.svg"/>
|
||||
<link rel="mask-icon" href="/static/images/logo/logo.svg" color="#0EA5E9" />
|
||||
<link rel="apple-touch-icon" href="/static/images/logo/pwa/pwa-180x180.png" sizes="180x180" />
|
||||
<meta name="theme-color" content="#0EA5E9" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="keywords" content="美术馆数字驾驶舱,数字孪生,3D编辑器,threejs,三维可视化,3D,编辑器,模型,网页设计工具,低代码,lowcode, WebGL,WebGPU,BIM,rvt,ifc,CAD,dwg,dxf">
|
||||
<meta name="description" content="美术馆数字驾驶舱 - 新一代数字孪生可视化编辑器,基于THREE.JS开发的专业Web端三维编辑器,包含BIM轻量化、CAD解析预览等特色功能">
|
||||
<title>美术馆数字驾驶舱 - 新一代数字孪生编辑器</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -24,12 +24,17 @@
|
||||
"animate.css": "^4.1.1",
|
||||
"axios": "^1.8.2",
|
||||
"cesium": "^1.126.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"disable-devtool": "^0.3.8",
|
||||
"keyframe-resample": "^0.1.0",
|
||||
"lucide-vue-next": "^0.577.0",
|
||||
"meshoptimizer": "^0.23.0",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"naive-ui": "catalog:",
|
||||
"pinia": "^2.1.4",
|
||||
"radix-vue": "^1.9.17",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"three": "catalog:",
|
||||
"vite-plugin-static-copy": "catalog:",
|
||||
"vue": "catalog:",
|
||||
@@ -40,9 +45,12 @@
|
||||
"@astral3d/build-vite-plugins": "workspace:^",
|
||||
"@types/cesium": "^1.70.4",
|
||||
"@types/three": "catalog:",
|
||||
"@vitejs/plugin-vue":"catalog:",
|
||||
"@vitejs/plugin-vue": "catalog:",
|
||||
"autoprefixer": "^10.4.27",
|
||||
"dotenv": "^16.3.1",
|
||||
"less": "^4.3.0",
|
||||
"postcss": "^8.5.8",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"typescript": "catalog:",
|
||||
"unocss": "^66.1.0-beta.12",
|
||||
"unplugin-vue-components": "^0.27.3",
|
||||
|
||||
6
Astral3D/packages/editor/postcss.config.js
Normal file
6
Astral3D/packages/editor/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -1,10 +1,31 @@
|
||||
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m27.19815,87.08654l-20.82,-11.88l0,-50.24l20.82,12.33l0,49.79z" fill="#63E2B7"/>
|
||||
<path d="m25.32815,13.95654l-18.95,11.01l20.82,12.33l18.95,-10.83l-20.82,-12.51z" fill="#7FE7C4"/>
|
||||
<path d="m92.90815,50.47654l-0.11,24.39l-43.39,25.06l0.14,-24.56l43.36,-24.89z" fill="#7FE7C4"/>
|
||||
<path d="m30.47815,88.79654l18.93,11.13l0.14,-24.56l-19.02,-10.58l-0.05,24.01z" fill="#63E2B7"/>
|
||||
<path d="m28.78815,12.09654l20.65,-12.17l43.28,25.04l-20.42,12.16l-43.51,-25.03z" fill="#7FE7C4"/>
|
||||
<path d="m92.74815,46.90654l-0.03,-21.94l-20.42,12.16l0.02,21.81l20.43,-12.03z" fill="#7FE7C4"/>
|
||||
<path d="m67.16815,60.04654l-17.52,10.11l-17.52,-10.11l0,-20.24l17.52,-10.11l17.52,10.11l0,20.24z" fill="#7FE7C4"/>
|
||||
<path d="m32.14875,39.8347l17.43802,-10.33057l17.43801,10.24793l-18.26446,10.49587" fill="#63E2B7"/>
|
||||
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Outer Frame - Gallery Window -->
|
||||
<rect x="10" y="20" width="80" height="60" rx="2" fill="none" stroke="#63E2B7" stroke-width="2.5"/>
|
||||
|
||||
<!-- Inner Frame - Art Canvas -->
|
||||
<rect x="18" y="28" width="40" height="44" rx="1" fill="none" stroke="#7FE7C4" stroke-width="1.5"/>
|
||||
|
||||
<!-- Abstract Art Element - Brush Stroke -->
|
||||
<path d="M25,65 Q30,45 38,50 Q46,55 42,68" fill="#63E2B7" opacity="0.9"/>
|
||||
<circle cx="35" cy="42" r="6" fill="#7FE7C4" opacity="0.7"/>
|
||||
<circle cx="48" cy="38" r="4" fill="#63E2B7" opacity="0.5"/>
|
||||
|
||||
<!-- Cockpit Elements - Data Visualization -->
|
||||
<!-- Arc Gauge Left -->
|
||||
<path d="M68,35 A12,12 0 0,1 80,47" fill="none" stroke="#63E2B7" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<circle cx="72" cy="41" r="2" fill="#7FE7C4"/>
|
||||
|
||||
<!-- Bar Charts Right -->
|
||||
<rect x="65" y="52" width="4" height="14" rx="1" fill="#63E2B7" opacity="0.8"/>
|
||||
<rect x="71" y="46" width="4" height="20" rx="1" fill="#7FE7C4" opacity="0.9"/>
|
||||
<rect x="77" y="54" width="4" height="12" rx="1" fill="#63E2B7" opacity="0.7"/>
|
||||
|
||||
<!-- Connection Dots -->
|
||||
<circle cx="58" cy="35" r="1.5" fill="#7FE7C4"/>
|
||||
<circle cx="85" cy="55" r="1.5" fill="#63E2B7"/>
|
||||
<circle cx="60" cy="70" r="1.5" fill="#7FE7C4"/>
|
||||
|
||||
<!-- Data Flow Lines -->
|
||||
<line x1="58" y1="35" x2="65" y2="52" stroke="#63E2B7" stroke-width="0.5" opacity="0.4"/>
|
||||
<line x1="85" y1="55" x2="77" y2="54" stroke="#63E2B7" stroke-width="0.5" opacity="0.4"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 1.5 KiB |
@@ -1,65 +1,80 @@
|
||||
<script lang="ts" setup>
|
||||
import {computed} from 'vue';
|
||||
import {GlobalThemeOverrides,zhCN, dateZhCN,enUS,dateEnUS} from "naive-ui";
|
||||
import {useGlobalConfigStore} from "@/store/modules/globalConfig";
|
||||
import Index from "@/views/index.vue";
|
||||
|
||||
// 全局配置相关
|
||||
const globalConfigStore = useGlobalConfigStore();
|
||||
|
||||
const NaiveUILocale = computed(() => {
|
||||
switch(globalConfigStore.locale){
|
||||
case 'zh-CN':
|
||||
return {
|
||||
locale:zhCN,
|
||||
dateLocale:dateZhCN
|
||||
}
|
||||
case 'en-US':
|
||||
return {
|
||||
locale:enUS,
|
||||
dateLocale:dateEnUS
|
||||
}
|
||||
}
|
||||
});
|
||||
const themeOverrides = computed<GlobalThemeOverrides>(() => {
|
||||
const mainColor = globalConfigStore.mainColor as IConfig.Color;
|
||||
|
||||
return {
|
||||
common: {
|
||||
primaryColor: mainColor.hex,
|
||||
primaryColorHover: mainColor.hexHover,
|
||||
primaryColorPressed: mainColor.hexPressed,
|
||||
primaryColorSuppl: mainColor.hexSuppl,
|
||||
successColor: mainColor.hex,
|
||||
successColorHover: mainColor.hexHover,
|
||||
successColorPressed: mainColor.hexPressed,
|
||||
successColorSuppl: mainColor.hexSuppl,
|
||||
fontWeightStrong: '600'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 调整 naive-ui 的字重配置 -->
|
||||
<n-config-provider :locale="NaiveUILocale.locale" :date-locale="NaiveUILocale.dateLocale" :theme="globalConfigStore.getProviderTheme()" :theme-overrides="themeOverrides">
|
||||
<n-loading-bar-provider>
|
||||
<n-dialog-provider>
|
||||
<n-modal-provider>
|
||||
<n-notification-provider placement="bottom">
|
||||
<n-message-provider>
|
||||
<Index/>
|
||||
</n-message-provider>
|
||||
</n-notification-provider>
|
||||
</n-modal-provider>
|
||||
</n-dialog-provider>
|
||||
</n-loading-bar-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.n-config-provider {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<script lang="ts" setup>
|
||||
import {computed} from 'vue';
|
||||
import {GlobalThemeOverrides,zhCN, dateZhCN,enUS,dateEnUS} from "naive-ui";
|
||||
import {useGlobalConfigStore} from "@/store/modules/globalConfig";
|
||||
import Index from "@/views/index.vue";
|
||||
|
||||
// 全局配置相关
|
||||
const globalConfigStore = useGlobalConfigStore();
|
||||
|
||||
const NaiveUILocale = computed(() => {
|
||||
switch(globalConfigStore.locale){
|
||||
case 'zh-CN':
|
||||
return {
|
||||
locale:zhCN,
|
||||
dateLocale:dateZhCN
|
||||
}
|
||||
case 'en-US':
|
||||
return {
|
||||
locale:enUS,
|
||||
dateLocale:dateEnUS
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 使用专业浅色主题 - Sky Blue (信任蓝)
|
||||
const themeOverrides = computed<GlobalThemeOverrides>(() => {
|
||||
return {
|
||||
common: {
|
||||
// 专业浅色主题:天空蓝
|
||||
primaryColor: '#0EA5E9', // Sky Blue - 主色
|
||||
primaryColorHover: '#0284C7', // Darker Sky - 悬停
|
||||
primaryColorPressed: '#0369A1', // Even Darker - 按下
|
||||
primaryColorSuppl: '#0EA5E9',
|
||||
|
||||
// 成功色 - 保留 Emerald 体现成功状态
|
||||
successColor: '#10B981',
|
||||
successColorHover: '#059669',
|
||||
successColorPressed: '#047857',
|
||||
successColorSuppl: '#10B981',
|
||||
|
||||
// 警告色 - Amber
|
||||
warningColor: '#F59E0B',
|
||||
warningColorHover: '#D97706',
|
||||
warningColorPressed: '#B45309',
|
||||
warningColorSuppl: '#F59E0B',
|
||||
|
||||
// 字体
|
||||
fontWeightStrong: '600',
|
||||
|
||||
// 边框圆角
|
||||
borderRadius: '0.5rem',
|
||||
borderRadiusSmall: '0.375rem',
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- 调整 naive-ui 的字重配置 -->
|
||||
<n-config-provider :locale="NaiveUILocale.locale" :date-locale="NaiveUILocale.dateLocale" :theme="globalConfigStore.getProviderTheme()" :theme-overrides="themeOverrides">
|
||||
<n-loading-bar-provider>
|
||||
<n-dialog-provider>
|
||||
<n-modal-provider>
|
||||
<n-notification-provider placement="bottom">
|
||||
<n-message-provider>
|
||||
<Index/>
|
||||
</n-message-provider>
|
||||
</n-notification-provider>
|
||||
</n-modal-provider>
|
||||
</n-dialog-provider>
|
||||
</n-loading-bar-provider>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.n-config-provider {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
445
Astral3D/packages/editor/src/assets/css/globals.css
Normal file
445
Astral3D/packages/editor/src/assets/css/globals.css
Normal file
@@ -0,0 +1,445 @@
|
||||
/* ========================================
|
||||
美术馆数字驾驶舱 - Professional Light Theme
|
||||
Style: Minimalist, Animated, Light
|
||||
======================================== */
|
||||
|
||||
/* 基础颜色变量 */
|
||||
:root {
|
||||
/* 主色调 - 天空蓝 Sky Blue */
|
||||
--color-primary: #0EA5E9;
|
||||
--color-primary-hover: #0284C7;
|
||||
--color-primary-pressed: #0369A1;
|
||||
--color-primary-light: #E0F2FE;
|
||||
|
||||
/* 浅色系背景 */
|
||||
--color-bg-primary: #FFFFFF;
|
||||
--color-bg-secondary: #F8FAFC;
|
||||
--color-bg-tertiary: #F1F5F9;
|
||||
--color-bg-elevated: #FFFFFF;
|
||||
|
||||
/* 文字颜色 */
|
||||
--color-text-primary: #0F172A;
|
||||
--color-text-secondary: #475569;
|
||||
--color-text-tertiary: #94A3B8;
|
||||
--color-text-inverse: #FFFFFF;
|
||||
|
||||
/* 边框与分割线 */
|
||||
--color-border: #E2E8F0;
|
||||
--color-border-hover: #CBD5E1;
|
||||
--color-divider: #F1F5F9;
|
||||
|
||||
/* 功能色 */
|
||||
--color-success: #10B981;
|
||||
--color-warning: #F59E0B;
|
||||
--color-error: #EF4444;
|
||||
--color-info: #3B82F6;
|
||||
|
||||
/* 阴影 - 现代柔和阴影 */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -2px rgb(0 0 0 / 0.07);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.08), 0 4px 6px -4px rgb(0 0 0 / 0.05);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.05);
|
||||
|
||||
/* 圆角 - 现代大圆角 */
|
||||
--radius-sm: 0.375rem;
|
||||
--radius-md: 0.5rem;
|
||||
--radius-lg: 0.75rem;
|
||||
--radius-xl: 1rem;
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* 过渡动画 */
|
||||
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--transition-normal: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
|
||||
/* 间距 */
|
||||
--spacing-xs: 0.25rem;
|
||||
--spacing-sm: 0.5rem;
|
||||
--spacing-md: 1rem;
|
||||
--spacing-lg: 1.5rem;
|
||||
--spacing-xl: 2rem;
|
||||
|
||||
/* Z-index 层 */
|
||||
--z-dropdown: 100;
|
||||
--z-sticky: 200;
|
||||
--z-modal: 300;
|
||||
--z-popover: 400;
|
||||
--z-tooltip: 500;
|
||||
}
|
||||
|
||||
/* 暗色主题 */
|
||||
.dark {
|
||||
--color-bg-primary: #0F172A;
|
||||
--color-bg-secondary: #1E293B;
|
||||
--color-bg-tertiary: #334155;
|
||||
--color-bg-elevated: #1E293B;
|
||||
|
||||
--color-text-primary: #F8FAFC;
|
||||
--color-text-secondary: #CBD5E1;
|
||||
--color-text-tertiary: #64748B;
|
||||
--color-text-inverse: #0F172A;
|
||||
|
||||
--color-border: #334155;
|
||||
--color-border-hover: #475569;
|
||||
--color-divider: #1E293B;
|
||||
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.3), 0 2px 4px -2px rgb(0 0 0 / 0.2);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.2);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.4), 0 8px 10px -6px rgb(0 0 0 / 0.2);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
全局样式重置与现代样式
|
||||
======================================== */
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background-color: var(--color-bg-primary);
|
||||
color: var(--color-text-primary);
|
||||
transition: background-color var(--transition-normal), color var(--transition-normal);
|
||||
}
|
||||
|
||||
/* 滚动条美化 */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-border);
|
||||
border-radius: var(--radius-full);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-border-hover);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
动画关键帧
|
||||
======================================== */
|
||||
|
||||
/* 淡入动画 */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
/* 上浮动画 */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 缩放淡入 */
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 滑动动画 */
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 脉冲动画 */
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
/* 骨架屏动画 */
|
||||
@keyframes shimmer {
|
||||
0% { background-position: -200% 0; }
|
||||
100% { background-position: 200% 0; }
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
实用动画类
|
||||
======================================== */
|
||||
|
||||
/* 淡入 */
|
||||
.animate-fadeIn {
|
||||
animation: fadeIn var(--transition-normal) ease-out forwards;
|
||||
}
|
||||
|
||||
/* 上浮淡入 */
|
||||
.animate-fadeInUp {
|
||||
animation: fadeInUp var(--transition-slow) ease-out forwards;
|
||||
}
|
||||
|
||||
/* 缩放淡入 */
|
||||
.animate-scaleIn {
|
||||
animation: scaleIn var(--transition-normal) ease-out forwards;
|
||||
}
|
||||
|
||||
/* 左滑入 */
|
||||
.animate-slideInLeft {
|
||||
animation: slideInLeft var(--transition-slow) ease-out forwards;
|
||||
}
|
||||
|
||||
/* 右滑入 */
|
||||
.animate-slideInRight {
|
||||
animation: slideInRight var(--transition-slow) ease-out forwards;
|
||||
}
|
||||
|
||||
/* 脉冲 */
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
/* 骨架屏 */
|
||||
.animate-skeleton {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--color-bg-tertiary) 25%,
|
||||
var(--color-bg-secondary) 50%,
|
||||
var(--color-bg-tertiary) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
/* 悬停动画 */
|
||||
.hover-lift {
|
||||
transition: transform var(--transition-fast), box-shadow var(--transition-fast);
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
/* 悬停发光效果 */
|
||||
.hover-glow {
|
||||
transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.hover-glow:hover {
|
||||
box-shadow: 0 0 20px rgba(14, 165, 233, 0.15);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
按钮样式
|
||||
======================================== */
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-text-inverse);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--color-primary-hover);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
background-color: var(--color-primary-pressed);
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 次要按钮 */
|
||||
.btn-secondary {
|
||||
background-color: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--color-bg-tertiary);
|
||||
border-color: var(--color-border-hover);
|
||||
}
|
||||
|
||||
/* 幽灵按钮 */
|
||||
.btn-ghost {
|
||||
background-color: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn-ghost:hover {
|
||||
background-color: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
输入框样式
|
||||
======================================== */
|
||||
|
||||
.input-light {
|
||||
background-color: var(--color-bg-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
color: var(--color-text-primary);
|
||||
transition: all var(--transition-fast);
|
||||
outline: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.input-light::placeholder {
|
||||
color: var(--color-text-tertiary);
|
||||
}
|
||||
|
||||
.input-light:focus {
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.1);
|
||||
}
|
||||
|
||||
.input-light:hover:not(:focus) {
|
||||
border-color: var(--color-border-hover);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
卡片样式
|
||||
======================================== */
|
||||
|
||||
.card {
|
||||
background-color: var(--color-bg-elevated);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.card-hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--color-border-hover);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* 玻璃态卡片 */
|
||||
.card-glass {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
.dark .card-glass {
|
||||
background-color: rgba(30, 41, 59, 0.8);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
侧边栏样式
|
||||
======================================== */
|
||||
|
||||
.sidebar {
|
||||
background-color: var(--color-bg-secondary);
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.dark .sidebar {
|
||||
background-color: var(--color-bg-secondary);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
工具类
|
||||
======================================== */
|
||||
|
||||
.text-primary { color: var(--color-text-primary); }
|
||||
.text-secondary { color: var(--color-text-secondary); }
|
||||
.text-tertiary { color: var(--color-text-tertiary); }
|
||||
.text-accent { color: var(--color-primary); }
|
||||
|
||||
.bg-primary { background-color: var(--color-bg-primary); }
|
||||
.bg-secondary { background-color: var(--color-bg-secondary); }
|
||||
.bg-tertiary { background-color: var(--color-bg-tertiary); }
|
||||
|
||||
.border-default { border-color: var(--color-border); }
|
||||
|
||||
/* 焦点样式 */
|
||||
.focus-ring:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.2);
|
||||
}
|
||||
|
||||
/* 点击反馈 */
|
||||
.active-scale:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
减少动画 (无障碍)
|
||||
======================================== */
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ withDefaults(defineProps<{
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex flex-col justify-center items-center bg-#1D82B8 relative z-9999" v-if="visible">
|
||||
<div class="w-full h-full flex flex-col justify-center items-center bg-#0EA5E9 relative z-9999" v-if="visible">
|
||||
<div class="es-folding-cube bg-#fff">
|
||||
<div class="es-cube1 es-cube"></div>
|
||||
<div class="es-cube2 es-cube"></div>
|
||||
@@ -43,7 +43,7 @@ withDefaults(defineProps<{
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1D82B8;
|
||||
background-color: #0EA5E9;
|
||||
-webkit-animation: es-foldCubeAngle 2.4s infinite linear both;
|
||||
animation: es-foldCubeAngle 2.4s infinite linear both;
|
||||
-webkit-transform-origin: 100% 100%;
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import {t} from "@/language";
|
||||
import Logo from "@/components/header/Logo.vue";
|
||||
import EsPluginList from "@/components/es/plugin/EsPluginList.vue";
|
||||
|
||||
withDefaults(defineProps<{
|
||||
visible:boolean
|
||||
}>(),{
|
||||
visible:false
|
||||
})
|
||||
|
||||
const emits = defineEmits(["update:visible"]);
|
||||
|
||||
const searchText = ref("");
|
||||
|
||||
function handleClose(){
|
||||
emits("update:visible",false);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal :show="visible" @maskClick="handleClose" @esc="handleClose">
|
||||
<n-card class="es-tools-dialog fixed top-20vh w-90% max-w-800px" :bordered="false" role="dialog" aria-modal="true">
|
||||
<template #header>
|
||||
<n-input v-model:value="searchText" type="text" size="large" autofocus clearable class="font-500"
|
||||
placeholder="Hi, Astral3D Editor">
|
||||
<template #prefix>
|
||||
<Logo class="w-30px h-30px" />
|
||||
</template>
|
||||
</n-input>
|
||||
</template>
|
||||
|
||||
<n-text depth="3" class="relative bottom-10px left-5px"> {{ t("plugin['Optional plug-in']") }} </n-text>
|
||||
|
||||
<EsPluginList @close="handleClose" :search="searchText" />
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@media screen and (max-width: 800px) {
|
||||
.es-tools-dialog{
|
||||
left:5%;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 800px) {
|
||||
.es-tools-dialog{
|
||||
left:calc(50% - 400px);
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import {t} from "@/language";
|
||||
import Logo from "@/components/header/Logo.vue";
|
||||
import EsPluginList from "@/components/es/plugin/EsPluginList.vue";
|
||||
|
||||
withDefaults(defineProps<{
|
||||
visible:boolean
|
||||
}>(),{
|
||||
visible:false
|
||||
})
|
||||
|
||||
const emits = defineEmits(["update:visible"]);
|
||||
|
||||
const searchText = ref("");
|
||||
|
||||
function handleClose(){
|
||||
emits("update:visible",false);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal :show="visible" @maskClick="handleClose" @esc="handleClose">
|
||||
<n-card class="es-tools-dialog fixed top-20vh w-90% max-w-800px" :bordered="false" role="dialog" aria-modal="true">
|
||||
<template #header>
|
||||
<n-input v-model:value="searchText" type="text" size="large" autofocus clearable class="font-500"
|
||||
placeholder="Hi, 美术馆数字驾驶舱">
|
||||
<template #prefix>
|
||||
<Logo class="w-30px h-30px" />
|
||||
</template>
|
||||
</n-input>
|
||||
</template>
|
||||
|
||||
<n-text depth="3" class="relative bottom-10px left-5px"> {{ t("plugin['Optional plug-in']") }} </n-text>
|
||||
|
||||
<EsPluginList @close="handleClose" :search="searchText" />
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@media screen and (max-width: 800px) {
|
||||
.es-tools-dialog{
|
||||
left:5%;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 800px) {
|
||||
.es-tools-dialog{
|
||||
left:calc(50% - 400px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,34 @@
|
||||
<template>
|
||||
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m27.19815,87.08654l-20.82,-11.88l0,-50.24l20.82,12.33l0,49.79z" :fill="primaryColor.hex"/>
|
||||
<path d="m25.32815,13.95654l-18.95,11.01l20.82,12.33l18.95,-10.83l-20.82,-12.51z" :fill="primaryColor.hexHover"/>
|
||||
<path d="m92.90815,50.47654l-0.11,24.39l-43.39,25.06l0.14,-24.56l43.36,-24.89z" :fill="primaryColor.hexHover"/>
|
||||
<path d="m30.47815,88.79654l18.93,11.13l0.14,-24.56l-19.02,-10.58l-0.05,24.01z" :fill="primaryColor.hex"/>
|
||||
<path d="m28.78815,12.09654l20.65,-12.17l43.28,25.04l-20.42,12.16l-43.51,-25.03z" :fill="primaryColor.hexHover"/>
|
||||
<path d="m92.74815,46.90654l-0.03,-21.94l-20.42,12.16l0.02,21.81l20.43,-12.03z" :fill="primaryColor.hexHover"/>
|
||||
<path d="m67.16815,60.04654l-17.52,10.11l-17.52,-10.11l0,-20.24l17.52,-10.11l17.52,10.11l0,20.24z" :fill="primaryColor.hexHover"/>
|
||||
<path d="m32.14875,39.8347l17.43802,-10.33057l17.43801,10.24793l-18.26446,10.49587" :fill="primaryColor.hex"/>
|
||||
<!-- Outer Frame - Gallery Window -->
|
||||
<rect x="10" y="20" width="80" height="60" rx="2" fill="none" :stroke="primaryColor.hex" stroke-width="2.5"/>
|
||||
|
||||
<!-- Inner Frame - Art Canvas -->
|
||||
<rect x="18" y="28" width="40" height="44" rx="1" fill="none" :stroke="primaryColor.hexHover" stroke-width="1.5"/>
|
||||
|
||||
<!-- Abstract Art Element - Brush Stroke -->
|
||||
<path d="M25,65 Q30,45 38,50 Q46,55 42,68" :fill="primaryColor.hex" opacity="0.9"/>
|
||||
<circle cx="35" cy="42" r="6" :fill="primaryColor.hexHover" opacity="0.7"/>
|
||||
<circle cx="48" cy="38" r="4" :fill="primaryColor.hex" opacity="0.5"/>
|
||||
|
||||
<!-- Cockpit Elements - Data Visualization -->
|
||||
<!-- Arc Gauge Left -->
|
||||
<path d="M68,35 A12,12 0 0,1 80,47" fill="none" :stroke="primaryColor.hex" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<circle cx="72" cy="41" r="2" :fill="primaryColor.hexHover"/>
|
||||
|
||||
<!-- Bar Charts Right -->
|
||||
<rect x="65" y="52" width="4" height="14" rx="1" :fill="primaryColor.hex" opacity="0.8"/>
|
||||
<rect x="71" y="46" width="4" height="20" rx="1" :fill="primaryColor.hexHover" opacity="0.9"/>
|
||||
<rect x="77" y="54" width="4" height="12" rx="1" :fill="primaryColor.hex" opacity="0.7"/>
|
||||
|
||||
<!-- Connection Dots -->
|
||||
<circle cx="58" cy="35" r="1.5" :fill="primaryColor.hexHover"/>
|
||||
<circle cx="85" cy="55" r="1.5" :fill="primaryColor.hex"/>
|
||||
<circle cx="60" cy="70" r="1.5" :fill="primaryColor.hexHover"/>
|
||||
|
||||
<!-- Data Flow Lines -->
|
||||
<line x1="58" y1="35" x2="65" y2="52" :stroke="primaryColor.hex" stroke-width="0.5" opacity="0.4"/>
|
||||
<line x1="85" y1="55" x2="77" y2="54" :stroke="primaryColor.hex" stroke-width="0.5" opacity="0.4"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
|
||||
38
Astral3D/packages/editor/src/components/ui/Button/Button.vue
Normal file
38
Astral3D/packages/editor/src/components/ui/Button/Button.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'
|
||||
size?: 'default' | 'sm' | 'lg' | 'icon'
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
:class="cn(
|
||||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
'bg-primary text-primary-foreground hover:bg-primary/90': variant === 'default',
|
||||
'bg-destructive text-destructive-foreground hover:bg-destructive/90': variant === 'destructive',
|
||||
'border border-input bg-background hover:bg-accent hover:text-accent-foreground': variant === 'outline',
|
||||
'bg-secondary text-secondary-foreground hover:bg-secondary/80': variant === 'secondary',
|
||||
'hover:bg-accent hover:text-accent-foreground': variant === 'ghost',
|
||||
'text-primary underline-offset-4 hover:underline': variant === 'link',
|
||||
'h-10 px-4 py-2': size === 'default',
|
||||
'h-9 rounded-md px-3': size === 'sm',
|
||||
'h-11 rounded-md px-8': size === 'lg',
|
||||
'h-10 w-10': size === 'icon',
|
||||
},
|
||||
props.class
|
||||
)"
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
</template>
|
||||
16
Astral3D/packages/editor/src/components/ui/Card/Card.vue
Normal file
16
Astral3D/packages/editor/src/components/ui/Card/Card.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('rounded-lg border bg-card text-card-foreground shadow-sm', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col space-y-2 p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p :class="cn('text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</p>
|
||||
</template>
|
||||
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col space-y-1.5 p-6', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span :class="cn('ml-auto text-xs tracking-widest opacity-60', props.class)">
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
6
Astral3D/packages/editor/src/components/ui/Card/index.ts
Normal file
6
Astral3D/packages/editor/src/components/ui/Card/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export { default as Card } from './Card.vue'
|
||||
export { default as CardHeader } from './CardHeader.vue'
|
||||
export { default as CardDescription } from './CardDescription.vue'
|
||||
export { default as CardTitle } from './CardTitle.vue'
|
||||
export { default as CardContent } from './CardContent.vue'
|
||||
export { default as CardFooter } from './CardFooter.vue'
|
||||
29
Astral3D/packages/editor/src/components/ui/Dialog/Dialog.vue
Normal file
29
Astral3D/packages/editor/src/components/ui/Dialog/Dialog.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogRoot>
|
||||
<DialogTrigger as-child>
|
||||
<slot />
|
||||
</DialogTrigger>
|
||||
<DialogPortal>
|
||||
<DialogOverlay class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" />
|
||||
<DialogContent
|
||||
:class="cn(
|
||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||
props.class
|
||||
)"
|
||||
>
|
||||
<slot />
|
||||
</DialogContent>
|
||||
</DialogPortal>
|
||||
</DialogRoot>
|
||||
</template>
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogClose
|
||||
:class="cn(
|
||||
'absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground',
|
||||
props.class
|
||||
)"
|
||||
>
|
||||
<slot />
|
||||
</DialogClose>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogDescription :class="cn('text-sm text-muted-foreground', props.class)">
|
||||
<slot />
|
||||
</DialogDescription>
|
||||
</template>
|
||||
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col space-y-1.5 text-center sm:text-left', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogTitle :class="cn('text-lg font-semibold leading-none tracking-tight', props.class)">
|
||||
<slot />
|
||||
</DialogTitle>
|
||||
</template>
|
||||
21
Astral3D/packages/editor/src/components/ui/Input/Input.vue
Normal file
21
Astral3D/packages/editor/src/components/ui/Input/Input.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/lib/utils'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
|
||||
interface Props {
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<input
|
||||
:class="cn(
|
||||
'flex h-10 w-full rounded-md border border-input bg-white px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
props.class
|
||||
)"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<slot />
|
||||
</template>
|
||||
8
Astral3D/packages/editor/src/components/ui/index.ts
Normal file
8
Astral3D/packages/editor/src/components/ui/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export { Button } from './Button/Button.vue'
|
||||
export { Input } from './Input/Input.vue'
|
||||
export { Card } from './Card/Card.vue'
|
||||
export { CardHeader } from './Card/CardHeader.vue'
|
||||
export { CardDescription } from './Card/CardDescription.vue'
|
||||
export { CardTitle } from './Card/CardTitle.vue'
|
||||
export { CardContent } from './Card/CardContent.vue'
|
||||
export { CardFooter } from './Card/CardFooter.vue'
|
||||
@@ -16,7 +16,7 @@ export default {
|
||||
'No more': "没有更多了",
|
||||
/* 项目 */
|
||||
'My Project': "我的项目",
|
||||
'Shared Project': "共享项目",
|
||||
'Shared Project': "项目",
|
||||
'New project': "新建项目",
|
||||
"Template": "模板",
|
||||
'Empty project': "空项目",
|
||||
|
||||
6
Astral3D/packages/editor/src/lib/utils.ts
Normal file
6
Astral3D/packages/editor/src/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
@@ -1,40 +1,41 @@
|
||||
import '@/utils/common/init';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { setupStore } from '@/store';
|
||||
|
||||
import 'virtual:uno.css';
|
||||
import "animate.css/animate.min.css";
|
||||
import '@/assets/less/index.less';
|
||||
|
||||
import {setupI18n} from '@/language';
|
||||
import {setupRouter} from "@/router";
|
||||
|
||||
import DisableDevtool from 'disable-devtool';
|
||||
|
||||
async function main() {
|
||||
const app = createApp(App);
|
||||
|
||||
setupRouter(app);
|
||||
|
||||
// 配置存储
|
||||
setupStore(app);
|
||||
|
||||
// 多语言配置
|
||||
setupI18n(app);
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
if (import.meta.env.PROD){
|
||||
DisableDevtool({
|
||||
clearLog:true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
|
||||
|
||||
|
||||
import '@/utils/common/init';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { setupStore } from '@/store';
|
||||
|
||||
import 'virtual:uno.css';
|
||||
import "animate.css/animate.min.css";
|
||||
import '@/assets/less/index.less';
|
||||
import '@/assets/css/globals.css';
|
||||
|
||||
import {setupI18n} from '@/language';
|
||||
import {setupRouter} from "@/router";
|
||||
|
||||
import DisableDevtool from 'disable-devtool';
|
||||
|
||||
async function main() {
|
||||
const app = createApp(App);
|
||||
|
||||
setupRouter(app);
|
||||
|
||||
// 配置存储
|
||||
setupStore(app);
|
||||
|
||||
// 多语言配置
|
||||
setupI18n(app);
|
||||
|
||||
app.mount('#app');
|
||||
|
||||
if (import.meta.env.PROD){
|
||||
DisableDevtool({
|
||||
clearLog:true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ export const useGlobalConfigStore = defineStore('global-config', () => {
|
||||
/* 主色 */
|
||||
const mainColor = useStorage<IConfig.Color>("astral-main-color", {
|
||||
"CMYK": [56, 0, 19, 11],
|
||||
"RGB": [99, 226, 183],
|
||||
"hex": "#63E2B7",
|
||||
"hexHover": "#7FE7C4",
|
||||
"hexPressed": "#5ACEA7",
|
||||
"hexSuppl": "#2A947D",
|
||||
"name": "\u9e23\u7fe0\u67f3",
|
||||
"pinyin": "mingcuiliu"
|
||||
"RGB": [14, 165, 233],
|
||||
"hex": "#0EA5E9",
|
||||
"hexHover": "#38BDF8",
|
||||
"hexPressed": "#0284C7",
|
||||
"hexSuppl": "#0369A1",
|
||||
"name": "\u5929\u7A7A\u84DD",
|
||||
"pinyin": "tiankonglan"
|
||||
});
|
||||
const setPrimaryColor = (color: IConfig.Color) => {
|
||||
const colors = generate(color.hex);
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
import SettingCenter from "@/components/setting/common/SettingCenter.vue";
|
||||
|
||||
const version = import.meta.env.VITE_GLOB_VERSION;
|
||||
const author = import.meta.env.VITE_GLOB_AUTHOR;
|
||||
const beian = import.meta.env.VITE_GLOB_BEIAN;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="inline-block !flex items-center">
|
||||
Version {{ version }} · Made by {{ author }}
|
||||
|
|
||||
<p><a href="https://beian.miit.gov.cn/" target="_blank">{{beian}}</a></p>
|
||||
<SettingCenter />
|
||||
</div>
|
||||
|
||||
<SettingCenter />
|
||||
</template>
|
||||
|
||||
@@ -13,8 +13,8 @@ withDefaults(defineProps<{
|
||||
</div>
|
||||
|
||||
<transition enter-active-class="animate__animated animate__fadeInRight" leave-active-class="animate__animated animate__fadeOutRight">
|
||||
<n-gradient-text :size="24" type="success" class="ml-5px" v-if="!collapsed">
|
||||
Astral 3D Editor
|
||||
<n-gradient-text :size="24" type="info" class="ml-5px" v-if="!collapsed">
|
||||
数字驾驶舱
|
||||
</n-gradient-text>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import {t} from "@/language";
|
||||
import HeaderCarousel from "@/views/home/components/HeaderCarousel.vue";
|
||||
import MyProject from "@/views/home/project/MyProject.vue";
|
||||
import SharedProject from "@/views/home/project/SharedProject.vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout-header>
|
||||
<HeaderCarousel/>
|
||||
</n-layout-header>
|
||||
|
||||
<n-layout-content content-style="padding: 24px;">
|
||||
<n-tabs type="line" animated default-value="shared-project" class="h-full">
|
||||
<n-tab-pane name="my-project" :tab="t('home.My Project')" disabled>
|
||||
<MyProject />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="shared-project" :tab="t('home.Shared Project')">
|
||||
<SharedProject />
|
||||
</n-tab-pane>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import HeaderCarousel from "@/views/home/components/HeaderCarousel.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-layout-header>
|
||||
<HeaderCarousel />
|
||||
</n-layout-header>
|
||||
|
||||
<n-layout-content content-style="padding: 24px;">
|
||||
<SettingTabs/>
|
||||
</n-layout-content>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import {h, ref} from 'vue';
|
||||
import type {MenuOption} from 'naive-ui'
|
||||
import {Cube, Sprout, Settings,Notebook,LogoGithub,DataCenter,StarReview} from '@vicons/carbon';
|
||||
import {Cube, Sprout, Settings, DataCenter} from '@vicons/carbon';
|
||||
import {t} from "@/language";
|
||||
import {renderIcon} from "@/utils/common/render";
|
||||
import Setting from "@/components/setting/Setting.vue";
|
||||
import SidebarTopInfo from "./components/SidebarTopInfo.vue";
|
||||
import SidebarBottomInfo from "./components/SidebarBottomInfo.vue";
|
||||
import Project from "./container/Project.vue";
|
||||
import DataCenterComponents from "./container/DataCenter.vue";
|
||||
import AssetsCenter from "./container/AssetsCenter.vue";
|
||||
@@ -39,42 +38,6 @@ const menuOptions: MenuOption[] = [
|
||||
icon: renderIcon(Settings),
|
||||
component:SettingCenter
|
||||
},
|
||||
{
|
||||
key: 'divider-1',
|
||||
type: 'divider',
|
||||
props: {
|
||||
style: {
|
||||
margin: "20px 25px"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: () => h('a', {
|
||||
href: 'https://github.com/mlt131220/ES-3DEditor',
|
||||
target: '_blank'
|
||||
}, "GitHub"),
|
||||
key: 'github-link',
|
||||
icon: renderIcon(LogoGithub),
|
||||
isLink:true
|
||||
},
|
||||
{
|
||||
label: () => h('a', {
|
||||
href: 'http://editor-doc.astraljs.com',
|
||||
target: '_blank'
|
||||
}, t("home.Usage Document")),
|
||||
key: 'usage-document',
|
||||
icon: renderIcon(Notebook),
|
||||
isLink:true
|
||||
},
|
||||
{
|
||||
label: () => h('a', {
|
||||
href: 'https://editor-doc.astraljs.com/promotion/',
|
||||
target: '_blank'
|
||||
}, "推广中心"),
|
||||
key: 'promotion-center',
|
||||
icon: renderIcon(StarReview),
|
||||
isLink:true
|
||||
}
|
||||
]
|
||||
const containerComponent = ref(Project);
|
||||
|
||||
@@ -99,10 +62,6 @@ function handleSelectMenu(key: string, item: MenuOption){
|
||||
<n-menu :value="menuActiveKey" :options="menuOptions" :collapsed="collapsed" :collapsed-width="64"
|
||||
:collapsed-icon-size="22" @update:value="handleSelectMenu" />
|
||||
|
||||
<transition enter-active-class="animate__animated animate__fadeInLeft"
|
||||
leave-active-class="animate__animated animate__fadeOutLeft">
|
||||
<SidebarBottomInfo class="absolute bottom-20px w-full" v-if="!collapsed" />
|
||||
</transition>
|
||||
</n-layout-sider>
|
||||
|
||||
<n-layout class="h-full">
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
</style>
|
||||
@@ -1,144 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {t} from "@/language";
|
||||
import {fetchGetAllScenes} from "@/http/api/scenes";
|
||||
import CardAction from "@/views/home/project/components/CardAction.vue";
|
||||
import CreateProject from "@/views/home/project/components/CreateProject.vue";
|
||||
import {getServiceStaticFile} from "@/utils/common/file";
|
||||
|
||||
const data = ref<ISceneFetchData[]>([]);
|
||||
let paginationReactive = reactive({
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
pageCount: 1
|
||||
})
|
||||
const loadMore = ref(false);
|
||||
const noMore = ref(false);
|
||||
const showCreateModal = ref(false);
|
||||
const loadingProjectId = ref(-1);
|
||||
|
||||
async function handleLoad() {
|
||||
if(noMore.value) return;
|
||||
|
||||
loadMore.value = true;
|
||||
const res = await fetchGetAllScenes({
|
||||
offset: paginationReactive.page * paginationReactive.pageSize,
|
||||
limit: paginationReactive.pageSize,
|
||||
sortby:"updateTime",
|
||||
order:"desc",
|
||||
query:``
|
||||
});
|
||||
if(res.data === null) return;
|
||||
|
||||
data.value.push(...(res.data.items || []));
|
||||
paginationReactive.pageCount = res.data.pages;
|
||||
paginationReactive.page++;
|
||||
loadMore.value = false;
|
||||
|
||||
if(paginationReactive.page >= paginationReactive.pageCount) noMore.value = true;
|
||||
}
|
||||
|
||||
async function refresh(){
|
||||
data.value = [];
|
||||
|
||||
loadMore.value = true;
|
||||
const res = await fetchGetAllScenes({
|
||||
offset: 0,
|
||||
limit: paginationReactive.page * paginationReactive.pageSize,
|
||||
sortby:"updateTime",
|
||||
order:"desc",
|
||||
query:``
|
||||
});
|
||||
if(res.data === null) return;
|
||||
|
||||
data.value.push(...(res.data.items || []));
|
||||
paginationReactive.pageCount = res.data.pages;
|
||||
loadMore.value = false;
|
||||
|
||||
if(paginationReactive.page >= paginationReactive.pageCount) noMore.value = true;
|
||||
}
|
||||
|
||||
function setLoadingProjectId(id:number){
|
||||
loadingProjectId.value = id;
|
||||
}
|
||||
|
||||
// 编辑场景
|
||||
function editScene(id:string){
|
||||
window.open(window.location.origin + "/#/editor/" + id, "_blank");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleLoad();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-infinite-scroll class="project-cards-list py-2 pr-4" :distance="10" @load="handleLoad">
|
||||
<n-card embedded hoverable :bordered="false" content-class="!p-2" class="cursor-pointer" @click="showCreateModal = true">
|
||||
<div class="new-container h-full min-h-200px flex flex-col justify-center items-center b-1 b-dashed b-rd-1">
|
||||
<span class="text-16 color-#fff">🫵</span>
|
||||
<p>{{ t('home.New project') }}</p>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card hoverable v-for="project in data" :key="project.id" >
|
||||
<template #cover>
|
||||
<n-skeleton v-if="loadingProjectId === Number(project.id)" height="100%" width="100%" />
|
||||
<template v-else>
|
||||
<div class="absolute top-10px right-10px z-10">
|
||||
<n-tag type="success" :bordered="false" >
|
||||
{{ project.projectType === 0 ? "Web3D" : "WebGIS" }}
|
||||
</n-tag>
|
||||
<n-tag type="success" :bordered="false" class="ml-5px">
|
||||
{{ project.sceneType }}
|
||||
</n-tag>
|
||||
</div>
|
||||
|
||||
<n-image preview-disabled object-fit="cover"
|
||||
:src="getServiceStaticFile(project.coverPicture) || '/static/images/carousel/Astral3DEditor.jpg'"
|
||||
class="w-full h-220px cursor-pointer hover:transform-scale-140 transition-all-200" @click="editScene(project.id)"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template #action>
|
||||
<n-skeleton v-if="loadingProjectId === Number(project.id)" text :repeat="1" />
|
||||
<CardAction v-show="loadingProjectId !== Number(project.id)" :data="project" @refresh="refresh" @setLoadingProjectId="setLoadingProjectId" />
|
||||
</template>
|
||||
</n-card>
|
||||
|
||||
<div v-if="loadMore" class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.Loading') }}...
|
||||
</div>
|
||||
<div v-else-if="!noMore" class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.Scroll to load more') }} 😽😽😽
|
||||
</div>
|
||||
<div v-else class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.No more') }} 🤪
|
||||
</div>
|
||||
</n-infinite-scroll>
|
||||
|
||||
<CreateProject v-model:visible="showCreateModal" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.project-cards-list {
|
||||
height: calc(100% - var(--n-pane-padding-top));
|
||||
|
||||
.n-scrollbar-content{
|
||||
display: grid;
|
||||
grid-gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
grid-auto-flow: row dense;
|
||||
|
||||
.new-container{
|
||||
border-color: var(--n-border-color);
|
||||
color:var(--n-close-icon-color)
|
||||
}
|
||||
|
||||
.n-card-cover{
|
||||
height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {t} from "@/language";
|
||||
import {fetchGetAllScenes} from "@/http/api/scenes";
|
||||
import CardAction from "@/views/home/project/components/CardAction.vue";
|
||||
import CreateProject from "@/views/home/project/components/CreateProject.vue";
|
||||
import {getServiceStaticFile} from "@/utils/common/file";
|
||||
import {Add} from '@vicons/carbon';
|
||||
|
||||
const data = ref<ISceneFetchData[]>([]);
|
||||
let paginationReactive = reactive({
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
pageCount: 1
|
||||
})
|
||||
const loadMore = ref(false);
|
||||
const noMore = ref(false);
|
||||
const showCreateModal = ref(false);
|
||||
const loadingProjectId = ref(-1);
|
||||
|
||||
async function handleLoad() {
|
||||
if(noMore.value) return;
|
||||
|
||||
loadMore.value = true;
|
||||
const res = await fetchGetAllScenes({
|
||||
offset: paginationReactive.page * paginationReactive.pageSize,
|
||||
limit: paginationReactive.pageSize,
|
||||
sortby:"updateTime",
|
||||
order:"desc",
|
||||
query:``
|
||||
});
|
||||
if(res.data === null) return;
|
||||
|
||||
data.value.push(...(res.data.items || []));
|
||||
paginationReactive.pageCount = res.data.pages;
|
||||
paginationReactive.page++;
|
||||
loadMore.value = false;
|
||||
|
||||
if(paginationReactive.page >= paginationReactive.pageCount) noMore.value = true;
|
||||
}
|
||||
|
||||
async function refresh(){
|
||||
data.value = [];
|
||||
|
||||
loadMore.value = true;
|
||||
const res = await fetchGetAllScenes({
|
||||
offset: 0,
|
||||
limit: paginationReactive.page * paginationReactive.pageSize,
|
||||
sortby:"updateTime",
|
||||
order:"desc",
|
||||
query:``
|
||||
});
|
||||
if(res.data === null) return;
|
||||
|
||||
data.value.push(...(res.data.items || []));
|
||||
paginationReactive.pageCount = res.data.pages;
|
||||
loadMore.value = false;
|
||||
|
||||
if(paginationReactive.page >= paginationReactive.pageCount) noMore.value = true;
|
||||
}
|
||||
|
||||
function setLoadingProjectId(id:number){
|
||||
loadingProjectId.value = id;
|
||||
}
|
||||
|
||||
// 编辑场景
|
||||
function editScene(id:string){
|
||||
window.open(window.location.origin + "/#/editor/" + id, "_blank");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleLoad();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-infinite-scroll class="project-cards-list py-2 pr-4" :distance="10" @load="handleLoad">
|
||||
<n-card embedded hoverable :bordered="false" content-class="!p-2" class="cursor-pointer" @click="showCreateModal = true">
|
||||
<div class="new-container h-full min-h-200px flex flex-col justify-center items-center b-1 b-dashed b-rd-1">
|
||||
<n-icon size="48" class="mb-10px">
|
||||
<Add />
|
||||
</n-icon>
|
||||
<p>{{ t('home.New project') }}</p>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card hoverable v-for="project in data" :key="project.id" >
|
||||
<template #cover>
|
||||
<n-skeleton v-if="loadingProjectId === Number(project.id)" height="100%" width="100%" />
|
||||
<template v-else>
|
||||
<div class="absolute top-10px right-10px z-10">
|
||||
<n-tag type="success" :bordered="false" >
|
||||
{{ project.projectType === 0 ? "Web3D" : "WebGIS" }}
|
||||
</n-tag>
|
||||
<n-tag type="success" :bordered="false" class="ml-5px">
|
||||
{{ project.sceneType }}
|
||||
</n-tag>
|
||||
</div>
|
||||
|
||||
<n-image preview-disabled object-fit="cover"
|
||||
:src="getServiceStaticFile(project.coverPicture) || '/static/images/carousel/Astral3DEditor.jpg'"
|
||||
class="w-full h-220px cursor-pointer hover:transform-scale-140 transition-all-200" @click="editScene(project.id)"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template #action>
|
||||
<n-skeleton v-if="loadingProjectId === Number(project.id)" text :repeat="1" />
|
||||
<CardAction v-show="loadingProjectId !== Number(project.id)" :data="project" @refresh="refresh" @setLoadingProjectId="setLoadingProjectId" />
|
||||
</template>
|
||||
</n-card>
|
||||
|
||||
<div v-if="loadMore" class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.Loading') }}...
|
||||
</div>
|
||||
<div v-else-if="!noMore" class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.Scroll to load more') }} 😽😽😽
|
||||
</div>
|
||||
<div v-else class="text-center" style="grid-column: 1 / -1;">
|
||||
{{ t('home.No more') }} 🤪
|
||||
</div>
|
||||
</n-infinite-scroll>
|
||||
|
||||
<CreateProject v-model:visible="showCreateModal" @refresh="refresh" />
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.project-cards-list {
|
||||
height: calc(100% - var(--n-pane-padding-top));
|
||||
|
||||
.n-scrollbar-content{
|
||||
display: grid;
|
||||
grid-gap: 1rem;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
grid-auto-flow: row dense;
|
||||
|
||||
.new-container{
|
||||
border-color: var(--n-border-color);
|
||||
color:var(--n-close-icon-color)
|
||||
}
|
||||
|
||||
.n-card-cover{
|
||||
height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
48
Astral3D/packages/editor/tailwind.config.ts
Normal file
48
Astral3D/packages/editor/tailwind.config.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export default {
|
||||
darkMode: 'class',
|
||||
content: [
|
||||
'./index.html',
|
||||
'./src/**/*.{vue,js,ts,jsx,tsx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
DEFAULT: 'var(--color-primary)',
|
||||
hover: 'var(--color-primary-hover)',
|
||||
pressed: 'var(--color-primary-pressed)',
|
||||
},
|
||||
background: 'var(--background)',
|
||||
foreground: 'var(--foreground)',
|
||||
surface: 'var(--sidebar-background)',
|
||||
card: {
|
||||
DEFAULT: 'var(--card)',
|
||||
foreground: 'var(--card-foreground)',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'var(--muted)',
|
||||
foreground: 'var(--muted-foreground)',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'var(--accent)',
|
||||
foreground: 'var(--accent-foreground)',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'var(--destructive)',
|
||||
foreground: 'var(--destructive-foreground)',
|
||||
},
|
||||
border: 'var(--border)',
|
||||
input: 'var(--input)',
|
||||
ring: 'var(--ring)',
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
} satisfies Config
|
||||
@@ -1,20 +1,26 @@
|
||||
import { defineConfig, presetAttributify, presetUno, presetIcons } from 'unocss'
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
presetUno(),
|
||||
presetAttributify(),
|
||||
presetIcons()
|
||||
],
|
||||
rules: [
|
||||
['no-wrap', { 'white-space': 'nowrap' }],
|
||||
[/^h-calc-\[?(.*?)\]?$/, ([, size]) => ({ height: `calc(100% - ${size})` })],
|
||||
[/^max-h-calc-\[?(.*?)\]?$/, ([, size]) => ({ 'max-height': `calc(100% - ${size})` })],
|
||||
[/^w-calc-\[?(.*?)\]?$/, ([, size]) => ({ width: `calc(100% - ${size})` })],
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
'flex-center': 'flex items-center justify-center',
|
||||
},
|
||||
]
|
||||
})
|
||||
import { defineConfig, presetUno, presetIcons } from 'unocss'
|
||||
|
||||
export default defineConfig({
|
||||
presets: [
|
||||
// 保留 UnoCSS 以支持项目中的工具类
|
||||
// 注意:UnoCSS 会生成与 Tailwind 相似的工具类,但项目已依赖 UnoCSS
|
||||
presetUno(),
|
||||
presetIcons({
|
||||
scale: 1.2,
|
||||
cdn: 'https://esm.sh/'
|
||||
})
|
||||
],
|
||||
rules: [
|
||||
['no-wrap', { 'white-space': 'nowrap' }],
|
||||
[/^h-calc-\[?(.*?)\]?$/, ([, size]) => ({ height: `calc(100% - ${size})` })],
|
||||
[/^max-h-calc-\[?(.*?)\]?$/, ([, size]) => ({ 'max-height': `calc(100% - ${size})` })],
|
||||
[/^w-calc-\[?(.*?)\]?$/, ([, size]) => ({ width: `calc(100% - ${size})` })],
|
||||
],
|
||||
shortcuts: [
|
||||
{
|
||||
'flex-center': 'flex items-center justify-center',
|
||||
},
|
||||
],
|
||||
// 允许与 Tailwind 共存
|
||||
mergeSelectors: true,
|
||||
})
|
||||
|
||||
@@ -1,203 +1,203 @@
|
||||
import {defineConfig, loadEnv} from 'vite';
|
||||
import path from 'path';
|
||||
import dotenv from "dotenv";
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import Unocss from 'unocss/vite';
|
||||
// import cesium from 'vite-plugin-cesium';
|
||||
import mkcert from 'vite-plugin-mkcert';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||
// 用于生成渐进式 Web 应用
|
||||
// import { VitePWA } from 'vite-plugin-pwa';
|
||||
// 自动按需引入Naive UI组件
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
|
||||
import {wrapperEnv, createPlugins} from "@astral3d/build-vite-plugins";
|
||||
|
||||
export default defineConfig(async ({mode, command}) => {
|
||||
const root = process.cwd();
|
||||
const env = loadEnv(mode, root);
|
||||
//LoadEnv读取的布尔类型是一个字符串。此函数可以转换为布尔类型
|
||||
const viteEnv = wrapperEnv(env);
|
||||
const {
|
||||
VITE_PORT,
|
||||
VITE_PUBLIC_PATH,
|
||||
VITE_BUILD_COMPRESS,
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||
VITE_ENABLE_ANALYZE,
|
||||
VITE_ENABLE_CONFIG_GENERATE
|
||||
} = viteEnv;
|
||||
|
||||
const isBuild = command === 'build';
|
||||
const plugins = await createPlugins({
|
||||
isBuild,
|
||||
root,
|
||||
compress: {
|
||||
compress: VITE_BUILD_COMPRESS,
|
||||
deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||
},
|
||||
enableAnalyze: VITE_ENABLE_ANALYZE,
|
||||
enableConfig:VITE_ENABLE_CONFIG_GENERATE
|
||||
});
|
||||
|
||||
// 为@monaco-editor定义define
|
||||
const define:any = {
|
||||
"process.env": process.env
|
||||
};
|
||||
if (mode === "development") {
|
||||
dotenv.config({ path: ".env.development" });
|
||||
define.global = {};
|
||||
} else if (mode === "production") {
|
||||
dotenv.config({ path: ".env.production" });
|
||||
}
|
||||
|
||||
return {
|
||||
define: define,
|
||||
base: VITE_PUBLIC_PATH,
|
||||
build: {
|
||||
outDir: "dist",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
// 生产环境移除console
|
||||
drop_console: false,
|
||||
},
|
||||
},
|
||||
sourcemap: false,
|
||||
// 启用 CSS 代码拆分
|
||||
cssCodeSplit: true,
|
||||
// 禁用 gzip 压缩大小报告。压缩大型输出文件可能会很慢,因此禁用该功能可能会提高大型项目的构建性能。
|
||||
reportCompressedSize: false,
|
||||
// 规定触发警告的 chunk 大小。(以 kbs 为单位)
|
||||
chunkSizeWarningLimit: 1024 * 6,
|
||||
// 自定义底层的 Rollup 打包配置
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vue: ['vue', 'vue-router', 'pinia'],
|
||||
i18n: ['vue-i18n'],
|
||||
ui: ['naive-ui'],
|
||||
astral3d: ['@astral3d/engine']
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
root,
|
||||
plugins:[
|
||||
vue(),
|
||||
Unocss(),
|
||||
// cesium(),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()]
|
||||
}),
|
||||
// 本地开发https证书(mkcert 需要网络下载,代理不通时会失败,可注释掉用 http)
|
||||
// mkcert(),
|
||||
// VitePWA({
|
||||
// registerType: 'autoUpdate',
|
||||
// // dev环境下是否开启
|
||||
// devOptions: {
|
||||
// enabled: false,
|
||||
// },
|
||||
// // 注册ws方式
|
||||
// injectRegister: 'auto',
|
||||
// workbox: {
|
||||
// // sw 预缓存的资源类型
|
||||
// globPatterns: ['**/*.{js}'],
|
||||
// // Error: Configure "workbox.maximumFileSizeToCacheInBytes" to change the limit: the default value is 2 MiB.
|
||||
// // 添加此项配置,增加需要缓存的最大文件大小,默认2MB
|
||||
// maximumFileSizeToCacheInBytes: 20 * 1024 * 1024
|
||||
// },
|
||||
// manifest: {
|
||||
// name: 'Astral 3D Editor',
|
||||
// short_name: 'Astral 3D',
|
||||
// description: '一款基于THREE.JS开发的专业的三维可视化编辑器',
|
||||
// theme_color: '#63E2B7',
|
||||
// icons: [
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-48x48.png',
|
||||
// sizes: '48x48',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-64x64.png',
|
||||
// sizes: '64x64',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-96x96.png',
|
||||
// sizes: '96x96',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-192x192.png',
|
||||
// sizes: '192x192',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-256x256.png',
|
||||
// sizes: '256x256',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// purpose: 'any',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// purpose: 'maskable',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{ src: 'node_modules/@astral3d/engine/dist/libs/*', dest: 'assets/libs' }
|
||||
],
|
||||
}),
|
||||
...plugins
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': path.resolve(__dirname, './types'),
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['keyframe-resample','draco3dgltf'],
|
||||
},
|
||||
server: {
|
||||
host: true,
|
||||
port: VITE_PORT,
|
||||
//设置 server.hmr.overlay 为 false 可以禁用开发服务器错误的屏蔽
|
||||
// hmr: { overlay: false },
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
},
|
||||
cors: {
|
||||
origin: "*",
|
||||
credentials: true
|
||||
},
|
||||
proxy: {
|
||||
'^/api': {
|
||||
target: env.VITE_PROXY_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^/api`), '/api')
|
||||
},
|
||||
"^/file/static": {
|
||||
target: env.VITE_PROXY_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^/file/static`), '/api/common/static')
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
import {defineConfig, loadEnv} from 'vite';
|
||||
import path from 'path';
|
||||
import dotenv from "dotenv";
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import Unocss from 'unocss/vite';
|
||||
// import cesium from 'vite-plugin-cesium';
|
||||
import mkcert from 'vite-plugin-mkcert';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy';
|
||||
// 用于生成渐进式 Web 应用
|
||||
// import { VitePWA } from 'vite-plugin-pwa';
|
||||
// 自动按需引入Naive UI组件
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
|
||||
import {wrapperEnv, createPlugins} from "@astral3d/build-vite-plugins";
|
||||
|
||||
export default defineConfig(async ({mode, command}) => {
|
||||
const root = process.cwd();
|
||||
const env = loadEnv(mode, root);
|
||||
//LoadEnv读取的布尔类型是一个字符串。此函数可以转换为布尔类型
|
||||
const viteEnv = wrapperEnv(env);
|
||||
const {
|
||||
VITE_PORT,
|
||||
VITE_PUBLIC_PATH,
|
||||
VITE_BUILD_COMPRESS,
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||
VITE_ENABLE_ANALYZE,
|
||||
VITE_ENABLE_CONFIG_GENERATE
|
||||
} = viteEnv;
|
||||
|
||||
const isBuild = command === 'build';
|
||||
const plugins = await createPlugins({
|
||||
isBuild,
|
||||
root,
|
||||
compress: {
|
||||
compress: VITE_BUILD_COMPRESS,
|
||||
deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||
},
|
||||
enableAnalyze: VITE_ENABLE_ANALYZE,
|
||||
enableConfig:VITE_ENABLE_CONFIG_GENERATE
|
||||
});
|
||||
|
||||
// 为@monaco-editor定义define
|
||||
const define:any = {
|
||||
"process.env": process.env
|
||||
};
|
||||
if (mode === "development") {
|
||||
dotenv.config({ path: ".env.development" });
|
||||
define.global = {};
|
||||
} else if (mode === "production") {
|
||||
dotenv.config({ path: ".env.production" });
|
||||
}
|
||||
|
||||
return {
|
||||
define: define,
|
||||
base: VITE_PUBLIC_PATH,
|
||||
build: {
|
||||
outDir: "dist",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
// 生产环境移除console
|
||||
drop_console: false,
|
||||
},
|
||||
},
|
||||
sourcemap: false,
|
||||
// 启用 CSS 代码拆分
|
||||
cssCodeSplit: true,
|
||||
// 禁用 gzip 压缩大小报告。压缩大型输出文件可能会很慢,因此禁用该功能可能会提高大型项目的构建性能。
|
||||
reportCompressedSize: false,
|
||||
// 规定触发警告的 chunk 大小。(以 kbs 为单位)
|
||||
chunkSizeWarningLimit: 1024 * 6,
|
||||
// 自定义底层的 Rollup 打包配置
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vue: ['vue', 'vue-router', 'pinia'],
|
||||
i18n: ['vue-i18n'],
|
||||
ui: ['naive-ui'],
|
||||
astral3d: ['@astral3d/engine']
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
root,
|
||||
plugins:[
|
||||
vue(),
|
||||
Unocss(),
|
||||
// cesium(),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()]
|
||||
}),
|
||||
// 本地开发https证书(mkcert 需要网络下载,代理不通时会失败,可注释掉用 http)
|
||||
// mkcert(),
|
||||
// VitePWA({
|
||||
// registerType: 'autoUpdate',
|
||||
// // dev环境下是否开启
|
||||
// devOptions: {
|
||||
// enabled: false,
|
||||
// },
|
||||
// // 注册ws方式
|
||||
// injectRegister: 'auto',
|
||||
// workbox: {
|
||||
// // sw 预缓存的资源类型
|
||||
// globPatterns: ['**/*.{js}'],
|
||||
// // Error: Configure "workbox.maximumFileSizeToCacheInBytes" to change the limit: the default value is 2 MiB.
|
||||
// // 添加此项配置,增加需要缓存的最大文件大小,默认2MB
|
||||
// maximumFileSizeToCacheInBytes: 20 * 1024 * 1024
|
||||
// },
|
||||
// manifest: {
|
||||
// name: 'Astral 3D Editor',
|
||||
// short_name: 'Astral 3D',
|
||||
// description: '一款基于THREE.JS开发的专业的三维可视化编辑器',
|
||||
// theme_color: '#63E2B7',
|
||||
// icons: [
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-48x48.png',
|
||||
// sizes: '48x48',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-64x64.png',
|
||||
// sizes: '64x64',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-96x96.png',
|
||||
// sizes: '96x96',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-192x192.png',
|
||||
// sizes: '192x192',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-256x256.png',
|
||||
// sizes: '256x256',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// purpose: 'any',
|
||||
// },
|
||||
// {
|
||||
// src: '/static/images/logo/pwa/pwa-512x512.png',
|
||||
// sizes: '512x512',
|
||||
// type: 'image/png',
|
||||
// purpose: 'maskable',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// }),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{ src: 'node_modules/@astral3d/engine/dist/libs/*', dest: 'assets/libs' }
|
||||
],
|
||||
}),
|
||||
...plugins
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': path.resolve(__dirname, './types'),
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['keyframe-resample','draco3dgltf'],
|
||||
},
|
||||
server: {
|
||||
host: true,
|
||||
port: VITE_PORT,
|
||||
//设置 server.hmr.overlay 为 false 可以禁用开发服务器错误的屏蔽
|
||||
// hmr: { overlay: false },
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
},
|
||||
cors: {
|
||||
origin: "*",
|
||||
credentials: true
|
||||
},
|
||||
proxy: {
|
||||
'^/api': {
|
||||
target: env.VITE_PROXY_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^/api`), '/api')
|
||||
},
|
||||
"^/file/static": {
|
||||
target: env.VITE_PROXY_URL,
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(new RegExp(`^/file/static`), '/api/common/static')
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
902
Astral3D/pnpm-lock.yaml
generated
902
Astral3D/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,7 @@ public class Astral3DScenesController {
|
||||
public Result<?> post(@RequestBody Astral3DScenes lb3dEditorScenes) {
|
||||
long count = astral3DScenesService.count();
|
||||
if (count > 2000) {
|
||||
return Result.error("共享项目场景数量已达上限(2000个),不允许新增");
|
||||
return Result.error("项目场景数量已达上限(2000个),不允许新增");
|
||||
}
|
||||
if (astral3DScenesService.save(lb3dEditorScenes)) {
|
||||
return Result.success(lb3dEditorScenes);
|
||||
|
||||
329
docs/css-migration-spec.md
Normal file
329
docs/css-migration-spec.md
Normal file
@@ -0,0 +1,329 @@
|
||||
# Astral3D UI 样式迁移规范 (CSS & Vue Style Guide)
|
||||
|
||||
> **项目**: Astral3D Web 3D 编辑器
|
||||
> **迁移目标**: NaiveUI → Shadcn UI + Tailwind CSS
|
||||
> **风格**: 现代简约 / Minimalist Modern
|
||||
> **版本**: 1.0
|
||||
|
||||
---
|
||||
|
||||
## 1. 主题与色彩系统 (Theme & Colors)
|
||||
|
||||
### 1.1 色彩变量 (CSS Variables)
|
||||
我们将在 Tailwind 的默认调色板基础上,定义与当前 NaiveUI 浅色主题兼容的 CSS 变量。
|
||||
|
||||
**建议配置 (`tailwind.config.ts` & `globals.css`)**:
|
||||
|
||||
| 用途 | Tailwind 映射 | 变量名 | 当前值 (NaiveUI Light) | 说明 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **主色 (Primary)** | `primary` | `--color-primary` | `#63E2B7` (Mint Green) | 品牌色,用于按钮、选中态 |
|
||||
| **主色悬停** | `primary-hover` | `--color-primary-hover` | `#7FE7C4` | 鼠标悬停 |
|
||||
| **主色按下** | `primary-pressed` | `--color-primary-pressed` | `#5ACEA7` | 鼠标按下 |
|
||||
| **背景 (Background)** | `background` | `--background` | `#ffffff` (White) | 页面主背景 |
|
||||
| **侧边栏背景** | `sidebar-bg` | `--sidebar-background` | `#f8fafc` (Slate 50) | 侧边栏容器 |
|
||||
| **卡片/面板背景** | `card-bg` | `--card-background` | `#ffffff` (White) | 表单、卡片背景 |
|
||||
| **边框 (Border)** | `border` | `--border` | `#e2e8f0` (Slate 200) | 分割线、输入框边框 |
|
||||
| **文字主色** | `foreground` | `--foreground` | `#0f172a` (Slate 900) | 标题、主要文字 |
|
||||
| **文字次要** | `muted-foreground` | `--muted-foreground` | `#64748b` (Slate 500) | 标签、占位符 |
|
||||
|
||||
### 1.2 暗色模式适配 (Dark Mode)
|
||||
我们将默认配置为浅色,支持通过 class 切换到深色:
|
||||
|
||||
```typescript
|
||||
// tailwind.config.ts
|
||||
export default {
|
||||
darkMode: 'class', // 允许通过添加 'dark' class 切换主题
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
DEFAULT: 'var(--color-primary)',
|
||||
hover: 'var(--color-primary-hover)',
|
||||
pressed: 'var(--color-primary-pressed)',
|
||||
},
|
||||
background: 'var(--background)',
|
||||
surface: 'var(--sidebar-background)',
|
||||
border: 'var(--border)',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 间距与排版 (Spacing & Typography)
|
||||
|
||||
### 2.1 间距系统 (Spacing)
|
||||
迁移 `n-space` 和 NaiveUI 的 padding/margin 逻辑。
|
||||
|
||||
| NaiveUI Size | Tailwind Class | 用途 |
|
||||
| :--- | :--- | :--- |
|
||||
| `size="small"` | `gap-2` (8px) | 紧凑列表、工具栏 |
|
||||
| `size="medium"` (默认) | `gap-3` (12px) | 通用表单、卡片 |
|
||||
| `size="large"` | `gap-4` (16px) | 模块间距、大间距 |
|
||||
| `n-layout-sider` padding | `p-3` (12px) | 侧边栏内容 padding |
|
||||
| `n-card` padding | `p-4` (16px) | 卡片内边距 |
|
||||
|
||||
### 2.2 圆角系统 (Border Radius)
|
||||
|
||||
| NaiveUI | Tailwind Class | 说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `bordered` (默认) | `rounded-md` (6px) | 按钮、输入框 |
|
||||
| `round` | `rounded-full` | 标签、头像 |
|
||||
| - | `rounded-lg` (8px) | 模态框、卡片 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 组件映射速查 (Component Mapping)
|
||||
|
||||
### 3.1 基础组件 (Basic Components)
|
||||
|
||||
#### Button 按钮
|
||||
- **NaiveUI**: `<n-button type="primary">Save</n-button>`
|
||||
- **Shadcn/Vue + Tailwind**:
|
||||
```vue
|
||||
<Button variant="default">Save</Button>
|
||||
```
|
||||
- **属性映射**:
|
||||
- `type="primary"` -> `variant="default"` (Primary Color Background)
|
||||
- `type="default"` -> `variant="outline"`
|
||||
- `type="tertiary"` -> `variant="ghost"`
|
||||
- `size="small"` -> `size="sm"`
|
||||
- `ghost=true` -> `variant="ghost"`
|
||||
|
||||
#### Input 输入框
|
||||
- **NaiveUI**: `<n-input v-model:value="text" placeholder="Enter..." />`
|
||||
- **Shadcn/Vue + Tailwind**:
|
||||
```vue
|
||||
<Input v-model="text" placeholder="Enter..." />
|
||||
```
|
||||
- **样式调整**:
|
||||
- 当前项目输入框通常为白色背景,需覆盖 `shadcn` 默认样式:
|
||||
```css
|
||||
.Input {
|
||||
@apply bg-white border-slate-300 text-slate-900 focus:ring-primary;
|
||||
}
|
||||
```
|
||||
|
||||
#### Select 选择器
|
||||
- **NaiveUI**: `<n-select v-model:value="val" :options="options" />`
|
||||
- **Shadcn**: 使用 `Select` 组件或自定义封装。
|
||||
- **Tailwind 实现 (自定义封装示例)**:
|
||||
```vue
|
||||
<div class="relative">
|
||||
<select v-model="val" class="appearance-none bg-white border border-slate-300 rounded-md px-3 py-2 text-sm w-full text-slate-900">
|
||||
<option v-for="opt in options" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
|
||||
</select>
|
||||
<!-- 自定义箭头图标 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 布局组件 (Layout Components)
|
||||
|
||||
#### Tabs 标签页 (侧边栏)
|
||||
- **NaiveUI**: `<n-tabs placement="left">` (侧边栏常规模式)
|
||||
- **Shadcn 实现**: Shadcn 默认 Tabs 是水平顶部排列。
|
||||
- **Tailwind 实现 (自定义侧边栏 Tabs)**:
|
||||
需要使用 Flexbox 布局模拟侧边栏 Tab。
|
||||
```vue
|
||||
<div class="flex h-full w-full">
|
||||
<!-- 竖向 Tab 列表 -->
|
||||
<div class="flex flex-col border-r border-slate-200 w-12 items-center py-2 gap-2 bg-slate-50">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.name"
|
||||
:class="['p-2 rounded', activeTab === tab.name ? 'bg-primary/10 text-primary' : 'text-slate-500 hover:bg-slate-100']"
|
||||
@click="activeTab = tab.name"
|
||||
>
|
||||
<component :is="tab.icon" class="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
<!-- Tab 内容区 -->
|
||||
<div class="flex-1 p-4 overflow-y-auto">
|
||||
<component :is="activeComponent" />
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Layout 布局容器
|
||||
- **NaiveUI**:
|
||||
```vue
|
||||
<n-layout has-sider>
|
||||
<n-layout-sider>...</n-layout-sider>
|
||||
<n-layout-content>...</n-layout-content>
|
||||
</n-layout>
|
||||
```
|
||||
- **Tailwind 实现**:
|
||||
```vue
|
||||
<div class="flex h-screen bg-background text-foreground">
|
||||
<aside class="w-64 border-r border-border bg-sidebar p-3 overflow-y-auto">
|
||||
<!-- 侧边栏内容 -->
|
||||
</aside>
|
||||
<main class="flex-1 overflow-hidden relative">
|
||||
<!-- 主内容区 -->
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### Card 卡片
|
||||
- **NaiveUI**: `<n-card title="Title" size="small">Content</n-card>`
|
||||
- **Shadcn 实现**:
|
||||
```vue
|
||||
<Card class="w-full bg-white border-slate-200">
|
||||
<CardHeader>
|
||||
<CardTitle>Title</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
Content
|
||||
</CardContent>
|
||||
</Card>
|
||||
```
|
||||
|
||||
#### Collapse 折叠面板
|
||||
- **NaiveUI**:
|
||||
```vue
|
||||
<n-collapse>
|
||||
<n-collapse-item title="Group" name="1">Content</n-collapse-item>
|
||||
</n-collapse>
|
||||
```
|
||||
- **Tailwind 实现**:
|
||||
```vue
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="1">
|
||||
<AccordionTrigger>Group</AccordionTrigger>
|
||||
<AccordionContent>Content</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 反馈组件 (Feedback Components)
|
||||
|
||||
#### Modal 对话框
|
||||
- **NaiveUI**: `<n-modal v-model:show="show" preset="card" title="Title" />`
|
||||
- **Shadcn 实现**:
|
||||
```vue
|
||||
<Dialog v-model:open="show">
|
||||
<DialogContent class="sm:max-w-[425px] bg-white border-slate-200">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Title</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<!-- actions -->
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
#### Message 消息提示
|
||||
- **NaiveUI**: `window.$message.success('Success')`
|
||||
- **迁移方案**: 使用 `sonner` 或自定义 Toast 组件。
|
||||
- **Tailwind 样式 (浅色)**:
|
||||
```css
|
||||
.toast-success {
|
||||
@apply bg-white border-l-4 border-primary text-slate-900 shadow-lg;
|
||||
}
|
||||
```
|
||||
|
||||
#### Loading 加载
|
||||
- **NaiveUI**: `<n-spin />` 或 `v-loading`
|
||||
- **Tailwind 实现**:
|
||||
```vue
|
||||
<div class="flex items-center justify-center">
|
||||
<Loader2 class="h-8 w-8 animate-spin text-primary" />
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 样式覆盖规范 (Style Overrides)
|
||||
|
||||
为了保持项目当前的视觉风格(浅色为主),需要在全局 CSS 中添加以下覆盖:
|
||||
|
||||
```css
|
||||
/* src/assets/globals.css */
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
/* 浅色模式 (默认) */
|
||||
--background: 255 255 255; /* White */
|
||||
--foreground: 15 23 42; /* Slate 900 */
|
||||
|
||||
--card: 255 255 255;
|
||||
--card-foreground: 15 23 42;
|
||||
|
||||
--primary: 99 226 183; /* Mint Green #63E2B7 */
|
||||
--primary-foreground: 15 23 42;
|
||||
|
||||
--secondary: 241 245 249; /* Slate 100 */
|
||||
--secondary-foreground: 15 23 42;
|
||||
|
||||
--muted: 241 245 249; /* Slate 100 */
|
||||
--muted-foreground: 100 116 139; /* Slate 500 */
|
||||
|
||||
--accent: 241 245 249;
|
||||
--accent-foreground: 15 23 42;
|
||||
|
||||
--destructive: 239 68 68; /* Red 500 */
|
||||
--destructive-foreground: 255 255 255;
|
||||
|
||||
--border: 226 232 240; /* Slate 200 */
|
||||
--input: 226 232 240;
|
||||
--ring: 99 226 183;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* 暗色模式 (可选) */
|
||||
.dark {
|
||||
--background: 15 23 42; /* Slate 950 */
|
||||
--foreground: 248 250 252; /* Slate 50 */
|
||||
|
||||
--card: 30 41 59; /* Slate 800 */
|
||||
--card-foreground: 248 250 252;
|
||||
|
||||
--secondary: 51 65 85; /* Slate 700 */
|
||||
--secondary-foreground: 248 250 252;
|
||||
|
||||
--muted: 51 65 85;
|
||||
--muted-foreground: 148 163 184;
|
||||
|
||||
--accent: 51 65 85;
|
||||
--accent-foreground: 248 250 252;
|
||||
|
||||
--destructive: 239 68 68;
|
||||
--destructive-foreground: 248 250 252;
|
||||
|
||||
--border: 51 65 85;
|
||||
--input: 51 65 85;
|
||||
}
|
||||
}
|
||||
|
||||
/* 自定义组件样式适配当前项目 (浅色) */
|
||||
.btn-primary {
|
||||
@apply bg-primary text-slate-900 hover:bg-primary/90;
|
||||
}
|
||||
|
||||
.input-light {
|
||||
@apply bg-white border-slate-200 text-slate-900 focus:ring-primary rounded-md;
|
||||
}
|
||||
|
||||
/* 侧边栏样式适配 */
|
||||
.sidebar {
|
||||
@apply bg-slate-50 border-r border-slate-200;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 迁移步骤建议
|
||||
|
||||
1. **安装依赖**: 运行 TODO 文档中的安装命令。
|
||||
2. **配置 Tailwind**: 创建 `tailwind.config.ts` 并配置颜色。
|
||||
3. **全局样式**: 创建 `globals.css` 并填入上方 CSS 变量。
|
||||
4. **组件替换**: 按照 "组件映射速查" 表格,逐页面替换 `naive-ui` 组件。
|
||||
5. **样式微调**: 针对特定的 NaiveUI 样式类(如 `.n-form-item`),使用 `@apply` 或 Tailwind 工具类进行覆盖。
|
||||
26
docs/digital-atelier-philosophy.md
Normal file
26
docs/digital-atelier-philosophy.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Design Philosophy: "Digital Atelier"
|
||||
|
||||
## Philosophy Name
|
||||
**Digital Atelier** — The marriage of classical gallery aesthetics with digital precision.
|
||||
|
||||
## Visual Expression
|
||||
|
||||
### Form and Space
|
||||
The logo draws from the architectural language of galleries—clean lines, intentional negative space, and frames that create depth. The composition suggests a portal or viewing window, evoking the experience of entering a sacred art space. Geometric forms reference cockpit instrumentation—subtle dials, data points, and interface elements—seamlessly integrated into the visual structure.
|
||||
|
||||
### Color and Material
|
||||
A restrained palette anchored in deep charcoal and warm ivory, with a single accent color—deep teal—that suggests both vintage museum label text and digital interface highlights. The contrast creates hierarchy without aggression. Colors should feel timeless, like aged paper against polished brass.
|
||||
|
||||
### Scale and Rhythm
|
||||
Proportions follow classical composition rules (golden ratio relationships), while the internal elements pulse with digital life. Typography is architectural—tall, narrow letterforms that suggest both museum signage and futuristic readouts.
|
||||
|
||||
### Composition and Balance
|
||||
Asymmetric equilibrium creates tension and interest. The eye moves through a deliberate path—from the frame to the core symbol to the text. Every element relates to others through proportion and spacing, creating a cohesive whole that feels inevitable.
|
||||
|
||||
### Visual Hierarchy
|
||||
The central mark commands attention, with supporting elements receding. Text serves as foundation, the mark hovers as experience, and negative space connects them. The result is a logo that works at multiple scales—from favicon to billboard.
|
||||
|
||||
---
|
||||
|
||||
## Subtle Conceptual Thread
|
||||
The logo subtly references the Japanese concept of "Ma" (間)—the negative space between things that gives them meaning. The cockpit elements are abstracted enough to suggest depth and complexity without overwhelming the elegant gallery essence. It's a mark that promises: *here, art meets intelligence.*
|
||||
92
docs/ui-migration-todo.md
Normal file
92
docs/ui-migration-todo.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Astral3D UI Migration TODO - NaiveUI to Shadcn UI + Tailwind CSS
|
||||
|
||||
> **Project**: Astral3D Web 3D Editor
|
||||
> **Goal**: Migrate from NaiveUI to Shadcn UI + Tailwind CSS
|
||||
> **Style**: Minimalist Modern
|
||||
> **Created**: 2026-03-12
|
||||
|
||||
---
|
||||
|
||||
## Progress Overview
|
||||
|
||||
| Phase | Status | Progress | Est. Time |
|
||||
|-------|--------|----------|-----------|
|
||||
| **Phase 1: Environment Setup** | Done | 100% | 2-4 hours |
|
||||
| **Phase 2: Basic Components** | In Progress | ~30% | 6-8 hours |
|
||||
| **Phase 3: Layout Components** | Pending | 0% | 4-6 hours |
|
||||
| **Phase 4: Feedback Components** | Pending | 0% | 4-6 hours |
|
||||
| **Phase 5: Data Components** | Pending | 0% | 4-6 hours |
|
||||
| **Phase 6: Verification** | Pending | 0% | 4-8 hours |
|
||||
| **Phase 7: Optimization** | Pending | 0% | 2-4 hours |
|
||||
|
||||
**Overall Progress: ~15%**
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Environment Setup (Complete)
|
||||
|
||||
### 1.1 Dependencies
|
||||
|
||||
- [x] Tailwind CSS v4 installed
|
||||
- [x] @tailwindcss/postcss installed
|
||||
- [x] Shadcn Vue dependencies (radix-vue, class-variance-authority, clsx, tailwind-merge)
|
||||
- [x] Dark mode support (@vueuse/core)
|
||||
|
||||
### 1.2 Configuration Files
|
||||
|
||||
- [x] `tailwind.config.ts` created
|
||||
- [x] `postcss.config.js` updated (using @tailwindcss/postcss)
|
||||
- [x] `src/lib/utils.ts` (cn() utility function)
|
||||
- [x] `src/assets/css/globals.css` with Tailwind v4 syntax and CSS variables
|
||||
|
||||
### 1.3 Theme Design System
|
||||
|
||||
- [x] Color system defined (matching NaiveUI theme)
|
||||
- [x] Spacing system
|
||||
- [x] Border radius system
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Basic Components Migration (In Progress)
|
||||
|
||||
### 2.1 Button
|
||||
- [x] Component: `Button` created
|
||||
- [x] Location: `src/components/ui/Button/Button.vue`
|
||||
|
||||
### 2.2 Input
|
||||
- [x] Component: `Input` created
|
||||
- [x] Location: `src/components/ui/Input/Input.vue`
|
||||
|
||||
### 2.3 Card
|
||||
- [x] Components: Card, CardHeader, CardDescription, CardTitle, CardContent, CardFooter
|
||||
- [x] Location: `src/components/ui/Card/`
|
||||
|
||||
### 2.4 Dialog
|
||||
- [x] Components: Dialog, DialogHeader, DialogTitle, DialogDescription, DialogClose
|
||||
- [x] Location: `src/components/ui/Dialog/`
|
||||
|
||||
### 2.5 Select
|
||||
- [ ] Pending implementation
|
||||
|
||||
### 2.6 Checkbox / Radio
|
||||
- [ ] Pending implementation
|
||||
|
||||
### 2.7 Switch
|
||||
- [ ] Pending implementation
|
||||
|
||||
---
|
||||
|
||||
## Completed Components
|
||||
|
||||
```typescript
|
||||
// Available from: src/components/ui/index.ts
|
||||
import { Button, Input, Card, CardHeader, CardDescription, CardTitle, CardContent, CardFooter } from '@/components/ui'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Status
|
||||
|
||||
- Project builds successfully with Vite
|
||||
- Tailwind CSS v4 configured correctly
|
||||
- PostCSS with @tailwindcss/postcss plugin working
|
||||
333
docs/二开改造方案.md
Normal file
333
docs/二开改造方案.md
Normal file
@@ -0,0 +1,333 @@
|
||||
# Astral3D 二次开发视觉改造方案
|
||||
|
||||
> 目标:将Astral3D编辑器视觉风格与原项目显著区分,建立独立品牌识别
|
||||
> 时间:2026-03-13
|
||||
> 作者:AI Assistant
|
||||
|
||||
## 一、需要修改的品牌元素清单
|
||||
|
||||
### 1. 核心Logo文件
|
||||
|
||||
| 文件路径 | 描述 | 优先级 |
|
||||
|---------|------|--------|
|
||||
| `/public/static/images/logo/logo.svg` | 主logo(SVG格式)| ⭐⭐⭐ |
|
||||
| `/public/static/images/logo/logo.png` | 主logo(PNG格式)| ⭐⭐⭐ |
|
||||
| `/public/static/images/logo/logo256x256.ico` | 网站favicon | ⭐⭐⭐ |
|
||||
| `/public/static/images/logo/pwa/pwa-*.png` | PWA各尺寸图标(16x16至1024x1024)| ⭐⭐⭐ |
|
||||
|
||||
**建议**:使用AI设计工具(如Canva、Midjourney、DALL-E)生成全新logo,风格建议:
|
||||
- 科技感几何图形
|
||||
- 3D立体效果
|
||||
- 与元宇宙/数字孪生相关的视觉符号
|
||||
- 避免与原Astral品牌配色(绿色#63E2B7)相似
|
||||
|
||||
### 2. 品牌名称与文字标识
|
||||
|
||||
| 位置 | 当前内容 | 修改建议 |
|
||||
|------|---------|---------|
|
||||
| `index.html` title | "Astral 3D Editor - 高效的三维可视化编辑工具" | 改为新品牌名如 "NeonVision 3D - 新一代数字孪生编辑器" |
|
||||
| `index.html` meta keywords | 包含"Astral"关键词 | 替换为新品牌关键词 |
|
||||
| `index.html` meta description | 原描述 | 重写描述,突出新品牌定位 |
|
||||
| `src/views/home/components/SidebarTopInfo.vue` | "Astral 3D Editor" | 改为新品牌名 |
|
||||
|
||||
### 3. 主题配色系统
|
||||
|
||||
> ⚠️ **重要更新 (2026-03-13)**:根据甲方需求,否定深色方案。确定采用**专业浅色 (Professional Light)** 风格,参考 Apple/SaaS 设计趋势,清爽高效。
|
||||
|
||||
#### 当前状态
|
||||
当前代码中实际配置的主色调为 Emerald Green (`#10B981`)。原项目曾使用 Mint Green (`#63E2B7`)。
|
||||
|
||||
#### 目标配色方案:专业浅色系 (Professional Clean)
|
||||
|
||||
本方案采用 **Trust Blue (信任蓝)** 作为主色,辅以 **Emerald (翠绿)** 体现成功状态,整体保持浅色背景,确保长时间使用的舒适度。
|
||||
|
||||
**需要修改的文件:**
|
||||
- `src/App.vue` - Naive UI 主题覆盖配置
|
||||
- `index.html` - `<meta name="theme-color" ... />`
|
||||
|
||||
**配色参数表:**
|
||||
|
||||
| 角色 | 颜色代码 | 名称 | 用途 |
|
||||
|:-----|:---------|:-----|:-----|
|
||||
| **主色 (Primary)** | `#0EA5E9` | **Sky Blue** | 核心按钮、侧边栏选中态、品牌标识 |
|
||||
| **辅助色 (Secondary)** | `#38BDF8` | **Light Sky** | 悬停状态、次级选中态 |
|
||||
| **强调色 (Accent)** | `#F59E0B` | **Amber** | 警告、新功能提示、关键CTA |
|
||||
| **成功色 (Success)** | `#10B981` | **Emerald** | 确认操作、运行状态(保留现有配置)|
|
||||
| **背景色 (Background)** | `#F8FAFC` | **Slate 50** | 主背景(微灰,不刺眼) |
|
||||
| **面板色 (Surface)** | `#FFFFFF` | **White** | 侧边栏、属性面板、卡片 |
|
||||
| **文字色 (Text)** | `#1E293B` | **Slate 800** | 主要文字(深灰,比纯黑柔和) |
|
||||
| **边框色 (Border)** | `#E2E8F0` | **Slate 200** | 分割线、输入框边框 |
|
||||
|
||||
### 4. UI组件样式
|
||||
|
||||
> ⚡ 详细内容已整合至 **步骤4:配置主题色**。主要通过修改 `src/App.vue` 中的 Naive UI 主题配置 `themeOverrides` 来实现。
|
||||
|
||||
#### UnoCSS/Tailwind 配置(如有定制)
|
||||
位置:`uno.config.ts`, `tailwind.config.ts`
|
||||
|
||||
如有UnoCSS或Tailwind配置,需同步更新对应的颜色别名(如 `primary`, `secondary`)以匹配上述Hex值。
|
||||
|
||||
### 5. 版权与作者信息
|
||||
|
||||
| 位置 | 当前内容 | 建议修改 |
|
||||
|------|---------|---------|
|
||||
| `index.html` | `author="ErSan,mlt131220@163.com"` | 改为新公司/团队信息 |
|
||||
| `index.html` | `copyright="ErSan,mlt131220@163.com"` | 改为新版权声明 |
|
||||
| `README.md` | 原作者信息 | 保留原项目致谢,添加二开说明 |
|
||||
|
||||
### 6. SEO相关标识
|
||||
```html
|
||||
<!-- 删除或替换以下SEO验证代码 -->
|
||||
<meta name="baidu-site-verification" content="codeva-AVKCbnEhHf" />
|
||||
<meta name="msvalidate.01" content="51C05441E591099C88B3C1975F9B9D73" />
|
||||
<meta name="google-site-verification" content="_hU0qCzBII0F3mupE17AaGpLznXbpQ89WGNaxrhVqfE" />
|
||||
```
|
||||
|
||||
## 二、具体修改步骤
|
||||
|
||||
### 步骤1:准备新Logo素材
|
||||
|
||||
1. 设计新logo(建议512x512以上)
|
||||
2. 导出以下格式:
|
||||
- SVG(矢量,用于web显示)
|
||||
- PNG(多种尺寸:32, 64, 128, 256, 512, 1024)
|
||||
- ICO(256x256,用于favicon)
|
||||
3. 按原目录结构替换文件
|
||||
|
||||
### 步骤2:修改品牌和元信息
|
||||
|
||||
编辑 `/packages/editor/index.html`:
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<!-- Logo -->
|
||||
<link rel="icon" sizes="any" type="image/svg+xml" href="/static/images/logo/logo.svg"/>
|
||||
<link rel="mask-icon" href="/static/images/logo/logo.svg" color="#新主色" />
|
||||
<link rel="apple-touch-icon" href="/static/images/logo/pwa/pwa-180x180.png" sizes="180x180" />
|
||||
|
||||
<!-- 主题色 -->
|
||||
<meta name="theme-color" content="#新主色" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta name="author" content="你的公司/团队名">
|
||||
<meta name="copyright" content="你的公司/团队名">
|
||||
<meta name="keywords" content="新关键词,数字孪生,3D编辑器,threejs,...">
|
||||
<meta name="description" content="新品牌描述">
|
||||
|
||||
<!-- 删除原SEO验证代码,添加自己的 -->
|
||||
|
||||
<title>新品牌名 - 新的Slogan</title>
|
||||
</head>
|
||||
```
|
||||
|
||||
### 步骤3:修改侧边栏品牌显示
|
||||
|
||||
编辑 `src/views/home/components/SidebarTopInfo.vue`:
|
||||
```vue
|
||||
<template>
|
||||
<div class="pt-24px w-full flex justify-center items-center">
|
||||
<div class="min-w-40px">
|
||||
<Logo />
|
||||
</div>
|
||||
<transition enter-active-class="animate__animated animate__fadeInRight"
|
||||
leave-active-class="animate__animated animate__fadeOutRight">
|
||||
<n-gradient-text :size="24" type="success" class="ml-5px" v-if="!collapsed">
|
||||
新品牌名 <!-- 替换这里 -->
|
||||
</n-gradient-text>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 步骤4:配置主题色(核心修改)
|
||||
|
||||
#### 方式A:修改Naive UI主题(推荐)
|
||||
|
||||
在 `src/App.vue` 的 `themeOverrides` 对象中更新 `common` 配置:
|
||||
|
||||
```typescript
|
||||
// src/App.vue
|
||||
const themeOverrides = computed<GlobalThemeOverrides>(() => {
|
||||
return {
|
||||
common: {
|
||||
// 专业浅色主题:天空蓝
|
||||
primaryColor: '#0EA5E9', // Sky Blue
|
||||
primaryColorHover: '#0284C7', // Darker Sky
|
||||
primaryColorPressed: '#0369A1',// Even Darker
|
||||
primaryColorSuppl: '#0EA5E9',
|
||||
|
||||
// 成功色
|
||||
successColor: '#10B981',
|
||||
|
||||
// 警告色
|
||||
warningColor: '#F59E0B',
|
||||
|
||||
// 边框圆角
|
||||
borderRadius: '0.5rem',
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
#### 方式B:使用CSS变量覆盖
|
||||
|
||||
在 `src/assets/css/globals.css` 或 `src/App.vue` 全局样式中添加:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-color: #0EA5E9;
|
||||
--primary-color-hover: #0284C7;
|
||||
--primary-color-pressed: #0369A1;
|
||||
|
||||
--background-color: #F8FAFC;
|
||||
--surface-color: #FFFFFF;
|
||||
--text-color: #1E293B;
|
||||
--border-color: #E2E8F0;
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ 注意:确保 `src/store/modules/globalConfig.ts` 中的默认主题设置为 `lightTheme` 或 `osTheme`(浅色模式),否则深色主题配置会覆盖此处设置。
|
||||
|
||||
### 步骤5:修改加载界面
|
||||
|
||||
查找加载动画/欢迎页组件:
|
||||
```bash
|
||||
grep -r "loading\|splash\|welcome" src --include="*.vue" -l
|
||||
```
|
||||
|
||||
常见的加载组件位置:
|
||||
- `src/App.vue`
|
||||
- `src/components/Loading/` 或类似目录
|
||||
- `src/views/` 下的首页
|
||||
|
||||
如有自定义加载画面,更新其中的logo和品牌名。
|
||||
|
||||
### 步骤6:更新关于页面
|
||||
|
||||
查找关于页面/版权信息:
|
||||
```bash
|
||||
grep -r "关于\|about\|copyright\|版本" src --include="*.vue" -i -l
|
||||
```
|
||||
|
||||
编辑相关文件,更新:
|
||||
- 版本号
|
||||
- 版权信息
|
||||
- 技术支持联系方式
|
||||
|
||||
## 三、进阶视觉改造建议
|
||||
|
||||
### 1. 更换字体
|
||||
|
||||
在 `index.html` 引入新字体:
|
||||
```html
|
||||
<link href="https://fonts.googleapis.com/css2?family=你的字体&display=swap" rel="stylesheet">
|
||||
```
|
||||
|
||||
在样式中应用:
|
||||
```css
|
||||
body {
|
||||
font-family: '你的字体', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
推荐科技字体:
|
||||
- 英文字体:**JetBrains Mono** (编辑器核心), **Poppins** (标题), **Inter** (正文)
|
||||
- 中文字体:思源黑体、钉钉进步体
|
||||
|
||||
### 2. 更换背景图
|
||||
|
||||
```bash
|
||||
# 查看现有背景图
|
||||
find public -name "*bg*" -o -name "*background*" -o -name "*banner*"
|
||||
```
|
||||
|
||||
替换首页/编辑器的背景图片。
|
||||
|
||||
### 3. 自定义加载动画
|
||||
|
||||
创建新的加载组件,替换原有的loading spinner。
|
||||
|
||||
### 4. 修改预设模板和示例
|
||||
|
||||
```bash
|
||||
# 查找预设内容
|
||||
grep -r "Astral\|示例\|Demo" src --include="*.vue" --include="*.ts" -l
|
||||
```
|
||||
|
||||
## 四、代码执行示例
|
||||
|
||||
### 一键查找品牌关键词
|
||||
```bash
|
||||
cd /opt/Big-Screen/Astral3D-Projects/Astral3D/packages/editor
|
||||
|
||||
# 查找包含"Astral"的所有文件
|
||||
grep -r "Astral" src public --include="*.vue" --include="*.ts" --include="*.html" --include="*.json" -l
|
||||
|
||||
# 查找包含作者邮箱的文件
|
||||
grep -r "mlt131220" src public --include="*.vue" --include="*.ts" --include="*.html" -l
|
||||
|
||||
# 查找包含原版权信息的文件
|
||||
grep -r "ErSan\|星孪数字" src public --include="*.vue" --include="*.ts" --include="*.html" -l
|
||||
```
|
||||
|
||||
### 批量替换(谨慎使用)
|
||||
```bash
|
||||
# 备份原文件
|
||||
cp -r src src.backup
|
||||
|
||||
# 使用sed替换(建议先手动确认)
|
||||
# sed -i 's/Astral 3D Editor/新品牌名/g' src/views/home/components/SidebarTopInfo.vue
|
||||
```
|
||||
|
||||
## 五、验证清单
|
||||
|
||||
修改完成后,检查以下位置是否正确显示:
|
||||
|
||||
- [ ] 浏览器标签页图标(favicon)
|
||||
- [ ] 浏览器标签页标题
|
||||
- [ ] PWA安装图标
|
||||
- [ ] 侧边栏顶部logo和名称
|
||||
- [ ] 登录页面(如有)品牌标识
|
||||
- [ ] 关于页面版权信息
|
||||
- [ ] 右键菜单/上下文菜单品牌名
|
||||
- [ ] 导出文件的默认命名
|
||||
- [ ] 错误页面的品牌展示
|
||||
|
||||
## 六、注意事项
|
||||
|
||||
1. **版权合规**:保留原项目的LICENSE和版权声明,添加NOTICE文件说明二次开发
|
||||
|
||||
2. **技术栈保持**:不要修改技术栈(Vue3 + Three.js + NaiveUI),只改视觉层
|
||||
|
||||
3. **渐进式修改**:建议分阶段修改,每改完一部分进行测试
|
||||
|
||||
4. **版本控制**:
|
||||
```bash
|
||||
git checkout -b feature/rebrand
|
||||
git add .
|
||||
git commit -m "rebrand: 更新品牌标识和视觉风格"
|
||||
```
|
||||
|
||||
5. **测试构建**:
|
||||
```bash
|
||||
pnpm run editor:build
|
||||
# 检查dist目录中的资源是否正确
|
||||
```
|
||||
|
||||
## 七、推荐工具
|
||||
|
||||
| 用途 | 工具推荐 |
|
||||
|-----|---------|
|
||||
| Logo设计 | Canva、Figma、Midjourney、Stable Diffusion |
|
||||
| 配色方案 | Coolors.co、ColorHunt、Adobe Color |
|
||||
| 图标生成 | Favicon.io、realfavicongenerator.net |
|
||||
| 字体资源 | Google Fonts、字由、阿里巴巴普惠体 |
|
||||
| 图片压缩 | TinyPNG、Squoosh |
|
||||
|
||||
---
|
||||
|
||||
**修改难度评估**:⭐⭐(简单)
|
||||
**预计耗时**:2-4小时(不含设计时间)
|
||||
**风险等级**:低(纯视觉层修改,不影响核心功能)
|
||||
Reference in New Issue
Block a user