This commit is contained in:
aaron 2025-05-09 14:46:08 +08:00
parent 30502d1c3e
commit e0f8cee288
4 changed files with 353 additions and 323 deletions

View File

@ -5,7 +5,7 @@ services:
build:
context: .
dockerfile: Dockerfile
image: tradus-web:1.0.13
image: tradus-web:1.0.14
container_name: tradus-web
ports:
- '6000:80'

View File

@ -7,6 +7,7 @@ const userStore = useUserStore()
const isAuthenticated = computed(() => userStore.isAuthenticated)
const userInfo = computed(() => userStore.userInfo)
const showMobileMenu = ref(false)
const showUserMenu = ref(false)
const handleLogout = () => {
userStore.logout()
@ -14,18 +15,27 @@ const handleLogout = () => {
window.location.href = '/'
}
showMobileMenu.value = false
showUserMenu.value = false
}
const toggleMobileMenu = () => {
showMobileMenu.value = !showMobileMenu.value
}
const toggleUserMenu = (event: Event) => {
event.stopPropagation()
showUserMenu.value = !showUserMenu.value
}
//
const closeMenus = (event: MouseEvent) => {
const target = event.target as HTMLElement
if (!target.closest('.mobile-menu') && !target.closest('.menu-button')) {
showMobileMenu.value = false
}
if (!target.closest('.user-info-box') && !target.closest('.user-menu')) {
showUserMenu.value = false
}
}
onMounted(() => {
@ -99,13 +109,42 @@ onUnmounted(() => {
<!-- 桌面端用户信息 -->
<div class="desktop-user-info" v-if="isAuthenticated">
<div class="user-info-box">
<div class="user-info-box" @click.stop="toggleUserMenu" :aria-expanded="showUserMenu">
<div class="user-avatar">
<span>{{ userInfo?.nickname?.charAt(0) || 'U' }}</span>
</div>
<span class="user-nickname">{{ userInfo?.nickname }}</span>
<svg
class="dropdown-icon"
viewBox="0 0 24 24"
width="16"
height="16"
stroke="currentColor"
stroke-width="2"
fill="none"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</div>
<!-- 用户菜单 -->
<div class="user-menu" v-if="showUserMenu" @click.stop>
<button class="menu-item" @click="handleLogout">
<svg
class="menu-icon"
viewBox="0 0 24 24"
width="16"
height="16"
stroke="currentColor"
stroke-width="2"
fill="none"
>
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" y1="12" x2="9" y2="12" />
</svg>
退出登录
</button>
</div>
<button class="logout-button" @click="handleLogout">退出登录</button>
</div>
<div class="desktop-user-info" v-else>
<RouterLink to="/login" class="auth-link">登录</RouterLink>
@ -114,13 +153,42 @@ onUnmounted(() => {
<!-- 移动端用户信息 -->
<div class="mobile-user-info" v-if="isAuthenticated">
<div class="user-info-box">
<div class="user-info-box" @click.stop="toggleUserMenu" :aria-expanded="showUserMenu">
<div class="user-avatar">
<span>{{ userInfo?.nickname?.charAt(0) || 'U' }}</span>
</div>
<span class="user-nickname">{{ userInfo?.nickname }}</span>
<svg
class="dropdown-icon"
viewBox="0 0 24 24"
width="16"
height="16"
stroke="currentColor"
stroke-width="2"
fill="none"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</div>
<!-- 用户菜单 -->
<div class="user-menu mobile" v-if="showUserMenu" @click.stop>
<button class="menu-item" @click="handleLogout">
<svg
class="menu-icon"
viewBox="0 0 24 24"
width="16"
height="16"
stroke="currentColor"
stroke-width="2"
fill="none"
>
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" y1="12" x2="9" y2="12" />
</svg>
退出登录
</button>
</div>
<button class="logout-button" @click="handleLogout">退出登录</button>
</div>
<div class="mobile-user-info" v-else>
<RouterLink to="/login" class="mobile-auth-link" @click="showMobileMenu = false"
@ -365,15 +433,15 @@ body {
/* 用户菜单样式 */
.user-menu {
position: absolute;
bottom: 100%;
right: 0;
margin-bottom: 0.5rem;
background-color: var(--color-bg-elevated);
bottom: calc(100% - 0.5rem);
right: 1.25rem;
background-color: var(--color-bg-primary);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
min-width: 120px;
min-width: 140px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 1100;
}
.menu-item {
@ -385,11 +453,15 @@ body {
font-size: 0.9rem;
text-align: left;
cursor: pointer;
transition: background-color 0.2s ease;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.menu-item:hover {
background-color: var(--color-bg-secondary);
background-color: var(--color-bg-hover);
color: var(--color-accent);
}
/* 移动端适配 */
@ -547,6 +619,59 @@ body {
padding: 1rem;
border-top: 1px solid var(--color-border);
margin-top: auto;
background-color: var(--color-bg-primary);
position: relative;
z-index: 1100;
}
.mobile-user-info .user-info-box {
display: flex;
align-items: center;
gap: 1rem;
cursor: pointer;
padding: 0.75rem;
border-radius: var(--border-radius);
transition: all 0.2s ease;
}
.mobile-user-info .user-info-box:hover {
background-color: var(--color-bg-hover);
}
.mobile-user-info .user-avatar {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
background: var(--color-bg-hover);
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
color: var(--color-accent);
font-weight: bold;
box-shadow: 0 2px 8px rgba(51, 85, 255, 0.2);
}
.mobile-user-info .user-nickname {
font-size: 1rem;
font-weight: var(--font-weight-medium);
color: var(--color-text-primary);
flex: 1;
}
/* 移动端用户菜单样式 */
.user-menu.mobile {
position: absolute;
bottom: 100%;
left: 1rem;
right: 1rem;
margin-bottom: 0.5rem;
background-color: var(--color-bg-primary);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
z-index: 1100;
}
.mobile-auth-link {
@ -558,32 +683,39 @@ body {
transition: all 0.2s ease;
text-align: center;
margin: 0.5rem 0;
background-color: var(--color-bg-secondary);
background-color: var(--color-bg-hover);
}
.mobile-auth-link:hover {
background-color: var(--color-bg-elevated);
}
.logout-button {
display: block;
width: 100%;
padding: 0.75rem 1rem;
margin-top: 1rem;
background-color: var(--color-bg-hover);
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: var(--border-radius);
color: var(--color-text-primary);
cursor: pointer;
transition: all 0.2s ease;
}
.logout-button:hover {
background-color: var(--color-bg-active);
border-color: var(--color-accent);
color: var(--color-accent);
}
/* 箭头动画 */
.mobile-user-info .dropdown-icon {
color: var(--color-text-secondary);
transition: transform 0.2s ease;
}
.mobile-user-info .user-info-box:hover .dropdown-icon {
color: var(--color-text-primary);
}
.mobile-user-info .user-info-box[aria-expanded='true'] .dropdown-icon {
transform: rotate(180deg);
}
@media (max-width: 768px) {
.mobile-user-info {
display: block;
}
/* 移除旧的退出按钮样式 */
.logout-button {
display: none;
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.menu-button {
@ -600,8 +732,8 @@ body {
max-width: 300px;
z-index: 1002;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
background-color: var(--color-bg-elevated);
box-shadow: 4px 0 16px rgba(0, 0, 0, 0.1);
background-color: var(--color-bg-primary);
box-shadow: none;
transform: translateX(0);
opacity: 0;
}
@ -609,16 +741,45 @@ body {
.sidebar-open {
left: 0;
opacity: 1;
box-shadow: 6px 0 25px rgba(0, 0, 0, 0.15);
}
.sidebar-overlay {
display: block;
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
z-index: 1000;
backdrop-filter: blur(2px);
opacity: 0;
transition: opacity 0.3s ease;
}
.sidebar-overlay.sidebar-open {
display: block;
opacity: 1;
}
.chat-container {
margin-left: 0;
padding-top: 4rem;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 当侧栏打开时,主内容区域右移并添加阴影效果 */
.sidebar-open + .sidebar-overlay + .chat-container {
transform: translateX(16px);
filter: brightness(0.95);
}
.mobile-user-info {
display: block;
animation: slideUp 0.3s ease;
background-color: var(--color-bg-primary);
border-top: 1px solid rgba(0, 0, 0, 0.06);
}
@keyframes slideUp {
@ -636,11 +797,6 @@ body {
display: none;
}
.chat-container {
margin-left: 0;
padding-top: 4rem;
}
.agent-item {
transform: translateX(-10px);
opacity: 0;
@ -675,13 +831,22 @@ body {
margin-top: auto;
border-top: 1px solid rgba(0, 0, 0, 0.06);
background-color: var(--color-bg-secondary);
position: relative;
z-index: 1100;
}
.desktop-user-info .user-info-box {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 1rem;
cursor: pointer;
padding: 0.5rem;
border-radius: var(--border-radius);
transition: all 0.2s ease;
}
.desktop-user-info .user-info-box:hover {
background-color: var(--color-bg-hover);
}
.desktop-user-info .user-avatar {
@ -703,8 +868,23 @@ body {
font-size: 1rem;
font-weight: var(--font-weight-medium);
color: var(--color-text-primary);
flex: 1;
}
.dropdown-icon {
color: var(--color-text-secondary);
transition: transform 0.2s ease;
}
.user-info-box:hover .dropdown-icon {
color: var(--color-text-primary);
}
.user-info-box[aria-expanded='true'] .dropdown-icon {
transform: rotate(180deg);
}
/* 登录注册链接样式 */
.desktop-user-info .auth-link {
display: block;
padding: 0.75rem 1rem;
@ -722,25 +902,6 @@ body {
color: var(--color-accent);
}
.desktop-user-info .logout-button {
display: block;
width: 100%;
padding: 0.75rem 1rem;
background-color: var(--color-bg-hover);
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: var(--border-radius);
color: var(--color-text-primary);
cursor: pointer;
transition: all 0.2s ease;
font-size: 0.95rem;
}
.desktop-user-info .logout-button:hover {
background-color: var(--color-bg-active);
border-color: var(--color-accent);
color: var(--color-accent);
}
/* 移动端适配 */
@media (max-width: 768px) {
.desktop-user-info {

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, nextTick, computed, onMounted, watch, onUnmounted } from 'vue'
import { ref, nextTick, computed, onMounted, watch } from 'vue'
import { useUserStore } from '../stores/user'
import { marked } from 'marked'
@ -71,10 +71,8 @@ const fetchAgents = async () => {
const data = await response.json()
agents.value = data.map((agent: AgentResponse) => ({
...agent,
icon: '📊', // agent
}))
// Agent
if (agents.value.length > 0 && !selectedAgent.value) {
selectedAgent.value = agents.value[0]
addInitialGreeting(agents.value[0])
@ -305,38 +303,30 @@ const sendMessage = async () => {
}
}
//
const showAgentMenu = ref(false)
//
const toggleAgentMenu = () => {
showAgentMenu.value = !showAgentMenu.value
}
// Agent
const selectAgent = (agent: Agent) => {
selectedAgent.value = agent
showAgentMenu.value = false
}
//
const closeAgentMenu = (event: MouseEvent) => {
const target = event.target as HTMLElement
if (!target.closest('.agent-selector')) {
showAgentMenu.value = false
}
// script
const getAgentIcon = (agent: Agent) => {
// agent SVG
return `<svg class="agent-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
${getIconPath(agent)}
</svg>`
}
onMounted(() => {
if (isAuthenticated.value) {
fetchAgents()
const getIconPath = (agent: Agent) => {
// agent id
switch (agent.id) {
case 'market_analysis':
return '<path d="M7 12l5-5 5 5M7 17l5-5 5 5"/>'
case 'trading_strategy':
return '<path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1zM4 22v-7"/>'
default:
return '<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line"/>'
}
}
document.addEventListener('click', closeAgentMenu)
})
onUnmounted(() => {
document.removeEventListener('click', closeAgentMenu)
})
</script>
<template>
@ -379,6 +369,25 @@ onUnmounted(() => {
</div>
</div>
<!-- Agent 选择器移到这里 -->
<div class="agent-selector">
<div class="agent-list">
<div v-if="isLoadingAgents" class="agent-loading">加载中...</div>
<template v-else>
<button
v-for="agent in agents"
:key="agent.id"
class="agent-item"
:class="{ active: selectedAgent?.id === agent.id }"
@click="selectAgent(agent)"
>
<span class="agent-icon" v-html="getAgentIcon(agent)"></span>
<span class="agent-name">{{ agent.name }}</span>
</button>
</template>
</div>
</div>
<div class="input-container">
<div class="input-wrapper">
<textarea
@ -399,32 +408,6 @@ onUnmounted(() => {
</div>
</div>
</div>
<!-- 添加新的 Agent 选择器 -->
<div class="agent-selector">
<button class="agent-selector-button" @click="toggleAgentMenu">
<span class="agent-icon">{{ selectedAgent?.icon || '🤖' }}</span>
<span class="agent-name">{{ selectedAgent?.name || '选择 Agent' }}</span>
</button>
<div v-if="showAgentMenu" class="agent-selector-menu">
<div v-if="isLoadingAgents" class="agent-loading">加载中...</div>
<template v-else>
<div
v-for="agent in agents"
:key="agent.id"
class="agent-menu-item"
:class="{ active: selectedAgent?.id === agent.id }"
@click="selectAgent(agent)"
>
<div class="agent-icon">{{ agent.icon }}</div>
<div class="agent-info">
<div class="agent-name">{{ agent.name }}</div>
<div class="agent-description">{{ agent.description }}</div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
@ -684,7 +667,7 @@ onUnmounted(() => {
}
.input-container {
padding: 1.5rem 2rem;
padding: 0.5rem 0.5rem 5.5rem 0.5rem;
background-color: var(--color-bg-primary);
width: 100%;
max-width: 900px;
@ -732,7 +715,7 @@ onUnmounted(() => {
.send-button {
position: absolute;
right: 0.75rem;
bottom: 0.75rem;
bottom: 0.5rem;
width: 2rem;
height: 2rem;
display: flex;
@ -819,217 +802,92 @@ onUnmounted(() => {
text-decoration: underline;
}
/* 添加新的 Agent 选择器样式 */
/* 修改 Agent 选择器样式 */
.agent-selector {
position: absolute;
top: 1rem;
right: 1rem;
z-index: 10;
/* padding: 1rem 2rem; */
background-color: #ffffff;
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.agent-selector-button {
.agent-list {
display: flex;
flex-direction: row;
gap: 0.75rem;
padding: 0.75rem;
overflow-x: auto;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE and Edge */
}
.agent-list::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
.agent-item {
display: inline-flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1.25rem;
background-color: #ffffff;
border: 1px solid rgba(51, 85, 255, 0.2);
border-radius: 12px;
padding: 0.75rem 1rem;
background-color: var(--color-bg-secondary);
border: 1px solid rgba(51, 85, 255, 0.15);
border-radius: 8px;
color: var(--color-text-primary);
cursor: pointer;
transition: all 0.2s ease;
white-space: nowrap;
font-size: 0.95rem;
font-weight: 500;
box-shadow: 0 2px 8px rgba(51, 85, 255, 0.08);
min-width: 160px;
min-width: 120px;
width: fit-content;
justify-content: flex-start;
flex-shrink: 0;
}
.agent-selector-button:hover {
.agent-item:hover {
border-color: var(--color-accent);
background-color: rgba(51, 85, 255, 0.04);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(51, 85, 255, 0.12);
}
.agent-selector-button .agent-icon {
font-size: 1.25rem;
color: var(--color-accent);
.agent-item.active {
background-color: var(--color-accent);
border-color: var(--color-accent);
color: #ffffff;
}
.agent-selector-button .agent-name {
font-size: 0.95rem;
color: var(--color-text-primary);
flex: 1;
.agent-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
stroke: currentColor;
}
.agent-selector-button::after {
content: '▼';
font-size: 0.8rem;
color: var(--color-accent);
opacity: 0.8;
transition: transform 0.2s ease;
.agent-item.active .agent-icon {
stroke: #ffffff;
}
.agent-selector-menu {
position: absolute;
top: calc(100% + 0.5rem);
right: 0;
background-color: #ffffff;
border: 1px solid rgba(51, 85, 255, 0.15);
border-radius: 12px;
min-width: 280px;
max-width: 320px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(51, 85, 255, 0.15);
animation: slideDown 0.2s ease;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.agent-menu-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem;
cursor: pointer;
transition: all 0.2s ease;
border-bottom: 1px solid rgba(51, 85, 255, 0.08);
background-color: #ffffff;
}
.agent-menu-item:last-child {
border-bottom: none;
}
.agent-menu-item:hover {
background-color: rgba(51, 85, 255, 0.04);
}
.agent-menu-item.active {
background-color: rgba(51, 85, 255, 0.08);
}
.agent-menu-item .agent-icon {
font-size: 1.5rem;
color: var(--color-accent);
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(51, 85, 255, 0.08);
border-radius: 8px;
}
.agent-menu-item .agent-info {
flex: 1;
min-width: 0;
}
.agent-menu-item .agent-name {
font-weight: 600;
color: var(--color-text-primary);
margin-bottom: 0.25rem;
font-size: 0.95rem;
}
.agent-menu-item .agent-description {
font-size: 0.85rem;
color: var(--color-text-secondary);
line-height: 1.4;
.agent-name {
text-align: left;
}
.agent-loading {
padding: 1rem;
padding: 0.75rem;
text-align: center;
color: var(--color-text-secondary);
}
/* 移动端适配 */
@media (max-width: 768px) {
.ai-agent-view {
height: 100%;
.agent-list {
padding: 0.5rem;
gap: 0.5rem;
}
.main-container {
height: 100%;
padding-bottom: env(safe-area-inset-bottom);
}
.messages-container {
padding: 1rem 0.5rem;
padding-bottom: calc(5rem + env(safe-area-inset-bottom));
}
.input-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 0.75rem;
padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));
background-color: var(--color-bg-elevated);
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
z-index: 100;
border-top: 1px solid var(--color-border);
}
.input-wrapper {
max-width: 900px;
margin: 0 auto;
}
.message-input {
font-size: 16px; /* 防止 iOS 自动缩放 */
padding: 0.6rem 2.5rem 0.6rem 0.75rem;
min-height: 2.5rem;
height: 2.5rem;
}
.send-button {
width: 1.8rem;
height: 1.8rem;
right: 0.5rem;
bottom: 0.35rem;
}
.send-icon {
font-size: 0.9rem;
}
.agent-selector {
top: 0.75rem;
right: 0.75rem;
}
.agent-selector-button {
.agent-item {
padding: 0.6rem 1rem;
min-width: 140px;
font-size: 0.9rem;
}
.agent-selector-menu {
min-width: 260px;
max-width: calc(100vw - 2rem);
right: -0.75rem;
}
.agent-menu-item {
padding: 0.875rem;
}
.agent-menu-item .agent-icon {
font-size: 1.25rem;
width: 28px;
height: 28px;
min-width: 100px;
}
}

View File

@ -11,8 +11,8 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
<div class="home-view">
<section class="hero-section">
<div class="hero-content">
<h1 class="hero-title"><span class="accent">Tradus</span></h1>
<p class="hero-subtitle">AI Agent for trading</p>
<h1 class="hero-title"><span class="accent">tradus</span></h1>
<p class="hero-subtitle">A intelligent trading assistant</p>
<div class="hero-actions">
<!-- 未登录状态显示登录和注册按钮 -->
<template v-if="!isAuthenticated">
@ -21,7 +21,7 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
</template>
</div>
<div class="discord-link">
<!-- <div class="discord-link">
<a href="https://discord.gg/8vMDD4kC" target="_blank" class="discord-text">
<svg class="discord-icon" viewBox="0 0 24 24" width="16" height="16">
<path
@ -31,7 +31,7 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
</svg>
加入Discord社区
</a>
</div>
</div> -->
</div>
</section>
</div>
@ -72,40 +72,51 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
}
.hero-title {
font-size: 5rem;
font-size: 1.8rem;
font-weight: 800;
margin-bottom: 1.5rem;
line-height: 1.1;
letter-spacing: -0.02em;
color: #3355ff;
margin-bottom: 0.3rem;
font-family:
'SF Pro Display',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
sans-serif;
letter-spacing: -0.5px;
display: block;
}
.accent {
position: relative;
display: inline-block;
}
.accent::after {
content: '';
position: absolute;
bottom: 8px;
left: 0;
width: 100%;
height: 12px;
background-color: rgba(51, 85, 255, 0.1);
z-index: -1;
border-radius: 6px;
opacity: 0.5;
transform: skewX(-12deg);
font-size: 2.5rem;
font-weight: 800;
background: linear-gradient(135deg, var(--color-accent) 0%, #2244ee 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
font-family:
'SF Pro Display',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
sans-serif;
}
.hero-subtitle {
font-size: 1.5rem;
color: #6c757d;
max-width: 700px;
margin: 0 auto 4rem;
letter-spacing: -0.01em;
font-size: 0.9rem;
color: var(--color-text-secondary);
font-weight: 400;
font-family:
'SF Pro Display',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
sans-serif;
letter-spacing: 0.5px;
text-transform: uppercase;
margin: 0 auto 4rem;
}
.hero-actions {
@ -193,7 +204,7 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
}
.hero-title {
font-size: 3.5rem;
font-size: 1.8rem;
}
.hero-subtitle {
@ -214,7 +225,7 @@ const isAuthenticated = computed(() => userStore.isAuthenticated)
}
.hero-title {
font-size: 2.75rem;
font-size: 1.5rem;
}
.hero-subtitle {