Initial commit: Set up Garmin Health Lab project structure

- Initialize monorepo with root workspace configuration
- Set up Express.js backend with TypeScript
- Set up React 18 frontend with TypeScript
- Create database schema with SQLite
- Implement project architecture and documentation
- Add development and deployment guidelines

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
ericwyuan
2026-08-23 11:11:29 +08:00
commit d73405decb
34 changed files with 1699 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
.layout {
display: flex;
flex-direction: column;
min-height: 100vh;
background-color: #f5f5f5;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 2rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.header-content {
max-width: 1400px;
margin: 0 auto;
}
.logo {
font-size: 1.8rem;
font-weight: bold;
margin-bottom: 0.5rem;
}
.tagline {
font-size: 0.9rem;
opacity: 0.9;
}
.container {
display: flex;
flex: 1;
max-width: 1400px;
width: 100%;
margin: 0 auto;
gap: 2rem;
padding: 2rem;
}
.sidebar {
width: 250px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
height: fit-content;
position: sticky;
top: 2rem;
}
.nav-list {
list-style: none;
padding: 0;
}
.nav-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 1.5rem;
text-decoration: none;
color: #333;
border-left: 3px solid transparent;
transition: all 0.3s ease;
}
.nav-link:hover {
background-color: #f5f5f5;
border-left-color: #667eea;
}
.nav-link.active {
background-color: #f0f0ff;
border-left-color: #667eea;
color: #667eea;
font-weight: 600;
}
.icon {
font-size: 1.2rem;
}
.label {
flex: 1;
}
.content {
flex: 1;
background: white;
border-radius: 8px;
padding: 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.footer {
text-align: center;
padding: 2rem;
color: #666;
font-size: 0.9rem;
border-top: 1px solid #eee;
}
@media (max-width: 768px) {
.container {
flex-direction: column;
padding: 1rem;
}
.sidebar {
width: 100%;
position: static;
}
.nav-list {
display: flex;
gap: 0.5rem;
overflow-x: auto;
}
.nav-link {
flex: 1;
min-width: 100px;
font-size: 0.9rem;
}
.logo {
font-size: 1.4rem;
}
}

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import './Layout.css';
interface LayoutProps {
children: React.ReactNode;
}
function Layout({ children }: LayoutProps) {
const location = useLocation();
const navigationItems = [
{ path: '/', label: '仪表板', icon: '📊' },
{ path: '/sync', label: '数据同步', icon: '🔄' },
{ path: '/analysis', label: '数据分析', icon: '📈' },
{ path: '/recommendations', label: '健康建议', icon: '💡' },
{ path: '/settings', label: '设置', icon: '⚙️' },
];
return (
<div className="layout">
<header className="header">
<div className="header-content">
<h1 className="logo">🏃 Garmin Health Lab</h1>
<p className="tagline"></p>
</div>
</header>
<div className="container">
<nav className="sidebar">
<ul className="nav-list">
{navigationItems.map(item => (
<li key={item.path}>
<Link
to={item.path}
className={`nav-link ${location.pathname === item.path ? 'active' : ''}`}
>
<span className="icon">{item.icon}</span>
<span className="label">{item.label}</span>
</Link>
</li>
))}
</ul>
</nav>
<main className="content">
{children}
</main>
</div>
<footer className="footer">
<p>© 2024 Garmin Health Lab. All rights reserved.</p>
</footer>
</div>
);
}
export default Layout;