Browse Source

'初版UI'

main
hflllll 2 weeks ago
commit
ebed72e5e5
30 changed files with 3741 additions and 0 deletions
  1. +24
    -0
      .gitignore
  2. +3
    -0
      .vscode/extensions.json
  3. +65
    -0
      README.md
  4. +20
    -0
      index.html
  5. +2016
    -0
      package-lock.json
  6. +26
    -0
      package.json
  7. BIN
      public/MOSEVideo.mp4
  8. BIN
      public/images.png
  9. +1
    -0
      public/vite.svg
  10. +43
    -0
      src/App.vue
  11. +1
    -0
      src/assets/vue.svg
  12. +41
    -0
      src/components/HelloWorld.vue
  13. +102
    -0
      src/components/layout/Footer.vue
  14. +171
    -0
      src/components/layout/NavBar.vue
  15. +34
    -0
      src/i18n/index.ts
  16. +55
    -0
      src/i18n/locales/en.json
  17. +55
    -0
      src/i18n/locales/ja.json
  18. +55
    -0
      src/i18n/locales/zh.json
  19. +12
    -0
      src/main.ts
  20. +34
    -0
      src/router/index.ts
  21. +213
    -0
      src/style.css
  22. +183
    -0
      src/views/About.vue
  23. +396
    -0
      src/views/Ecosystem.vue
  24. +90
    -0
      src/views/Home.vue
  25. +27
    -0
      src/views/NotFound.vue
  26. +1
    -0
      src/vite-env.d.ts
  27. +20
    -0
      tsconfig.app.json
  28. +7
    -0
      tsconfig.json
  29. +26
    -0
      tsconfig.node.json
  30. +20
    -0
      vite.config.ts

+ 24
- 0
.gitignore View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

+ 3
- 0
.vscode/extensions.json View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

+ 65
- 0
README.md View File

@ -0,0 +1,65 @@
# MOSE Web
MOSE Web 是一个基于 Vue 3 和 Tailwind CSS v4 的多语言区块链项目网站。
## 特点
- 使用 Vue 3 和 TypeScript 构建
- 使用 Tailwind CSS v4 进行样式设计
- 支持多语言(中文、英文、日语)
- 响应式设计,适配桌面、平板和移动端
- 模块化组件结构
## 页面
- 首页:展示项目概览和核心特点
- 生态系统:展示项目生态系统中的应用和合作伙伴
- 关于我们:介绍项目团队和发展历程
- 404页面:自定义错误页面
## 技术栈
- Vue 3:前端框架
- Vue Router:路由管理
- Vue I18n:国际化
- Tailwind CSS v4:CSS 框架
- Vite:构建工具
## 开发
```bash
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 构建生产版本
npm run build
# 预览生产版本
npm run preview
```
## 项目结构
```
MOSE Web/
├── public/ # 静态资源
├── src/
│ ├── assets/ # 项目资源文件
│ ├── components/ # 组件
│ │ └── layout/ # 布局组件
│ ├── i18n/ # 国际化
│ │ └── locales/ # 语言文件
│ ├── router/ # 路由
│ ├── views/ # 页面
│ ├── App.vue # 根组件
│ ├── main.ts # 入口文件
│ └── style.css # 全局样式
├── index.html # HTML 模板
├── package.json # 项目配置
├── tailwind.config.js # Tailwind 配置
├── tsconfig.json # TypeScript 配置
└── vite.config.ts # Vite 配置
```

+ 20
- 0
index.html View File

@ -0,0 +1,20 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link href="/src/style.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="MOSE Blockchain - Next-generation blockchain platform for high performance, security, and scalability" />
<meta name="keywords" content="blockchain, crypto, MOSE, DeFi, NFT, DAO" />
<title>MOSE Blockchain</title>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Montserrat:wght@500;600;700;800&display=swap" rel="stylesheet">
</head>
<body class="bg-background">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

+ 2016
- 0
package-lock.json
File diff suppressed because it is too large
View File


+ 26
- 0
package.json View File

@ -0,0 +1,26 @@
{
"name": "mose-web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.11",
"tailwindcss": "^4.1.11",
"vue": "^3.5.13",
"vue-i18n": "^11.1.9",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@types/node": "^24.0.13",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"typescript": "~5.7.2",
"vite": "^6.1.0",
"vue-tsc": "^2.2.0"
}
}

BIN
public/MOSEVideo.mp4 View File


BIN
public/images.png View File

Before After
Width: 225  |  Height: 225  |  Size: 4.7 KiB

+ 1
- 0
public/vite.svg View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

+ 43
- 0
src/App.vue View File

@ -0,0 +1,43 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import NavBar from '@/components/layout/NavBar.vue';
import Footer from '@/components/layout/Footer.vue';
const { locale } = useI18n();
//
const changeLanguage = (lang: string) => {
locale.value = lang;
localStorage.setItem('language', lang);
};
</script>
<template>
<div class="min-h-screen flex flex-col bg-background text-text">
<NavBar @change-language="changeLanguage" />
<main class="flex-grow">
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</main>
<Footer />
</div>
</template>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

+ 1
- 0
src/assets/vue.svg View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 41
- 0
src/components/HelloWorld.vue View File

@ -0,0 +1,41 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

+ 102
- 0
src/components/layout/Footer.vue View File

@ -0,0 +1,102 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
const socialLinks = [
{ name: 'Twitter', icon: 'twitter', url: 'https://twitter.com/mose' },
{ name: 'Discord', icon: 'discord', url: 'https://discord.gg/mose' },
{ name: 'Telegram', icon: 'telegram', url: 'https://t.me/mose' },
{ name: 'GitHub', icon: 'github', url: 'https://github.com/mose' },
];
//
const currentYear = new Date().getFullYear();
</script>
<template>
<footer class="bg-background-dark text-text-secondary py-12 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<!-- Footer Top Section -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12">
<!-- Logo & Description -->
<div>
<div class="flex items-center mb-4">
<img src="/public/vite.svg" alt="MOSE Logo" class="h-8 w-auto mr-2" />
<span class="text-xl font-bold text-primary-light">MOSE</span>
</div>
<p class="text-sm mb-6">
MOSE is a next-generation blockchain platform designed for high performance, security, and scalability.
</p>
<!-- Social Links -->
<div class="flex space-x-4">
<a
v-for="link in socialLinks"
:key="link.name"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
class="text-text-secondary hover:text-primary-light transition-colors duration-200"
>
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24">
<!-- Simplified SVG icons for demo purposes -->
<path v-if="link.icon === 'twitter'" d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path>
<path v-if="link.icon === 'discord'" d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"></path>
<path v-if="link.icon === 'telegram'" d="M24 12c0 6.627-5.373 12-12 12S0 18.627 0 12 5.373 0 12 0s12 5.373 12 12zm-6.465-3.192c-.379-.12-1.68-.523-3.037-.763a9.45 9.45 0 0 0-.398-.053c-.813-.095-1.49.597-1.001 1.319.26.437.54.873.547 1.519a20.32 20.32 0 0 1-.172 2.313c-.19.256-.385.186-.53.074a22.813 22.813 0 0 1-1.287-1.048c-.145-.127-.349-.21-.571-.264-.782-.188-1.296.276-1.001.913.026.061.074.138.148.256a9.98 9.98 0 0 0 1.579 1.911c.947.933 2.422 2.153 3.134 2.612.932.593 2.16.638 2.504.695.485.067 1.284-.117 1.478-.491.112-.214.183-.492.22-.797.073-.594.128-1.344.107-2.116a2.24 2.24 0 0 0-.169-.868c-.098-.231-.382-.454-.753-.563z"></path>
<path v-if="link.icon === 'github'" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"></path>
</svg>
</a>
</div>
</div>
<!-- Quick Links -->
<div>
<h3 class="text-lg font-medium text-text mb-4">{{ t('nav.ecosystem') }}</h3>
<ul class="space-y-2">
<li><router-link to="/ecosystem/defi" class="hover:text-primary-light transition-colors duration-200">DeFi</router-link></li>
<li><router-link to="/ecosystem/nft" class="hover:text-primary-light transition-colors duration-200">NFT</router-link></li>
<li><router-link to="/ecosystem/dao" class="hover:text-primary-light transition-colors duration-200">DAO</router-link></li>
<li><router-link to="/ecosystem/gaming" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.categories.gaming') }}</router-link></li>
</ul>
</div>
<!-- Resources -->
<div>
<h3 class="text-lg font-medium text-text mb-4">{{ t('nav.resources') }}</h3>
<ul class="space-y-2">
<li><router-link to="/resources/docs" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.docs') }}</router-link></li>
<li><router-link to="/resources/github" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.github') }}</router-link></li>
<li><router-link to="/resources/grants" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.grants') }}</router-link></li>
<li><router-link to="/resources/community" class="hover:text-primary-light transition-colors duration-200">{{ t('ecosystem.resources.community') }}</router-link></li>
</ul>
</div>
<!-- Contact -->
<div>
<h3 class="text-lg font-medium text-text mb-4">{{ t('nav.contact') }}</h3>
<ul class="space-y-2">
<li><a href="mailto:info@mose.io" class="hover:text-primary-light transition-colors duration-200">info@mose.io</a></li>
<li><a href="mailto:support@mose.io" class="hover:text-primary-light transition-colors duration-200">support@mose.io</a></li>
<li><router-link to="/contact" class="hover:text-primary-light transition-colors duration-200">{{ t('nav.contact') }}</router-link></li>
</ul>
</div>
</div>
<!-- Footer Bottom -->
<div class="pt-8 border-t border-background-light flex flex-col md:flex-row justify-between items-center">
<p class="text-sm mb-4 md:mb-0">
&copy; {{ currentYear }} MOSE. {{ t('footer.rights') }}.
</p>
<div class="flex space-x-6 text-sm">
<router-link to="/privacy" class="hover:text-primary-light transition-colors duration-200">
{{ t('footer.privacy') }}
</router-link>
<router-link to="/terms" class="hover:text-primary-light transition-colors duration-200">
{{ t('footer.terms') }}
</router-link>
</div>
</div>
</div>
</footer>
</template>

+ 171
- 0
src/components/layout/NavBar.vue View File

@ -0,0 +1,171 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
const { t, locale } = useI18n();
const router = useRouter();
const isMenuOpen = ref(false);
//
const toggleMenu = () => {
isMenuOpen.value = !isMenuOpen.value;
};
//
const changeLanguage = (lang: string) => {
emit('changeLanguage', lang);
};
//
const languages = [
{ code: 'en', name: 'English' },
{ code: 'zh', name: '中文' },
{ code: 'ja', name: '日本語' }
];
//
const currentLanguage = computed(() => {
return languages.find(lang => lang.code === locale.value)?.name || 'English';
});
//
const navItems = [
{ name: t('nav.home'), path: '/' },
{ name: t('nav.ecosystem'), path: '/ecosystem' },
{ name: t('nav.about'), path: '/about' },
{ name: t('nav.resources'), path: '/resources' },
{ name: t('nav.community'), path: '/community' },
{ name: t('nav.faq'), path: '/faq' },
{ name: t('nav.contact'), path: '/contact' }
];
//
const isLangDropdownOpen = ref(false);
const toggleLangDropdown = () => {
isLangDropdownOpen.value = !isLangDropdownOpen.value;
};
// emit
const emit = defineEmits(['changeLanguage']);
</script>
<template>
<header class="bg-background-dark text-text py-4 px-6 md:px-12 lg:px-24 fixed w-full z-50">
<div class="container mx-auto flex justify-between items-center">
<!-- Logo -->
<router-link to="/" class="flex items-center">
<img src="/public/vite.svg" alt="MOSE Logo" class="h-8 w-auto mr-2" />
<span class="text-xl font-bold text-primary-light">MOSE</span>
</router-link>
<!-- Desktop Navigation -->
<nav class="hidden md:flex items-center space-x-6">
<router-link
v-for="item in navItems"
:key="item.path"
:to="item.path"
class="text-text-secondary hover:text-text transition-colors duration-200"
:class="{ 'text-primary-light font-medium': $route.path === item.path }"
>
{{ item.name }}
</router-link>
<!-- Language Selector -->
<div class="relative">
<button
@click="toggleLangDropdown"
class="flex items-center text-text-secondary hover:text-text"
>
{{ currentLanguage }}
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div
v-show="isLangDropdownOpen"
class="absolute right-0 mt-2 w-40 bg-background-light rounded-md shadow-lg py-1 z-10"
>
<button
v-for="lang in languages"
:key="lang.code"
@click="changeLanguage(lang.code); toggleLangDropdown()"
class="block w-full text-left px-4 py-2 text-text-secondary hover:bg-background hover:text-text"
:class="{ 'text-primary-light': locale === lang.code }"
>
{{ lang.name }}
</button>
</div>
</div>
</nav>
<!-- Mobile Menu Button -->
<button
@click="toggleMenu"
class="md:hidden text-text-secondary hover:text-text focus:outline-none"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
v-if="!isMenuOpen"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
<path
v-else
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<!-- Mobile Menu -->
<div
v-show="isMenuOpen"
class="md:hidden bg-background-light mt-4 rounded-lg py-4 px-6 shadow-lg"
>
<div class="flex flex-col space-y-4">
<router-link
v-for="item in navItems"
:key="item.path"
:to="item.path"
class="text-text-secondary hover:text-text py-2"
:class="{ 'text-primary-light font-medium': $route.path === item.path }"
@click="isMenuOpen = false"
>
{{ item.name }}
</router-link>
<!-- Mobile Language Selector -->
<div class="py-2 border-t border-background">
<p class="text-text-secondary mb-2">{{ t('language.en') }}</p>
<div class="flex flex-col space-y-2">
<button
v-for="lang in languages"
:key="lang.code"
@click="changeLanguage(lang.code); isMenuOpen = false"
class="text-left text-text-secondary hover:text-text"
:class="{ 'text-primary-light': locale === lang.code }"
>
{{ lang.name }}
</button>
</div>
</div>
</div>
</div>
</header>
<!-- Spacer to prevent content from hiding under fixed header -->
<div class="h-16"></div>
</template>

+ 34
- 0
src/i18n/index.ts View File

@ -0,0 +1,34 @@
import { createI18n } from 'vue-i18n'
import en from './locales/en.json'
import zh from './locales/zh.json'
import ja from './locales/ja.json'
// 获取浏览器语言或从本地存储中获取
const getBrowserLanguage = () => {
const storedLanguage = localStorage.getItem('language')
if (storedLanguage) {
return storedLanguage
}
const browserLanguage = navigator.language.toLowerCase()
if (browserLanguage.includes('zh')) {
return 'zh'
} else if (browserLanguage.includes('ja')) {
return 'ja'
} else {
return 'en' // 默认英语
}
}
const i18n = createI18n({
legacy: false, // 使用组合式API
locale: getBrowserLanguage(),
fallbackLocale: 'en',
messages: {
en,
zh,
ja
}
})
export default i18n

+ 55
- 0
src/i18n/locales/en.json View File

@ -0,0 +1,55 @@
{
"nav": {
"home": "Home",
"ecosystem": "Ecosystem",
"about": "About",
"resources": "Resources",
"community": "Community",
"faq": "FAQ",
"contact": "Contact"
},
"ecosystem": {
"title": "Ecosystem",
"subtitle": "Explore the MOSE ecosystem and discover the various projects and applications built on our platform",
"categories": {
"all": "All",
"defi": "DeFi",
"nft": "NFT",
"dao": "DAO",
"gaming": "Gaming",
"infrastructure": "Infrastructure",
"social": "Social"
},
"projects": {
"featured": "Featured Projects",
"viewAll": "View All",
"learnMore": "Learn More"
},
"partners": {
"title": "Strategic Partners",
"subtitle": "Organizations and projects that work with us to expand the MOSE ecosystem"
},
"join": {
"title": "Join Our Ecosystem",
"subtitle": "Build the next generation of decentralized applications on MOSE",
"cta": "Apply Now"
},
"resources": {
"title": "Developer Resources",
"docs": "Documentation",
"github": "GitHub",
"grants": "Grants Program",
"community": "Developer Community"
}
},
"footer": {
"rights": "All rights reserved",
"privacy": "Privacy Policy",
"terms": "Terms of Service"
},
"language": {
"en": "English",
"zh": "中文",
"ja": "日本語"
}
}

+ 55
- 0
src/i18n/locales/ja.json View File

@ -0,0 +1,55 @@
{
"nav": {
"home": "ホーム",
"ecosystem": "エコシステム",
"about": "私たちについて",
"resources": "リソース",
"community": "コミュニティ",
"faq": "よくある質問",
"contact": "お問い合わせ"
},
"ecosystem": {
"title": "エコシステム",
"subtitle": "MOSEエコシステムを探索し、プラットフォーム上に構築されたさまざまなプロジェクトとアプリケーションを発見しましょう",
"categories": {
"all": "すべて",
"defi": "DeFi",
"nft": "NFT",
"dao": "DAO",
"gaming": "ゲーム",
"infrastructure": "インフラストラクチャ",
"social": "ソーシャル"
},
"projects": {
"featured": "注目のプロジェクト",
"viewAll": "すべて表示",
"learnMore": "詳細を見る"
},
"partners": {
"title": "戦略的パートナー",
"subtitle": "MOSEエコシステムの拡大に協力する組織とプロジェクト"
},
"join": {
"title": "エコシステムに参加する",
"subtitle": "MOSEで次世代の分散型アプリケーションを構築する",
"cta": "今すぐ申し込む"
},
"resources": {
"title": "開発者リソース",
"docs": "ドキュメント",
"github": "GitHub",
"grants": "助成金プログラム",
"community": "開発者コミュニティ"
}
},
"footer": {
"rights": "全著作権所有",
"privacy": "プライバシーポリシー",
"terms": "利用規約"
},
"language": {
"en": "English",
"zh": "中文",
"ja": "日本語"
}
}

+ 55
- 0
src/i18n/locales/zh.json View File

@ -0,0 +1,55 @@
{
"nav": {
"home": "首页",
"ecosystem": "生态系统",
"about": "关于我们",
"resources": "资源",
"community": "社区",
"faq": "常见问题",
"contact": "联系我们"
},
"ecosystem": {
"title": "生态系统",
"subtitle": "探索MOSE生态系统,发现在我们平台上构建的各种项目和应用",
"categories": {
"all": "全部",
"defi": "去中心化金融",
"nft": "非同质化代币",
"dao": "去中心化自治组织",
"gaming": "游戏",
"infrastructure": "基础设施",
"social": "社交"
},
"projects": {
"featured": "精选项目",
"viewAll": "查看全部",
"learnMore": "了解更多"
},
"partners": {
"title": "战略合作伙伴",
"subtitle": "与我们合作拓展MOSE生态系统的组织和项目"
},
"join": {
"title": "加入我们的生态系统",
"subtitle": "在MOSE上构建下一代去中心化应用",
"cta": "立即申请"
},
"resources": {
"title": "开发者资源",
"docs": "文档",
"github": "GitHub",
"grants": "资助计划",
"community": "开发者社区"
}
},
"footer": {
"rights": "版权所有",
"privacy": "隐私政策",
"terms": "服务条款"
},
"language": {
"en": "English",
"zh": "中文",
"ja": "日本語"
}
}

+ 12
- 0
src/main.ts View File

@ -0,0 +1,12 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import i18n from './i18n'
const app = createApp(App)
app.use(router)
app.use(i18n)
app.mount('#app')

+ 34
- 0
src/router/index.ts View File

@ -0,0 +1,34 @@
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/ecosystem',
name: 'Ecosystem',
component: () => import('@/views/Ecosystem.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/NotFound.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior() {
return { top: 0 }
}
})
export default router

+ 213
- 0
src/style.css View File

@ -0,0 +1,213 @@
@import "tailwindcss";
@layer base {
:root {
--color-primary: #1E40AF;
--color-primary-light: #3B82F6;
--color-primary-dark: #1E3A8A;
--color-secondary: #10B981;
--color-secondary-light: #34D399;
--color-secondary-dark: #059669;
--color-background: #0F172A;
--color-background-light: #1E293B;
--color-background-dark: #020617;
--color-accent: #F59E0B;
--color-accent-light: #FBBF24;
--color-accent-dark: #D97706;
--color-text: #F8FAFC;
--color-text-secondary: #94A3B8;
--color-text-dark: #1E293B;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', system-ui, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: var(--color-background);
color: var(--color-text);
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Montserrat', sans-serif;
line-height: 1.2;
}
}
/* 自定义颜色类 */
.bg-primary {
background-color: var(--color-primary);
}
.bg-primary-light {
background-color: var(--color-primary-light);
}
.bg-primary-dark {
background-color: var(--color-primary-dark);
}
.bg-secondary {
background-color: var(--color-secondary);
}
.bg-secondary-light {
background-color: var(--color-secondary-light);
}
.bg-secondary-dark {
background-color: var(--color-secondary-dark);
}
.bg-background {
background-color: var(--color-background);
}
.bg-background-light {
background-color: var(--color-background-light);
}
.bg-background-dark {
background-color: var(--color-background-dark);
}
.bg-accent {
background-color: var(--color-accent);
}
.bg-accent-light {
background-color: var(--color-accent-light);
}
.bg-accent-dark {
background-color: var(--color-accent-dark);
}
.text-primary {
color: var(--color-primary);
}
.text-primary-light {
color: var(--color-primary-light);
}
.text-primary-dark {
color: var(--color-primary-dark);
}
.text-secondary {
color: var(--color-secondary);
}
.text-text {
color: var(--color-text);
}
.text-text-secondary {
color: var(--color-text-secondary);
}
.text-text-dark {
color: var(--color-text-dark);
}
.border-primary {
border-color: var(--color-primary);
}
.border-primary-light {
border-color: var(--color-primary-light);
}
/* 自定义容器和按钮样式 */
.container {
width: 100%;
margin-left: auto;
margin-right: auto;
padding-left: 1rem;
padding-right: 1rem;
}
@media (min-width: 640px) {
.container {
max-width: 640px;
}
}
@media (min-width: 768px) {
.container {
max-width: 768px;
padding-left: 1.5rem;
padding-right: 1.5rem;
}
}
@media (min-width: 1024px) {
.container {
max-width: 1024px;
padding-left: 2rem;
padding-right: 2rem;
}
}
@media (min-width: 1280px) {
.container {
max-width: 1280px;
}
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-weight: 500;
transition-property: background-color, border-color, color;
transition-duration: 300ms;
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-text);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
}
.btn-outline {
background-color: transparent;
border: 1px solid var(--color-primary-light);
color: var(--color-primary-light);
}
.btn-outline:hover {
background-color: var(--color-primary-light);
background-opacity: 0.1;
}
.shadow-card {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.shadow-button {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
.blur-3xl {
--tw-blur: blur(64px);
filter: var(--tw-blur);
}
/* 自定义滚动条 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #1E293B;
}
::-webkit-scrollbar-thumb {
background: #3B82F6;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #2563EB;
}

+ 183
- 0
src/views/About.vue View File

@ -0,0 +1,183 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
const teamMembers = [
{
id: 1,
name: 'John Doe',
position: 'CEO & Founder',
image: '/public/images.png',
linkedin: 'https://linkedin.com'
},
{
id: 2,
name: 'Jane Smith',
position: 'CTO',
image: '/public/images.png',
linkedin: 'https://linkedin.com'
},
{
id: 3,
name: 'Mike Johnson',
position: 'Lead Developer',
image: '/public/images.png',
linkedin: 'https://linkedin.com'
},
{
id: 4,
name: 'Sarah Williams',
position: 'Marketing Director',
image: '/public/images.png',
linkedin: 'https://linkedin.com'
}
];
//
const milestones = [
{
year: '2021',
title: 'MOSE Founded',
description: 'MOSE was founded with a vision to create a high-performance blockchain platform.'
},
{
year: '2022',
title: 'Testnet Launch',
description: 'Successfully launched our testnet with key features and functionalities.'
},
{
year: '2023',
title: 'Mainnet Beta',
description: 'Released the beta version of our mainnet with improved performance and security.'
},
{
year: '2024',
title: 'Ecosystem Growth',
description: 'Expanded our ecosystem with various projects and partnerships.'
}
];
</script>
<template>
<div class="bg-background min-h-screen">
<!-- Hero Section -->
<section class="relative py-24 px-6 md:px-12 lg:px-24 bg-background-dark overflow-hidden">
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-text mb-6">
关于我们
</h1>
<p class="text-lg md:text-xl text-text-secondary mb-8">
了解MOSE的愿景使命和团队
</p>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-10">
<div class="absolute -top-24 -left-24 w-64 h-64 rounded-full bg-primary-light blur-3xl"></div>
<div class="absolute top-1/2 right-0 w-80 h-80 rounded-full bg-secondary blur-3xl"></div>
<div class="absolute -bottom-24 left-1/3 w-72 h-72 rounded-full bg-accent blur-3xl"></div>
</div>
</section>
<!-- Our Story Section -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<div class="max-w-3xl mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-6">我们的故事</h2>
<div class="space-y-6 text-text-secondary">
<p>
MOSE是一个致力于构建高性能安全和可扩展区块链平台的项目我们的使命是为去中心化应用提供强大的基础设施使开发者能够构建下一代的区块链应用
</p>
<p>
我们的团队由区块链技术专家经验丰富的开发者和行业领导者组成共同致力于推动区块链技术的发展和应用
</p>
<p>
MOSE的核心价值观包括去中心化安全可扩展性和社区驱动我们相信通过这些价值观的指导我们可以构建一个更加开放公平和高效的区块链生态系统
</p>
</div>
</div>
</div>
</section>
<!-- Team Section -->
<section class="py-16 px-6 md:px-12 lg:px-24 bg-background-light">
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-10 text-center">
我们的团队
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
<div
v-for="member in teamMembers"
:key="member.id"
class="bg-background rounded-xl overflow-hidden shadow-card hover:shadow-lg transition-all duration-300"
>
<img :src="member.image" :alt="member.name" class="w-full h-48 object-cover" />
<div class="p-5">
<h3 class="text-lg font-bold text-text mb-1">{{ member.name }}</h3>
<p class="text-text-secondary text-sm mb-3">{{ member.position }}</p>
<a
:href="member.linkedin"
target="_blank"
rel="noopener noreferrer"
class="text-primary-light hover:text-primary-dark transition-colors duration-200 flex items-center text-sm"
>
<svg class="h-4 w-4 mr-1" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"></path>
</svg>
LinkedIn
</a>
</div>
</div>
</div>
</div>
</section>
<!-- Milestones Section -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-10 text-center">
发展历程
</h2>
<div class="max-w-4xl mx-auto">
<div class="relative">
<!-- Timeline Line -->
<div class="absolute top-0 left-6 md:left-1/2 w-0.5 h-full bg-primary-light transform -translate-x-1/2"></div>
<!-- Timeline Items -->
<div class="space-y-12">
<div
v-for="(milestone, index) in milestones"
:key="index"
class="relative"
>
<div class="flex flex-col md:flex-row items-center">
<!-- Year Bubble -->
<div
class="absolute left-6 md:left-1/2 w-12 h-12 bg-primary rounded-full flex items-center justify-center transform -translate-x-1/2 z-10"
>
<span class="text-text font-bold text-sm">{{ milestone.year }}</span>
</div>
<!-- Content -->
<div
class="ml-20 md:ml-0 md:w-1/2 md:pr-8 md:text-right"
:class="{ 'md:pl-8 md:pr-0 md:text-left md:order-2': index % 2 !== 0 }"
>
<h3 class="text-xl font-bold text-text mb-2">{{ milestone.title }}</h3>
<p class="text-text-secondary">{{ milestone.description }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</template>

+ 396
- 0
src/views/Ecosystem.vue View File

@ -0,0 +1,396 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
const selectedCategory = ref('all');
//
const categories = [
{ id: 'all', name: t('ecosystem.categories.all') },
{ id: 'defi', name: t('ecosystem.categories.defi') },
{ id: 'nft', name: t('ecosystem.categories.nft') },
{ id: 'dao', name: t('ecosystem.categories.dao') },
{ id: 'gaming', name: t('ecosystem.categories.gaming') },
{ id: 'infrastructure', name: t('ecosystem.categories.infrastructure') },
{ id: 'social', name: t('ecosystem.categories.social') },
];
//
const projects = [
{
id: 1,
name: 'MOSE Swap',
description: 'Decentralized exchange with low fees and high liquidity',
category: 'defi',
image: '/public/images.png',
url: 'https://moseswap.io',
featured: true
},
{
id: 2,
name: 'MOSE NFT Marketplace',
description: 'Trade unique digital assets on the MOSE blockchain',
category: 'nft',
image: '/public/images.png',
url: 'https://mosenft.io',
featured: true
},
{
id: 3,
name: 'MOSE DAO',
description: 'Decentralized governance for the MOSE ecosystem',
category: 'dao',
image: '/public/images.png',
url: 'https://mosedao.io',
featured: true
},
{
id: 4,
name: 'MOSE Gaming',
description: 'Play-to-earn games built on MOSE',
category: 'gaming',
image: '/public/images.png',
url: 'https://mosegaming.io',
featured: false
},
{
id: 5,
name: 'MOSE Bridge',
description: 'Cross-chain bridge for MOSE assets',
category: 'infrastructure',
image: '/public/images.png',
url: 'https://mosebridge.io',
featured: true
},
{
id: 6,
name: 'MOSE Social',
description: 'Decentralized social network',
category: 'social',
image: '/public/images.png',
url: 'https://mosesocial.io',
featured: false
},
{
id: 7,
name: 'MOSE Lending',
description: 'Decentralized lending protocol',
category: 'defi',
image: '/public/images.png',
url: 'https://moselending.io',
featured: false
},
{
id: 8,
name: 'MOSE Staking',
description: 'Stake your MOSE tokens for rewards',
category: 'defi',
image: '/public/images.png',
url: 'https://mosestaking.io',
featured: false
}
];
//
const partners = [
{
id: 1,
name: 'Partner 1',
logo: '/public/images.png',
url: 'https://partner1.com'
},
{
id: 2,
name: 'Partner 2',
logo: '/public/images.png',
url: 'https://partner2.com'
},
{
id: 3,
name: 'Partner 3',
logo: '/public/images.png',
url: 'https://partner3.com'
},
{
id: 4,
name: 'Partner 4',
logo: '/public/images.png',
url: 'https://partner4.com'
},
{
id: 5,
name: 'Partner 5',
logo: '/public/images.png',
url: 'https://partner5.com'
},
{
id: 6,
name: 'Partner 6',
logo: '/public/images.png',
url: 'https://partner6.com'
}
];
//
const filteredProjects = computed(() => {
if (selectedCategory.value === 'all') {
return projects;
} else {
return projects.filter(project => project.category === selectedCategory.value);
}
});
//
const featuredProjects = computed(() => {
return projects.filter(project => project.featured);
});
//
const selectCategory = (category: string) => {
selectedCategory.value = category;
};
</script>
<template>
<div class="bg-background min-h-screen">
<!-- Hero Section -->
<section class="relative py-24 px-6 md:px-12 lg:px-24 bg-background-dark overflow-hidden">
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-text mb-6">
{{ t('ecosystem.title') }}
</h1>
<p class="text-lg md:text-xl text-text-secondary mb-8">
{{ t('ecosystem.subtitle') }}
</p>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-10">
<div class="absolute -top-24 -left-24 w-64 h-64 rounded-full bg-primary-light blur-3xl"></div>
<div class="absolute top-1/2 right-0 w-80 h-80 rounded-full bg-secondary blur-3xl"></div>
<div class="absolute -bottom-24 left-1/3 w-72 h-72 rounded-full bg-accent blur-3xl"></div>
</div>
</section>
<!-- Featured Projects Section -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<div class="flex justify-between items-center mb-10">
<h2 class="text-2xl md:text-3xl font-bold text-text">
{{ t('ecosystem.projects.featured') }}
</h2>
<a href="#all-projects" class="text-primary-light hover:text-primary-dark transition-colors duration-200">
{{ t('ecosystem.projects.viewAll') }}
</a>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div
v-for="project in featuredProjects"
:key="project.id"
class="bg-background-light rounded-xl overflow-hidden shadow-card hover:transform hover:scale-105 transition-all duration-300"
>
<img :src="project.image" :alt="project.name" class="w-full h-48 object-cover" />
<div class="p-6">
<h3 class="text-xl font-bold text-text mb-2">{{ project.name }}</h3>
<p class="text-text-secondary mb-4">{{ project.description }}</p>
<div class="flex justify-between items-center">
<span class="px-3 py-1 bg-background text-primary-light text-xs rounded-full">
{{ t(`ecosystem.categories.${project.category}`) }}
</span>
<a
:href="project.url"
target="_blank"
rel="noopener noreferrer"
class="text-primary-light hover:text-primary-dark transition-colors duration-200"
>
{{ t('ecosystem.projects.learnMore') }}
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- All Projects Section -->
<section id="all-projects" class="py-16 px-6 md:px-12 lg:px-24 bg-background-light">
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-10">
{{ t('ecosystem.title') }}
</h2>
<!-- Categories Filter -->
<div class="flex flex-wrap gap-2 mb-10">
<button
v-for="category in categories"
:key="category.id"
@click="selectCategory(category.id)"
class="px-4 py-2 rounded-full text-sm transition-colors duration-200"
:class="selectedCategory === category.id
? 'bg-primary text-text'
: 'bg-background-dark text-text-secondary hover:bg-background hover:text-text'"
>
{{ category.name }}
</button>
</div>
<!-- Projects Grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<div
v-for="project in filteredProjects"
:key="project.id"
class="bg-background rounded-xl overflow-hidden shadow-card hover:shadow-lg transition-all duration-300"
>
<img :src="project.image" :alt="project.name" class="w-full h-40 object-cover" />
<div class="p-5">
<h3 class="text-lg font-bold text-text mb-2">{{ project.name }}</h3>
<p class="text-text-secondary text-sm mb-4">{{ project.description }}</p>
<div class="flex justify-between items-center">
<span class="px-3 py-1 bg-background-dark text-primary-light text-xs rounded-full">
{{ t(`ecosystem.categories.${project.category}`) }}
</span>
<a
:href="project.url"
target="_blank"
rel="noopener noreferrer"
class="text-primary-light hover:text-primary-dark transition-colors duration-200 text-sm"
>
{{ t('ecosystem.projects.learnMore') }}
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Partners Section -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<div class="text-center mb-12">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-4">
{{ t('ecosystem.partners.title') }}
</h2>
<p class="text-text-secondary max-w-2xl mx-auto">
{{ t('ecosystem.partners.subtitle') }}
</p>
</div>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-8">
<a
v-for="partner in partners"
:key="partner.id"
:href="partner.url"
target="_blank"
rel="noopener noreferrer"
class="flex items-center justify-center p-6 bg-background-light rounded-lg hover:bg-background-dark transition-colors duration-300"
>
<img :src="partner.logo" :alt="partner.name" class="max-h-12 max-w-full" />
</a>
</div>
</div>
</section>
<!-- Join Ecosystem CTA -->
<section class="py-20 px-6 md:px-12 lg:px-24 bg-primary bg-opacity-10 relative overflow-hidden">
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-4">
{{ t('ecosystem.join.title') }}
</h2>
<p class="text-text-secondary mb-8">
{{ t('ecosystem.join.subtitle') }}
</p>
<a
href="#"
class="inline-block px-8 py-3 bg-primary text-text rounded-lg hover:bg-primary-dark transition-colors duration-300 shadow-button"
>
{{ t('ecosystem.join.cta') }}
</a>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-30">
<div class="absolute top-0 right-0 w-64 h-64 rounded-full bg-primary blur-3xl"></div>
<div class="absolute bottom-0 left-0 w-80 h-80 rounded-full bg-primary blur-3xl"></div>
</div>
</section>
<!-- Developer Resources -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-10">
{{ t('ecosystem.resources.title') }}
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<a
href="#"
class="bg-background-light p-6 rounded-xl flex flex-col items-center text-center hover:bg-background-dark transition-colors duration-300"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-primary-light mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
<h3 class="text-lg font-bold text-text mb-2">{{ t('ecosystem.resources.docs') }}</h3>
<p class="text-text-secondary text-sm">
Comprehensive documentation for developers
</p>
</a>
<a
href="#"
class="bg-background-light p-6 rounded-xl flex flex-col items-center text-center hover:bg-background-dark transition-colors duration-300"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-primary-light mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
</svg>
<h3 class="text-lg font-bold text-text mb-2">{{ t('ecosystem.resources.github') }}</h3>
<p class="text-text-secondary text-sm">
Open source code repositories
</p>
</a>
<a
href="#"
class="bg-background-light p-6 rounded-xl flex flex-col items-center text-center hover:bg-background-dark transition-colors duration-300"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-primary-light mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<h3 class="text-lg font-bold text-text mb-2">{{ t('ecosystem.resources.grants') }}</h3>
<p class="text-text-secondary text-sm">
Funding for innovative projects
</p>
</a>
<a
href="#"
class="bg-background-light p-6 rounded-xl flex flex-col items-center text-center hover:bg-background-dark transition-colors duration-300"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-primary-light mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
<h3 class="text-lg font-bold text-text mb-2">{{ t('ecosystem.resources.community') }}</h3>
<p class="text-text-secondary text-sm">
Join our developer community
</p>
</a>
</div>
</div>
</section>
</div>
</template>
<style scoped>
/* 添加一些额外的动画效果 */
.hover\:transform:hover {
transform: translateY(-5px);
}
</style>

+ 90
- 0
src/views/Home.vue View File

@ -0,0 +1,90 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
const { t } = useI18n();
const router = useRouter();
const goToEcosystem = () => {
router.push('/ecosystem');
};
</script>
<template>
<div class="bg-background min-h-screen">
<!-- Hero Section -->
<section class="relative py-32 px-6 md:px-12 lg:px-24 bg-background-dark overflow-hidden">
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-text mb-6">
MOSE Blockchain
</h1>
<p class="text-lg md:text-xl text-text-secondary mb-8">
Next-generation blockchain platform for high performance, security, and scalability
</p>
<div class="flex flex-col sm:flex-row justify-center gap-4">
<button
@click="goToEcosystem"
class="px-8 py-3 bg-primary text-text rounded-lg hover:bg-primary-dark transition-colors duration-300 shadow-button"
>
{{ t('ecosystem.title') }}
</button>
<a
href="#"
class="px-8 py-3 bg-transparent border border-primary-light text-primary-light rounded-lg hover:bg-primary-light hover:bg-opacity-10 transition-colors duration-300"
>
{{ t('ecosystem.resources.docs') }}
</a>
</div>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-10">
<div class="absolute -top-24 -left-24 w-64 h-64 rounded-full bg-primary-light blur-3xl"></div>
<div class="absolute top-1/2 right-0 w-80 h-80 rounded-full bg-secondary blur-3xl"></div>
<div class="absolute -bottom-24 left-1/3 w-72 h-72 rounded-full bg-accent blur-3xl"></div>
</div>
</section>
<!-- Video Section -->
<section class="py-16 px-6 md:px-12 lg:px-24">
<div class="container mx-auto">
<div class="max-w-4xl mx-auto bg-background-light rounded-2xl overflow-hidden shadow-card">
<video
src="/public/MOSEVideo.mp4"
controls
class="w-full h-auto"
poster="/public/images.png"
></video>
</div>
</div>
</section>
<!-- Call to Action -->
<section class="py-20 px-6 md:px-12 lg:px-24 bg-primary bg-opacity-10 relative overflow-hidden">
<div class="container mx-auto relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h2 class="text-2xl md:text-3xl font-bold text-text mb-4">
{{ t('ecosystem.join.title') }}
</h2>
<p class="text-text-secondary mb-8">
{{ t('ecosystem.join.subtitle') }}
</p>
<button
@click="goToEcosystem"
class="inline-block px-8 py-3 bg-primary text-text rounded-lg hover:bg-primary-dark transition-colors duration-300 shadow-button"
>
{{ t('ecosystem.title') }}
</button>
</div>
</div>
<!-- Background Decoration -->
<div class="absolute top-0 left-0 w-full h-full overflow-hidden opacity-30">
<div class="absolute top-0 right-0 w-64 h-64 rounded-full bg-primary blur-3xl"></div>
<div class="absolute bottom-0 left-0 w-80 h-80 rounded-full bg-primary blur-3xl"></div>
</div>
</section>
</div>
</template>

+ 27
- 0
src/views/NotFound.vue View File

@ -0,0 +1,27 @@
<script setup lang="ts">
import { useRouter } from 'vue-router';
const router = useRouter();
const goHome = () => {
router.push('/');
};
</script>
<template>
<div class="bg-background min-h-screen flex items-center justify-center px-6 py-24">
<div class="text-center">
<h1 class="text-6xl md:text-8xl font-bold text-primary-light mb-4">404</h1>
<h2 class="text-2xl md:text-3xl font-bold text-text mb-6">页面未找到</h2>
<p class="text-text-secondary mb-8 max-w-md mx-auto">
您访问的页面不存在或已被移除请检查URL或返回首页
</p>
<button
@click="goHome"
class="px-8 py-3 bg-primary text-text rounded-lg hover:bg-primary-dark transition-colors duration-300 shadow-button"
>
返回首页
</button>
</div>
</div>
</template>

+ 1
- 0
src/vite-env.d.ts View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

+ 20
- 0
tsconfig.app.json View File

@ -0,0 +1,20 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
/* */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

+ 7
- 0
tsconfig.json View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

+ 26
- 0
tsconfig.node.json View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
},
"include": ["vite.config.ts"]
}

+ 20
- 0
vite.config.ts View File

@ -0,0 +1,20 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
tailwindcss(),
],
server: {
port: 3000,
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
})

Loading…
Cancel
Save