feat(page): 新增启动与安装文档页面 (#26)

完善一些页面的样式和功能
This commit is contained in:
Dawn
2024-12-09 17:28:06 +08:00
committed by GitHub
parent 83d5079303
commit 778d71486e
14 changed files with 919 additions and 306 deletions

View File

@@ -28,4 +28,13 @@ useHead({
opacity: 0;
filter: blur(1rem);
}
.layout-enter-active,
.layout-leave-active {
transition: all 0.4s;
}
.layout-enter-from,
.layout-leave-to {
opacity: 0;
filter: blur(1rem);
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<PageBackground>
<div class="flex relative h-[calc(100vh-var(--header-height))] overflow-y-auto flex-col md:flex-row">
<!-- Sidebar -->
<aside
class="md:sticky md:top-0 md:w-44 md:ml-48 w-full border-b md:border-b-0 md:border-r border-gray-200 dark:border-teal-900 overflow-y-auto">
<nav class="p-4 space-y-1">
<div class="mb-4">
<h3 class="px-3 text-sm font-semibold text-gray-500 dark:text-gray-400">开始使用</h3>
<div class="mt-1 space-y-1">
<NuxtLink
to="/docs/getting-started/introduction"
class="flex items-center px-3 py-2 text-sm rounded-lg md:ml-4"
:class="{
'text-teal-600': $route.path === '/docs/getting-started/introduction',
'hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300':
$route.path !== '/docs/getting-started/introduction'
}">
<div
:class="[
'w-5 h-5 mr-2 flex items-center justify-center rounded',
$route.path === '/docs/getting-started/introduction'
? 'bg-teal-600'
: 'bg-gray-200 dark:bg-gray-700'
]">
<Icon
name="ph:book-open"
:class="[
'w-3.5 h-3.5',
$route.path === '/docs/getting-started/introduction'
? 'text-white'
: 'text-gray-500 dark:text-gray-400'
]" />
</div>
安装与启动
</NuxtLink>
</div>
</div>
</nav>
</aside>
<!-- Main content -->
<main class="flex-1 md:ml-2 overflow-y-auto" style="scrollbar-width: none">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
<slot />
</div>
</main>
</div>
</PageBackground>
</template>
<script setup lang="ts"></script>
<style scoped>
.photon-effect {
position: absolute;
width: 2px;
height: 100%;
animation: movePhoton 3s linear infinite;
}
.light-photon {
background: linear-gradient(180deg, transparent, rgba(14, 165, 233, 0.5), transparent);
opacity: 0.3;
}
.dark-photon {
background: linear-gradient(180deg, transparent, #fff, transparent);
opacity: 0.5;
}
.delay-2 {
animation-delay: 1s;
left: 30%;
}
.delay-4 {
animation-delay: 2s;
left: 70%;
}
@keyframes movePhoton {
0% {
transform: translateY(-100%) translateX(-100%);
}
100% {
transform: translateY(100%) translateX(100%);
}
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<footer class="bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-800 py-8 md:py-12">
<div class="container mx-auto px-4 grid grid-cols-2 md:grid-cols-4 gap-6 md:gap-8">
<!-- Product Section -->
<div class="text-center md:text-left">
<h4 class="font-semibold text-gray-800 dark:text-gray-200 mb-3 md:mb-4">产品展示</h4>
<nav class="flex flex-col space-y-2">
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">定制</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">路线图</a>
</nav>
</div>
<!-- Developers Section -->
<div class="text-center md:text-left">
<h4 class="font-semibold text-gray-800 dark:text-gray-200 mb-3 md:mb-4">开发人员</h4>
<nav class="flex flex-col space-y-2">
<a
href="https://github.com/orgs/HuLaSpark/teams"
class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm"
>HuLaSpark团队</a
>
</nav>
</div>
<!-- Community Section -->
<div class="text-center md:text-left">
<h4 class="font-semibold text-gray-800 dark:text-gray-200 mb-3 md:mb-4">社区</h4>
<nav class="flex flex-col space-y-2">
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">微信群聊</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">QQ</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">HuLa</a>
</nav>
</div>
<!-- Company Section -->
<div class="text-center md:text-left">
<h4 class="font-semibold text-gray-800 dark:text-gray-200 mb-3 md:mb-4">团队简介</h4>
<nav class="flex flex-col space-y-2">
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-sm">关于HuLaSpark</a>
</nav>
</div>
</div>
<div
class="container mx-auto px-4 mt-6 md:mt-8 pt-6 md:pt-8 border-t border-gray-200 dark:border-gray-800 text-center">
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
<div class="text-gray-600 dark:text-gray-400 text-xs md:text-sm">
{{ currentYear }} HuLaSpark. All rights reserved.
</div>
<div class="flex space-x-4">
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-xs md:text-sm">
隐私条款
</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-teal-600 transition text-xs md:text-sm">
服务协议
</a>
</div>
</div>
</div>
</footer>
</template>
<script setup lang="ts">
const currentYear = new Date().getFullYear()
</script>

View File

@@ -94,19 +94,97 @@
</div>
</div>
<div v-if="isMobileMenuOpen" class="fixed inset-0 bg-white dark:bg-gray-900 z-50 flex flex-col">
<div v-if="isMobileMenuOpen" class="fixed inset-0 bg-white dark:bg-gray-900 z-50 flex flex-col overflow-y-auto">
<button
@click="isMobileMenuOpen = false"
class="absolute top-4 right-4 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
<UIcon name="solar:close-circle-linear" class="w-6 h-6" />
</button>
<div class="p-4">
<span
:class="{ 'text-teal-600': isActive('/docs/getting-started/introduction') }"
class="font-semibold text-sm/6 inline-block relative">
开始使用
</span>
<span class="text-sm leading-snug text-gray-500 dark:text-gray-400 line-clamp-2"> 了解如何开始使用 HuLa </span>
<div class="p-4 space-y-4">
<div class="flex items-center gap-2.5 border-b pb-4 border-gray-200 dark:border-gray-800">
<NuxtLink to="/" @click="isMobileMenuOpen = false" class="inline-flex items-center gap-2.5">
<img class="w-7 h-7" src="~/assets/logo/logo.png" alt="" />
<span class="text-lg text-teal-900 dark:text-teal-600 font-semibold">HuLa</span>
</NuxtLink>
<span
class="inline-flex items-center text-xs px-1.5 py-0.5 bg-teal-50 dark:bg-teal-400 dark:bg-opacity-10 text-teal-500 dark:text-teal-400 ring-1 ring-inset ring-teal-500 dark:ring-teal-400 ring-opacity-25 dark:ring-opacity-25 rounded font-semibold">
{{ config.MasterVersion }}
</span>
</div>
<div class="space-y-2">
<h3 class="text-sm font-semibold text-gray-600 dark:text-gray-400 mb-2">文档</h3>
<div class="space-y-1">
<NuxtLink
to="/docs/getting-started/introduction"
@click="isMobileMenuOpen = false"
:class="{ 'text-teal-600': isActive('/docs/getting-started/introduction') }"
class="block px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50 flex items-center gap-2">
<UIcon
name="solar:bolt-outline"
:class="{ 'text-teal-600': isActive('/docs/getting-started/introduction') }"
class="w-4 h-4 text-gray-500 dark:text-gray-400 flex-shrink-0" />
<div>
<span
:class="{ 'text-teal-600': isActive('/docs/getting-started/introduction') }"
class="font-semibold text-sm/6 block">
开始使用
</span>
<span class="text-xs text-gray-500 dark:text-gray-400 line-clamp-1"> 了解如何开始使用 HuLa </span>
</div>
</NuxtLink>
</div>
</div>
<div class="space-y-2 mt-4">
<h3 class="text-sm font-semibold text-gray-600 dark:text-gray-400 mb-2">快捷操作</h3>
<div class="grid grid-cols-2 gap-2">
<button
@click="handleMobileAction('new-file')"
class="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50">
<UIcon name="i-heroicons-document-plus" class="w-4 h-4 text-gray-500 dark:text-gray-400" />
<span class="text-sm">新建文件</span>
</button>
<button
@click="handleMobileAction('new-folder')"
class="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50">
<UIcon name="i-heroicons-folder-plus" class="w-4 h-4 text-gray-500 dark:text-gray-400" />
<span class="text-sm">新建文件夹</span>
</button>
<button
@click="handleMobileAction('hashtag')"
class="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50">
<UIcon name="i-heroicons-hashtag" class="w-4 h-4 text-gray-500 dark:text-gray-400" />
<span class="text-sm">添加标签</span>
</button>
<button
@click="handleMobileAction('label')"
class="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50">
<UIcon name="i-heroicons-tag" class="w-4 h-4 text-gray-500 dark:text-gray-400" />
<span class="text-sm">添加标签</span>
</button>
</div>
</div>
<div class="space-y-2 mt-4">
<h3 class="text-sm font-semibold text-gray-600 dark:text-gray-400 mb-2">链接</h3>
<div class="space-y-1">
<a
v-for="user in users"
:key="user.id"
:href="user.href"
target="_blank"
class="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-gray-100/50 dark:hover:bg-gray-950/50">
<img
:src="user.avatar.src"
:srcset="user.avatar.srcset"
:loading="user.avatar.loading as any"
class="w-6 h-6 rounded-full" />
<span class="text-sm">{{ user.label }}</span>
</a>
</div>
</div>
</div>
</div>
@@ -229,6 +307,25 @@ const onSelect = (option: any) => {
const isActive = (path: string) => {
return route.path === path
}
const handleMobileAction = (action: string) => {
switch (action) {
case 'new-file':
toast.add({ title: 'New file added!' })
break
case 'new-folder':
toast.add({ title: 'New folder added!' })
break
case 'hashtag':
toast.add({ title: 'Hashtag added!' })
break
case 'label':
toast.add({ title: 'Label added!' })
break
default:
break
}
}
</script>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,94 @@
<template>
<div class="flex border-b border-gray-200 dark:border-gray-700 mb-4 items-center overflow-x-auto">
<div class="flex flex-1 min-w-max">
<button
v-for="manager in props.packageManagers"
:key="manager"
:class="[
'px-4 py-2 text-sm font-medium flex items-center gap-2 transition-colors duration-200',
manager === 'npm' || manager === 'yarn'
? 'text-gray-300 dark:text-gray-600 cursor-not-allowed opacity-50'
: activeManager === manager
? 'text-teal-600 dark:text-teal-500 border-b-2 border-transparent border-teal-600 dark:border-teal-500'
: ''
]"
:disabled="manager === 'npm' || manager === 'yarn'"
@click="handleManagerChange(manager)">
<img :src="managerIcons[manager].icon" :alt="manager" class="w-4 h-4" />
{{ manager }}
<span
v-if="manager === 'pnpm'"
class="ml-2 px-2 py-0.5 text-xs font-medium text-teal-700 bg-teal-100 rounded-full">
推荐
</span>
</button>
</div>
<div class="relative">
<button
v-if="activeManager === 'pnpm' || activeManager === 'bun'"
@click="handleCopy"
class="ml-4 text-gray-500 hover:text-teal-600 transition-colors relative">
<Icon name="ph:copy-simple-fill" class="w-5 h-5" />
</button>
<div
v-if="showCopyTooltip"
class="absolute -top-8 left-1/2 transform -translate-x-1/2 bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-white text-xs px-2 py-1 rounded shadow-sm inline-flex whitespace-nowrap transition-all duration-300 ease-in-out">
复制成功
</div>
</div>
</div>
<slot :activeManager="activeManager"></slot>
</template>
<script setup lang="ts">
const props = defineProps({
manager: {
type: String,
default: 'pnpm'
},
packageManagers: {
type: Array as PropType<string[]>,
default: () => ['npm', 'yarn', 'pnpm', 'bun']
}
})
const managerIcons: Record<string, { icon: string; color: string }> = {
npm: {
icon: '/assets/svg/npm.svg',
color: '#CB3837'
},
yarn: {
icon: '/assets/svg/yarn.svg',
color: '#2C8EBB'
},
pnpm: {
icon: '/assets/svg/pnpm.svg',
color: '#F69220'
},
bun: {
icon: '/assets/svg/bun.svg',
color: '#FBF0DF'
}
}
const activeManager = ref(props.manager)
const showCopyTooltip = ref(false)
const emit = defineEmits(['update:manager', 'copy'])
const handleManagerChange = (manager: string) => {
if (manager !== 'npm' && manager !== 'yarn') {
activeManager.value = manager
emit('update:manager', manager)
}
}
const handleCopy = () => {
emit('copy')
showCopyTooltip.value = true
setTimeout(() => {
showCopyTooltip.value = false
}, 2000)
}
</script>

View File

@@ -0,0 +1,57 @@
<template>
<div class="min-h-[calc(100vh-var(--header-height))] relative bg-[#f8fafc] dark:bg-[#111729] overflow-hidden">
<img
class="pointer-events-none absolute w-full top-[1px] text-teal flex-shrink-0 z-10"
src="/assets/svg/header.svg"
alt="" />
<div class="absolute inset-0">
<div
class="absolute inset-0 bg-gradient-to-b from-[#f8fafc] via-[#e2e8f0] to-[#f8fafc] dark:from-[#111729] dark:via-[#0c1322] dark:to-[#111729] opacity-60 dark:opacity-80"></div>
<div
class="absolute inset-0 bg-[url('/assets/svg/grid-light.svg')] dark:bg-[url('/assets/svg/grid.svg')] bg-center [mask-image:linear-gradient(180deg,white,rgba(255,255,255,0))]">
<div class="photon-effect light-photon dark:dark-photon"></div>
<div class="photon-effect light-photon dark:dark-photon delay-2"></div>
<div class="photon-effect light-photon dark:dark-photon delay-4"></div>
</div>
</div>
<slot></slot>
</div>
</template>
<style scoped>
.photon-effect {
position: absolute;
width: 2px;
height: 100%;
animation: movePhoton 3s linear infinite;
}
.light-photon {
background: linear-gradient(180deg, transparent, rgba(14, 165, 233, 0.5), transparent);
opacity: 0.3;
}
.dark-photon {
background: linear-gradient(180deg, transparent, #fff, transparent);
opacity: 0.5;
}
.delay-2 {
animation-delay: 1s;
left: 30%;
}
.delay-4 {
animation-delay: 2s;
left: 70%;
}
@keyframes movePhoton {
0% {
transform: translateY(-100%) translateX(-100%);
}
100% {
transform: translateY(100%) translateX(100%);
}
}
</style>

View File

@@ -1,9 +1,10 @@
<template>
<div>
<Header />
<slot name="left" />
<slot name="main" />
<slot name="right" />
<Docs>
<slot />
</Docs>
<Footer />
</div>
</template>

View File

@@ -3,6 +3,7 @@ export default defineNuxtConfig({
modules: ['@nuxt/test-utils/module', '@nuxt/ui', '@nuxt/image', '@nuxtjs/color-mode'],
app: {
pageTransition: { name: 'page', mode: 'out-in' },
layoutTransition: { name: 'layout', mode: 'out-in' },
head: {
script: [{ src: '/icon.js' }]
}

View File

@@ -1,12 +1,224 @@
<template>
<div class="w-full min-h-[calc(100vh-var(--header-height))] flex justify-center items-center">
官网正在编写中敬请期待
<div class="max-w-3xl mx-auto lg:mx-24 px-4 sm:px-6 lg:px-8">
<div class="mb-8">
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 dark:text-white">HuLa 介绍</h1>
<p class="mt-2 text-base sm:text-lg text-gray-600 dark:text-gray-400">了解 HuLa 的特性开始你的第一个项目:</p>
</div>
<div class="prose prose-sm max-w-none dark:prose-invert">
<div class="mb-8">
<h2 class="text-xl sm:text-2xl font-semibold">什么是 HuLa</h2>
<p>
HuLa 是一个基于 TauriVite 5Vue 3 TypeScript 构建的即时通讯系统它利用了 Tauri 的跨平台能力和 Vue 3
的响应式设计结合了 TypeScript 的类型安全特性和 Vite 5
的快速构建为用户提供了一个高效安全和易用的通讯解决方案
</p>
</div>
<div class="mb-8">
<h2 class="text-xl sm:text-2xl font-semibold">核心特性</h2>
<ul class="space-y-4">
<li class="flex items-start">
<Icon name="ph:lightning" class="w-5 h-5 sm:w-6 sm:h-6 mr-2 text-teal-600" />
<div>
<strong>现代架构</strong>
<p class="mt-1 text-sm sm:text-base">基于前沿技术构建实现最佳性能和开发体验</p>
</div>
</li>
<li class="flex items-start">
<Icon name="ph:code" class="w-5 h-5 sm:w-6 sm:h-6 mr-2 text-teal-600" />
<div>
<strong>开发体验</strong>
<p class="mt-1 text-sm sm:text-base">良好的开发规范和工具链封装通用的组件和 API实现快速开发</p>
</div>
</li>
<li class="flex items-start">
<Icon name="ph:rocket" class="w-5 h-5 sm:w-6 sm:h-6 mr-2 text-teal-600" />
<div>
<strong>高性能</strong>
<p class="mt-1 text-sm sm:text-base">使用Rust优化的构建过程和基于Vite 6 的高性能打造极速应用</p>
</div>
</li>
<li class="flex items-start">
<Icon name="ph:puzzle-piece" class="w-5 h-5 sm:w-6 sm:h-6 mr-2 text-teal-600" />
<div>
<strong>可扩展性</strong>
<span class="ml-2 px-2 py-0.5 text-xs font-medium text-purple-700 bg-purple-100 rounded-full">
Beta
</span>
<p class="mt-1 text-sm sm:text-base">丰富的插件和模块生态系统轻松扩展功能</p>
</div>
</li>
</ul>
</div>
<div class="mb-8">
<h2 class="text-xl sm:text-2xl font-semibold">快速开始</h2>
<p class="mb-4 text-sm sm:text-base">准备开始了吗按照以下步骤启动你的第一个 HuLa 项目:</p>
<div class="space-y-6">
<h3 class="text-base sm:text-lg font-medium mb-3">第一步克隆项目</h3>
<div class="not-prose bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
<div class="flex flex-col gap-4">
<div class="relative">
<div class="bg-gray-100 dark:bg-gray-900 p-2 rounded pr-10 text-xs sm:text-sm overflow-x-auto">
Gitee: {{ commands.clone.gitee }}
</div>
<button
@click="copyLink(commands.clone.gitee)"
class="absolute top-2 right-2 text-gray-500 hover:text-teal-600 transition-colors">
<Icon name="ph:copy-simple-fill" class="w-4 h-4 sm:w-5 sm:h-5" />
</button>
</div>
<p class="text-center text-sm">或者</p>
<div class="relative">
<div class="bg-gray-100 dark:bg-gray-900 p-2 rounded pr-10 text-xs sm:text-sm overflow-x-auto">
GitHub: {{ commands.clone.github }}
</div>
<button
@click="copyLink(commands.clone.github)"
class="absolute top-2 right-2 text-gray-500 hover:text-teal-600 transition-colors">
<Icon name="ph:copy-simple-fill" class="w-4 h-4 sm:w-5 sm:h-5" />
</button>
</div>
</div>
</div>
<h3 class="text-base sm:text-lg font-medium mb-3">第二步进入项目目录</h3>
<div class="not-prose bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
<div class="relative">
<div class="bg-gray-100 dark:bg-gray-900 p-2 rounded pr-10 text-xs sm:text-sm overflow-x-auto">
{{ commands.directory }}
</div>
<button
@click="copyLink(commands.directory)"
class="absolute top-2 right-2 text-gray-500 hover:text-teal-600 transition-colors">
<Icon name="ph:copy-simple-fill" class="w-4 h-4 sm:w-5 sm:h-5" />
</button>
</div>
</div>
<h3 class="text-base sm:text-lg font-medium mb-3">第三步安装依赖</h3>
<div class="not-prose bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
<PackageManagerTabs v-model:manager="activeManager" @copy="copyCommand(commands[activeManager].install)">
<template #default="{ activeManager }">
<div>
<div
v-if="activeManager === 'pnpm'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.pnpm.install }}
</div>
<div
v-if="activeManager === 'bun'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.bun.install }}
</div>
</div>
</template>
</PackageManagerTabs>
</div>
<h3 class="text-base sm:text-lg font-medium mb-3">第四步启动项目</h3>
<div class="not-prose bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
<PackageManagerTabs v-model:manager="activeManager" @copy="copyCommand(commands[activeManager].dev)">
<template #default="{ activeManager }">
<div>
<div
v-if="activeManager === 'pnpm'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.pnpm.dev }}
</div>
<div
v-if="activeManager === 'bun'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.bun.dev }}
</div>
</div>
</template>
</PackageManagerTabs>
</div>
<h3 class="text-base sm:text-lg font-medium mb-3">后续(可操作)打包项目</h3>
<div class="not-prose bg-gray-50 dark:bg-gray-800 rounded-lg p-4">
<PackageManagerTabs v-model:manager="activeManager" @copy="copyCommand(commands[activeManager].build)">
<template #default="{ activeManager }">
<div>
<div
v-if="activeManager === 'pnpm'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.pnpm.build }}
</div>
<div
v-if="activeManager === 'bun'"
class="bg-gray-100 dark:bg-gray-900 p-2 rounded text-xs sm:text-sm overflow-x-auto">
{{ commands.bun.build }}
</div>
</div>
</template>
</PackageManagerTabs>
</div>
</div>
</div>
<div class="mb-8">
<h2 class="text-xl sm:text-2xl font-semibold">为什么选择 HuLa</h2>
<p class="text-sm sm:text-base">
HuLa 将现代 Web 开发的最佳实践与直观的开发体验相结合无论你是构建小型应用还是大型项目HuLa
都能为你提供所需的工具和结构支持助你取得成功
</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
useSeoMeta({
title: 'introduction · 介绍'
})
</script>
<style scoped lang="scss"></style>
<script setup lang="ts">
definePageMeta({
layout: 'custom'
})
useSeoMeta({
title: '产品介绍 · HuLa',
description: '开始使用 HuLa - 用于构建高效、可扩展应用程序的现代 Web 开发框架'
})
const activeManager = ref('pnpm')
const commands = {
clone: {
gitee: 'git clone https://gitee.com/HuLaSpark/HuLa',
github: 'git clone https://github.com/HuLaSpark/HuLa'
},
directory: 'cd HuLa',
pnpm: {
install: 'pnpm install',
dev: 'pnpm run tauri:dev',
build: 'pnpm run tauri:build'
},
bun: {
install: 'bun install',
dev: 'bun tauri:dev',
build: 'bun tauri:build'
}
} as any
const copyLink = (command: string) => {
navigator.clipboard
.writeText(command)
.then(() => {
console.log(`Copied: ${command}`)
})
.catch((err) => {
console.error('Failed to copy: ', err)
})
}
const copyCommand = (command: string) => {
navigator.clipboard
.writeText(command)
.then(() => {
console.log(`Copied: ${command}`)
})
.catch((err) => {
console.error('Failed to copy: ', err)
})
}
</script>

View File

@@ -1,310 +1,292 @@
<template>
<main class="min-h-[calc(100vh-var(--header-height))] relative bg-[#f8fafc] dark:bg-[#111729]">
<img
class="pointer-events-none absolute w-full top-[1px] text-teal flex-shrink-0 z-10"
src="/assets/svg/header.svg"
alt="" />
<PageBackground>
<!-- 首页介绍 -->
<div class="bg-[#f8fafc] dark:bg-[#111729] min-h-screen relative overflow-hidden">
<div class="absolute inset-0">
<div
class="absolute inset-0 bg-gradient-to-b from-[#f8fafc] via-[#e2e8f0] to-[#f8fafc] dark:from-[#111729] dark:via-[#0c1322] dark:to-[#111729] opacity-60 dark:opacity-80"></div>
<div
class="absolute inset-0 bg-[url('/assets/svg/grid-light.svg')] dark:bg-[url('/assets/svg/grid.svg')] bg-center [mask-image:linear-gradient(180deg,white,rgba(255,255,255,0))]">
<div class="photon-effect light-photon dark:dark-photon"></div>
<div class="photon-effect light-photon dark:dark-photon delay-2"></div>
<div class="photon-effect light-photon dark:dark-photon delay-4"></div>
</div>
</div>
<div class="relative pt-20 pb-16 sm:pb-24 lg:pb-32">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<!-- Hero Section -->
<div class="text-center relative z-[1]">
<div class="mb-8 animate-fade-in">
<NuxtLink to="https://github.com/HuLaSpark/HuLa" target="_blank" rel="noopener noreferrer">
<span
class="inline-flex items-center text-sm px-3 py-1.5 bg-teal-50 dark:bg-teal-400/10 text-teal-500 dark:text-teal-400 ring-1 ring-inset ring-teal-500/25 dark:ring-teal-400/25 rounded-full font-semibold transition hover:bg-teal-100 dark:hover:bg-teal-400/15">
<span>HuLa {{ config.MasterVersion }} 现已发布</span>
<UIcon name="solar:arrow-right-line-duotone" class="w-5 h-5 ml-1" />
</span>
</NuxtLink>
</div>
<div class="relative pt-20 pb-16 sm:pb-24 lg:pb-32">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<!-- Hero Section -->
<div class="text-center relative z-[1]">
<div class="mb-8 animate-fade-in">
<NuxtLink to="https://github.com/HuLaSpark/HuLa" target="_blank" rel="noopener noreferrer">
<span
class="inline-flex items-center text-sm px-3 py-1.5 bg-teal-50 dark:bg-teal-400/10 text-teal-500 dark:text-teal-400 ring-1 ring-inset ring-teal-500/25 dark:ring-teal-400/25 rounded-full font-semibold transition hover:bg-teal-100 dark:hover:bg-teal-400/15">
<span>HuLa {{ config.MasterVersion }} 现已发布</span>
<UIcon name="solar:arrow-right-line-duotone" class="w-5 h-5 ml-1" />
</span>
</NuxtLink>
</div>
<h1 class="text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl lg:text-7xl mb-6">
<span class="block">高度集成的</span>
<span class="block mt-2 text-teal-600 dark:text-teal-500">IM 框架</span>
</h1>
<h1 class="text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl lg:text-7xl mb-6">
<span class="block">高度集成的</span>
<span class="block mt-2 text-teal-600 dark:text-teal-500">IM 框架</span>
</h1>
<p class="mx-auto max-w-2xl text-lg text-gray-600 dark:text-gray-300 leading-relaxed mb-2">
HuLa 是一款
<a
href="https://github.com/HuLaSpark/HuLa"
target="_blank"
rel="noopener noreferrer"
class="text-teal-600 dark:text-teal-400 hover:underline">
开源的即时通讯应用程序
</a>
功能更全面和强大
</p>
<p class="mx-auto max-w-2xl text-lg text-gray-600 dark:text-gray-300 leading-relaxed mb-2">
HuLa 是一款
<a
href="https://github.com/HuLaSpark/HuLa"
target="_blank"
rel="noopener noreferrer"
class="text-teal-600 dark:text-teal-400 hover:underline">
开源的即时通讯应用程序
</a>
功能更全面和强大
</p>
<p class="mx-auto max-w-2xl text-lg text-gray-600 dark:text-gray-300 leading-relaxed">
可集成更多应用插件满足各种应用场景
</p>
<p class="mx-auto max-w-2xl text-lg text-gray-600 dark:text-gray-300 leading-relaxed">
可集成更多应用插件满足各种应用场景
</p>
<!-- CTA Buttons -->
<div class="mt-10 flex flex-wrap items-center justify-center gap-6">
<a
href="/docs/getting-started/introduction"
class="inline-flex items-center px-6 py-3 rounded-lg bg-teal-500 text-white hover:bg-teal-600 transition shadow-lg shadow-teal-500/20">
<span class="font-medium">开始使用</span>
<UIcon name="solar:arrow-right-linear" class="w-5 h-5 ml-2" />
</a>
<div v-if="!isMobile" class="hidden md:block">
<!-- Mac下载按钮 -->
<UPopover v-if="system === 'mac'" v-model:open="panelVisible" mode="hover">
<div class="flex items-center gap-4">
<div
:class="{ 'text-teal-600': panelVisible }"
class="group flex items-center gap-2 text-sm bg-[#fefefe] w-fit px-6 py-2 rounded-md dark:bg-gray-800">
<svg class="size-6 group-hover:text-teal-600"><use href="#mac"></use></svg>
<span class="group-hover:text-teal-600">MacOS</span>
<UIcon
name="solar:alt-arrow-down-line-duotone"
:class="{ 'rotate-180': panelVisible }"
class="w-4 h-4 group-hover:text-teal-600 group-hover:rotate-180" />
</div>
<!-- CTA Buttons -->
<div class="mt-10 flex flex-wrap items-center justify-center gap-6">
<a
href="/docs/getting-started/introduction"
class="inline-flex items-center px-6 py-3 rounded-lg bg-teal-500 text-white hover:bg-teal-600 transition shadow-lg shadow-teal-500/20">
<span class="font-medium">开始使用</span>
<UIcon name="solar:arrow-right-linear" class="w-5 h-5 ml-2" />
</a>
<div v-if="!isMobile" class="hidden md:block">
<!-- Mac下载按钮 -->
<UPopover v-if="system === 'mac'" v-model:open="panelVisible" mode="hover">
<div class="flex items-center gap-4">
<div
:class="{ 'text-teal-600': panelVisible }"
class="group flex items-center gap-2 text-sm bg-[#fefefe] w-fit px-6 py-2 rounded-md dark:bg-gray-800">
<svg class="size-6 group-hover:text-teal-600"><use href="#mac"></use></svg>
<span class="group-hover:text-teal-600">MacOS</span>
<UIcon
name="solar:alt-arrow-down-line-duotone"
:class="{ 'rotate-180': panelVisible }"
class="w-4 h-4 group-hover:text-teal-600 group-hover:rotate-180" />
</div>
</div>
<template #panel>
<div class="p-2 flex flex-col gap-2">
<a
v-for="(item, index) in macDownloads"
:key="index"
class="flex items-center gap-4 py-1 px-2 box-border rounded-md hover:bg-gray-100 hover:dark:bg-gray-800"
rel="noopener noreferrer"
:href="item.url">
<svg class="size-4 flex-shrink-0"><use href="#to-bottom"></use></svg>
<p class="text-end w-full">{{ item.label }}</p>
</a>
</div>
</template>
</UPopover>
<!-- Windows下载按钮 -->
<template v-if="system === 'windows'">
<div class="flex items-center gap-4">
<template #panel>
<div class="p-2 flex flex-col gap-2">
<a
class="group flex items-center gap-2 text-sm bg-[#fefefe] w-fit px-6 py-2 rounded-md dark:bg-gray-800"
v-for="(item, index) in macDownloads"
:key="index"
class="flex items-center gap-4 py-1 px-2 box-border rounded-md hover:bg-gray-100 hover:dark:bg-gray-800"
rel="noopener noreferrer"
:href="windowsDownload.url">
<svg class="size-6 group-hover:text-teal-600"><use href="#windows"></use></svg>
<span class="group-hover:text-teal-600">Windows</span>
:href="item.url">
<svg class="size-4 flex-shrink-0"><use href="#to-bottom"></use></svg>
<p class="text-end w-full">{{ item.label }}</p>
</a>
</div>
</template>
</div>
<div v-else class="text-center py-4 text-gray-500">移动端版本敬请期待</div>
</UPopover>
<!-- Windows下载按钮 -->
<template v-if="system === 'windows'">
<div class="flex items-center gap-4">
<a
class="group flex items-center gap-2 text-sm bg-[#fefefe] w-fit px-6 py-2 rounded-md dark:bg-gray-800"
rel="noopener noreferrer"
:href="windowsDownload.url">
<svg class="size-6 group-hover:text-teal-600"><use href="#windows"></use></svg>
<span class="group-hover:text-teal-600">Windows</span>
</a>
</div>
</template>
</div>
<div v-else class="text-center py-4 text-gray-500">移动端版本敬请期待</div>
</div>
</div>
<!-- Key Features -->
<div class="mt-32 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:chat-dots-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
即时通讯
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
支持文本图片语音等多种消息类型实现流畅的即时通讯体验基于 WebSocket
的实时通信确保消息的及时送达
</p>
</div>
<!-- Key Features -->
<div class="mt-32 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:chat-dots-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
即时通讯
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
支持文本图片语音等多种消息类型实现流畅的即时通讯体验基于 WebSocket
的实时通信确保消息的及时送达
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:shield-keyhole-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
安全可靠
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
采用端到端加密技术确保用户隐私和数据安全支持消息加密传输保护您的通信内容不被窃取
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:code-square-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
开源生态
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
完全开源支持自定义开发和扩展打造属于你的IM系统提供丰富的API接口方便与其他系统集成
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:widget-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
跨平台支持
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
支持 WindowsMacOS 等多个平台提供统一的用户体验基于 Tauri 构建确保应用性能和稳定性
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:user-plus-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
社区驱动
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
活跃的开发者社区持续提供功能更新和问题修复欢迎参与项目开发共同打造更好的即时通讯工具
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:settings-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
高度可定制
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
提供丰富的配置选项满足不同场景的需求支持主题定制插件扩展打造个性化的通讯工具
</p>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:shield-keyhole-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
安全可靠
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
采用端到端加密技术确保用户隐私和数据安全支持消息加密传输保护您的通信内容不被窃取
</p>
</div>
<!-- 图片 -->
<div class="mt-32 w-full flex items-center justify-center" @click="toggleImage">
<Transition name="fade" mode="out-in">
<img
v-if="showFirstImage"
key="first"
class="dark:hidden w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/1.png"
alt="" />
<img
v-else
key="second"
class="dark:hidden w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/3.png"
alt="" />
</Transition>
<Transition name="fade" mode="out-in">
<img
v-if="showFirstImage"
key="first-dark"
class="hidden dark:block w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/2.png"
alt="" />
<img
v-else
key="second-dark"
class="hidden dark:block w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/4.png"
alt="" />
</Transition>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:code-square-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
开源生态
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
完全开源支持自定义开发和扩展打造属于你的IM系统提供丰富的API接口方便与其他系统集成
</p>
</div>
<!-- Technical Features -->
<div class="mt-32 relative">
<!-- Background glow effect -->
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:widget-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
跨平台支持
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
支持 WindowsMacOS 等多个平台提供统一的用户体验基于 Tauri 构建确保应用性能和稳定性
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:user-plus-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
社区驱动
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
活跃的开发者社区持续提供功能更新和问题修复欢迎参与项目开发共同打造更好的即时通讯工具
</p>
</div>
<div
class="relative rounded-2xl border border-gray-200 dark:border-gray-800 p-8 hover:border-teal-500 dark:hover:border-teal-500 transition group">
<div class="absolute -top-4 left-4">
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-teal-500 text-white transform group-hover:scale-110 transition">
<UIcon name="solar:settings-bold" class="w-5 h-5" />
</span>
</div>
<h3
class="mt-4 text-xl font-semibold text-gray-900 dark:text-white group-hover:text-teal-500 dark:group-hover:text-teal-400 transition">
高度可定制
</h3>
<p class="mt-2 text-gray-600 dark:text-gray-400">
提供丰富的配置选项满足不同场景的需求支持主题定制插件扩展打造个性化的通讯工具
</p>
</div>
</div>
<!-- 图片 -->
<div class="mt-32 w-full flex items-center justify-center" @click="toggleImage">
<Transition name="fade" mode="out-in">
<img
v-if="showFirstImage"
key="first"
class="dark:hidden w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/1.png"
alt="" />
<img
v-else
key="second"
class="dark:hidden w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/3.png"
alt="" />
</Transition>
<Transition name="fade" mode="out-in">
<img
v-if="showFirstImage"
key="first-dark"
class="hidden dark:block w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/2.png"
alt="" />
<img
v-else
key="second-dark"
class="hidden dark:block w-full max-w-5xl aspect-auto md:aspect-[5xl] select-none cursor-pointer"
src="/assets/images/4.png"
alt="" />
</Transition>
</div>
<!-- Technical Features -->
<div class="mt-32 relative">
<!-- Background glow effect -->
<div
class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[400px] pointer-events-none">
<div
class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[400px] pointer-events-none">
<div
class="absolute inset-0 bg-gradient-to-r from-teal-500/30 to-blue-500/30 blur-[64px] opacity-20 animate-pulse"></div>
class="absolute inset-0 bg-gradient-to-r from-teal-500/30 to-blue-500/30 blur-[64px] opacity-20 animate-pulse"></div>
</div>
<div class="text-center mb-16 relative">
<h2 class="text-3xl font-bold text-gray-900 dark:text-white">技术特性</h2>
<p class="mt-4 text-lg text-gray-600 dark:text-gray-400">基于现代化技术栈提供强大的功能支持</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 relative">
<div
class="p-6 rounded-xl bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm group hover:scale-[1.02] transition duration-300 hover:shadow-xl">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<UIcon name="solar:server-bold" class="w-6 h-6 mr-2 text-teal-500" />
后端架构
</h3>
<ul class="space-y-3 text-gray-600 dark:text-gray-400">
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
基于 Spring Boot 的微服务架构
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
高性能的 WebSocket 服务
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
分布式消息队列支持
</li>
</ul>
</div>
<div class="text-center mb-16 relative">
<h2 class="text-3xl font-bold text-gray-900 dark:text-white">技术特性</h2>
<p class="mt-4 text-lg text-gray-600 dark:text-gray-400">基于现代化技术栈提供强大的功能支持</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 relative">
<div
class="p-6 rounded-xl bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm group hover:scale-[1.02] transition duration-300 hover:shadow-xl">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<UIcon name="solar:server-bold" class="w-6 h-6 mr-2 text-teal-500" />
后端架构
</h3>
<ul class="space-y-3 text-gray-600 dark:text-gray-400">
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
基于 Spring Boot 的微服务架构
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
高性能的 WebSocket 服务
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
分布式消息队列支持
</li>
</ul>
</div>
<div
class="p-6 rounded-xl bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm group hover:scale-[1.02] transition duration-300 hover:shadow-xl">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<UIcon name="solar:screencast-2-bold" class="w-6 h-6 mr-2 text-teal-500" />
客户端技术
</h3>
<ul class="space-y-3 text-gray-600 dark:text-gray-400">
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
Tauri + Vue3 + Typescript 构建
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
优雅的UI设计和交互体验
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
高效的消息处理机制
</li>
</ul>
</div>
<div
class="p-6 rounded-xl bg-white/50 dark:bg-gray-800/50 backdrop-blur-sm group hover:scale-[1.02] transition duration-300 hover:shadow-xl">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<UIcon name="solar:screencast-2-bold" class="w-6 h-6 mr-2 text-teal-500" />
客户端技术
</h3>
<ul class="space-y-3 text-gray-600 dark:text-gray-400">
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
Tauri + Vue3 + Typescript 构建
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
优雅的UI设计和交互体验
</li>
<li class="flex items-center">
<UIcon name="solar:check-circle-bold" class="w-5 h-5 mr-2 text-teal-500" />
高效的消息处理机制
</li>
</ul>
</div>
</div>
</div>
@@ -438,8 +420,8 @@
</div>
</div>
<!-- Community Section -->
<div class="mt-32 text-center px-4 sm:px-6">
<!-- 社区部分 -->
<div class="relative mt-32 text-center px-4 sm:px-6">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 dark:text-white">加入我们</h2>
<p class="mt-4 text-base sm:text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
HuLa
@@ -464,7 +446,7 @@
</div>
<!-- 页脚部分 -->
<footer class="mt-32 bg-[#f8fafc] dark:bg-gray-900 w-full">
<footer class="relative mt-32 bg-[#f8fafc] dark:bg-gray-900 w-full">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-12">
<!-- 联系方式 -->
<div class="flex items-start gap-8 mb-8">
@@ -526,7 +508,7 @@
</div>
</div>
</footer>
</main>
</PageBackground>
</template>
<script setup lang="ts">
import { useUserSystem } from '~/hooks/useUserSystem'
@@ -600,6 +582,7 @@ onUnmounted(() => {
</script>
<style scoped>
/** */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;

View File

@@ -0,0 +1 @@
<svg id="Bun" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 70"><title>Bun Logo</title><path id="Shadow" d="M71.09,20.74c-.16-.17-.33-.34-.5-.5s-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5-.33-.34-.5-.5A26.46,26.46,0,0,1,75.5,35.7c0,16.57-16.82,30.05-37.5,30.05-11.58,0-21.94-4.23-28.83-10.86l.5.5.5.5.5.5.5.5.5.5.5.5.5.5C19.55,65.3,30.14,69.75,42,69.75c20.68,0,37.5-13.48,37.5-30C79.5,32.69,76.46,26,71.09,20.74Z"/><g id="Body"><path id="Background" d="M73,35.7c0,15.21-15.67,27.54-35,27.54S3,50.91,3,35.7C3,26.27,9,17.94,18.22,13S33.18,3,38,3s8.94,4.13,19.78,10C67,17.94,73,26.27,73,35.7Z" style="fill:#fbf0df"/><path id="Bottom_Shadow" data-name="Bottom Shadow" d="M73,35.7a21.67,21.67,0,0,0-.8-5.78c-2.73,33.3-43.35,34.9-59.32,24.94A40,40,0,0,0,38,63.24C57.3,63.24,73,50.89,73,35.7Z" style="fill:#f6dece"/><path id="Light_Shine" data-name="Light Shine" d="M24.53,11.17C29,8.49,34.94,3.46,40.78,3.45A9.29,9.29,0,0,0,38,3c-2.42,0-5,1.25-8.25,3.13-1.13.66-2.3,1.39-3.54,2.15-2.33,1.44-5,3.07-8,4.7C8.69,18.13,3,26.62,3,35.7c0,.4,0,.8,0,1.19C9.06,15.48,20.07,13.85,24.53,11.17Z" style="fill:#fffefc"/><path id="Top" d="M35.12,5.53A16.41,16.41,0,0,1,29.49,18c-.28.25-.06.73.3.59,3.37-1.31,7.92-5.23,6-13.14C35.71,5,35.12,5.12,35.12,5.53Zm2.27,0A16.24,16.24,0,0,1,39,19c-.12.35.31.65.55.36C41.74,16.56,43.65,11,37.93,5,37.64,4.74,37.19,5.14,37.39,5.49Zm2.76-.17A16.42,16.42,0,0,1,47,17.12a.33.33,0,0,0,.65.11c.92-3.49.4-9.44-7.17-12.53C40.08,4.54,39.82,5.08,40.15,5.32ZM21.69,15.76a16.94,16.94,0,0,0,10.47-9c.18-.36.75-.22.66.18-1.73,8-7.52,9.67-11.12,9.45C21.32,16.4,21.33,15.87,21.69,15.76Z" style="fill:#ccbea7;fill-rule:evenodd"/><path id="Outline" d="M38,65.75C17.32,65.75.5,52.27.5,35.7c0-10,6.18-19.33,16.53-24.92,3-1.6,5.57-3.21,7.86-4.62,1.26-.78,2.45-1.51,3.6-2.19C32,1.89,35,.5,38,.5s5.62,1.2,8.9,3.14c1,.57,2,1.19,3.07,1.87,2.49,1.54,5.3,3.28,9,5.27C69.32,16.37,75.5,25.69,75.5,35.7,75.5,52.27,58.68,65.75,38,65.75ZM38,3c-2.42,0-5,1.25-8.25,3.13-1.13.66-2.3,1.39-3.54,2.15-2.33,1.44-5,3.07-8,4.7C8.69,18.13,3,26.62,3,35.7,3,50.89,18.7,63.25,38,63.25S73,50.89,73,35.7C73,26.62,67.31,18.13,57.78,13,54,11,51.05,9.12,48.66,7.64c-1.09-.67-2.09-1.29-3-1.84C42.63,4,40.42,3,38,3Z"/></g><g id="Mouth"><g id="Background-2" data-name="Background"><path d="M45.05,43a8.93,8.93,0,0,1-2.92,4.71,6.81,6.81,0,0,1-4,1.88A6.84,6.84,0,0,1,34,47.71,8.93,8.93,0,0,1,31.12,43a.72.72,0,0,1,.8-.81H44.26A.72.72,0,0,1,45.05,43Z" style="fill:#b71422"/></g><g id="Tongue"><path id="Background-3" data-name="Background" d="M34,47.79a6.91,6.91,0,0,0,4.12,1.9,6.91,6.91,0,0,0,4.11-1.9,10.63,10.63,0,0,0,1-1.07,6.83,6.83,0,0,0-4.9-2.31,6.15,6.15,0,0,0-5,2.78C33.56,47.4,33.76,47.6,34,47.79Z" style="fill:#ff6164"/><path id="Outline-2" data-name="Outline" d="M34.16,47a5.36,5.36,0,0,1,4.19-2.08,6,6,0,0,1,4,1.69c.23-.25.45-.51.66-.77a7,7,0,0,0-4.71-1.93,6.36,6.36,0,0,0-4.89,2.36A9.53,9.53,0,0,0,34.16,47Z"/></g><path id="Outline-3" data-name="Outline" d="M38.09,50.19a7.42,7.42,0,0,1-4.45-2,9.52,9.52,0,0,1-3.11-5.05,1.2,1.2,0,0,1,.26-1,1.41,1.41,0,0,1,1.13-.51H44.26a1.44,1.44,0,0,1,1.13.51,1.19,1.19,0,0,1,.25,1h0a9.52,9.52,0,0,1-3.11,5.05A7.42,7.42,0,0,1,38.09,50.19Zm-6.17-7.4c-.16,0-.2.07-.21.09a8.29,8.29,0,0,0,2.73,4.37A6.23,6.23,0,0,0,38.09,49a6.28,6.28,0,0,0,3.65-1.73,8.3,8.3,0,0,0,2.72-4.37.21.21,0,0,0-.2-.09Z"/></g><g id="Face"><ellipse id="Right_Blush" data-name="Right Blush" cx="53.22" cy="40.18" rx="5.85" ry="3.44" style="fill:#febbd0"/><ellipse id="Left_Bluch" data-name="Left Bluch" cx="22.95" cy="40.18" rx="5.85" ry="3.44" style="fill:#febbd0"/><path id="Eyes" d="M25.7,38.8a5.51,5.51,0,1,0-5.5-5.51A5.51,5.51,0,0,0,25.7,38.8Zm24.77,0A5.51,5.51,0,1,0,45,33.29,5.5,5.5,0,0,0,50.47,38.8Z" style="fill-rule:evenodd"/><path id="Iris" d="M24,33.64a2.07,2.07,0,1,0-2.06-2.07A2.07,2.07,0,0,0,24,33.64Zm24.77,0a2.07,2.07,0,1,0-2.06-2.07A2.07,2.07,0,0,0,48.75,33.64Z" style="fill:#fff;fill-rule:evenodd"/></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#cb3837" d="M2 38.5h124v43.71H64v7.29H36.44v-7.29H2zm6.89 36.43h13.78V53.07h6.89v21.86h6.89V45.79H8.89zm34.44-29.14v36.42h13.78v-7.28h13.78V45.79zm13.78 7.29H64v14.56h-6.89zm20.67-7.29v29.14h13.78V53.07h6.89v21.86h6.89V53.07h6.89v21.86h6.89V45.79z"/></svg>

After

Width:  |  Height:  |  Size: 330 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#f8ab00" d="M0 .004V40h39.996V.004Zm43.996 0V40h40V.004Zm44.008 0V40H128V.004Zm0 43.996v39.996H128V44Z"/><path fill="#4c4c4c" d="M43.996 44v39.996h40V44ZM0 87.996v40h39.996v-40Zm43.996 0v40h40v-40Zm44.008 0v40H128v-40Z"/></svg>

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"> <path fill="#2c8ebb" d="M64 0a64 64 0 1 0 64 64A64 64 0 0 0 64 0Zm4.685 21.948a5.037 5.037 0 0 1 2.21.802c.671.444 1.528 1.032 4.026 6.194a4.841 4.841 0 0 1 2.942-.103 3.933 3.933 0 0 1 2.468 2.004c2.55 4.893 2.889 13.614 1.774 19.22a34.89 34.89 0 0 1-6.028 13.74 26.56 26.56 0 0 1 5.957 9.733 26.24 26.24 0 0 1 1.456 10.746 29.626 29.626 0 0 0 3.22-1.796c3.158-1.951 7.927-4.894 13.615-4.966a6.834 6.834 0 0 1 7.225 5.885 6.555 6.555 0 0 1-5.046 7.256c-3.458.836-5.069 1.486-9.714 4.5a69.161 69.161 0 0 1-16.062 7.412 8.991 8.991 0 0 1-3.758 1.828c-3.933.96-17.425 1.682-18.488 1.682h-.248c-4.13 0-6.47-1.28-7.73-2.621-3.51 1.755-8.052 1.03-11.355-.714a5.729 5.729 0 0 1-3.097-4.024 6.194 6.194 0 0 1 0-2.127 6.875 6.875 0 0 1-.816-1.032 16.908 16.908 0 0 1-2.333-10.386c.3-3.85 2.964-7.287 4.698-9.114A29.481 29.481 0 0 1 35.726 64a27.685 27.685 0 0 1 7.04-9.29c-1.703-2.87-3.436-7.288-1.754-11.789 1.208-3.21 2.199-4.996 4.377-5.76a7.06 7.06 0 0 0 2.59-1.383 18.22 18.22 0 0 1 12.243-5.843c.196-.495.423-1.033.671-1.508 1.652-3.51 3.406-5.48 5.46-6.193a5.037 5.037 0 0 1 2.332-.286zm-.558 3.697c-2.703.089-5.355 8.099-5.355 8.099a14.452 14.452 0 0 0-12.089 4.645 9.951 9.951 0 0 1-3.973 2.345c-.424.144-.94.122-2.22 3.58-1.961 5.234 3.345 11.16 3.345 11.16s-6.328 4.47-8.672 10.034a25.58 25.58 0 0 0-1.806 12.057s-4.5 3.901-4.788 7.927a13.285 13.285 0 0 0 1.826 8.083 2.003 2.003 0 0 0 2.714.94s-2.993 3.487-.196 4.963c2.55 1.331 6.844 2.065 9.115-.196 1.652-1.651 1.982-5.335 2.591-6.842.144-.351.64.588 1.115 1.032a10.323 10.323 0 0 0 1.403 1.032s-4.024 1.734-2.373 5.688c.547 1.31 2.498 2.145 5.688 2.125 1.187 0 14.203-.743 17.671-1.58a4.47 4.47 0 0 0 2.696-1.505 65.032 65.032 0 0 0 15.99-7.226c4.892-3.19 6.895-4.059 10.848-4.998 3.262-.774 3.045-5.83-1.28-5.758-4.48.052-8.402 2.363-11.716 4.427-6.193 3.83-9.29 3.583-9.29 3.583l-.105-.175c-.423-.692 1.983-6.896-.712-14.287-2.91-8.082-7.534-10.033-7.163-10.653 1.58-2.673 5.534-6.917 7.113-14.824.94-4.79.691-12.676-1.435-16.805-.393-.764-3.902 1.28-3.902 1.28s-3.283-7.319-4.201-7.907a1.442 1.442 0 0 0-.839-.244z" /> </svg>

After

Width:  |  Height:  |  Size: 2.1 KiB