diff --git a/.gitea/workflows/deploy-website.yaml b/.gitea/workflows/deploy-website.yaml new file mode 100644 index 0000000..b6f0a19 --- /dev/null +++ b/.gitea/workflows/deploy-website.yaml @@ -0,0 +1,27 @@ +name: Deploy Website to S3 + +on: + push: + branches: + - main + paths: + - 'website/**' + - '.gitea/workflows/deploy-website.yaml' + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Sync to S3 + uses: https://github.com/jakejarvis/s3-sync-action@master + with: + args: --acl public-read --follow-symlinks --delete + env: + AWS_S3_BUCKET: ${{ secrets.S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.S3_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }} + AWS_S3_ENDPOINT: ${{ secrets.S3_ENDPOINT }} + SOURCE_DIR: 'website' diff --git a/website/assets/hero.png b/website/assets/hero.png new file mode 100644 index 0000000..6e9ef14 Binary files /dev/null and b/website/assets/hero.png differ diff --git a/website/index.html b/website/index.html new file mode 100644 index 0000000..9af9072 --- /dev/null +++ b/website/index.html @@ -0,0 +1,193 @@ + + + + + + Strava MCP Server | Modern Training Data Access + + + +
+ +
+ + +
+ Futuristic Background +

Empower your AI with Strava Data.

+

A production-ready Model Context Protocol (MCP) server that exposes the Strava API for AI agents and LLMs.

+ +
+ +
+
+

Features

+

Comprehensive access to your training data through standardized MCP tools.

+
+
+
+ 👤 +

Athlete Profiles

+

Detailed profiles, heart rate zones, and power stats for personalized analysis.

+
+
+ 🚴 +

Activity Deep-Dive

+

Access laps, streams, comments, and detailed segment efforts.

+
+
+ 📍 +

Segments & Routes

+

Explore popular segments and your saved routes with all metadata.

+
+
+ ⚙️ +

Hardware Tracking

+

Manage your equipment and track the mileage of your bikes and shoes.

+
+
+
+ +
+
+

Dual-Output Architecture

+

Optimized for both humans and machines. Every tool delivers two outputs:

+
+
    +
  • User Content: Formatted markdown for an aesthetic display in the chat.
  • +
  • Assistant Resource: Structured JSON for precise data processing by the LLM.
  • +
+
+
+
+
+
+
+
+
+
+// JSON Resource for Assistant
+{
+  "id": "12345678",
+  "name": "Morning Ride",
+  "distance": "45200",
+  "moving_time": "5400",
+  "audience": ["assistant"]
+}
+
+
+
+ +
+

Quick Start

+

Start the server locally with a single command via UV.

+
+ $ uv run strava-mcp-server +
+
+ + +
+ + + + diff --git a/website/style.css b/website/style.css new file mode 100644 index 0000000..d3d0bc1 --- /dev/null +++ b/website/style.css @@ -0,0 +1,325 @@ +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap'); + +:root { + --primary: #FC4C02; + --primary-glow: rgba(252, 76, 2, 0.4); + --bg-dark: #0A0A0A; + --bg-card: rgba(255, 255, 255, 0.05); + --text-main: #FFFFFF; + --text-dim: #A0A0A0; + --glass-border: rgba(255, 255, 255, 0.1); + --transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Outfit', sans-serif; + background-color: var(--bg-dark); + color: var(--text-main); + line-height: 1.6; + overflow-x: hidden; +} + +/* Background Effects */ +.bg-gradient { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient(circle at 80% 20%, #1a100a 0%, transparent 40%), + radial-gradient(circle at 10% 80%, #0d0a14 0%, transparent 40%); + z-index: -1; +} + +/* Layout */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 2rem; +} + +/* Navigation */ +nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 2rem 0; + backdrop-filter: blur(10px); + position: sticky; + top: 0; + z-index: 100; +} + +.logo { + font-size: 1.5rem; + font-weight: 800; + letter-spacing: -1px; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.logo span { + color: var(--primary); +} + +.nav-links { + display: flex; + gap: 2.5rem; + list-style: none; +} + +.nav-links a { + color: var(--text-dim); + text-decoration: none; + font-size: 0.9rem; + font-weight: 500; + transition: var(--transition); +} + +.nav-links a:hover { + color: var(--primary); +} + +.lang-switch { + display: flex; + gap: 0.5rem; + background: rgba(255, 255, 255, 0.05); + padding: 0.25rem; + border-radius: 100px; + border: 1px solid var(--glass-border); +} + +.lang-btn { + padding: 0.4rem 0.8rem; + border-radius: 100px; + font-size: 0.75rem; + font-weight: 600; + cursor: pointer; + border: none; + background: transparent; + color: var(--text-dim); + transition: var(--transition); +} + +.lang-btn.active { + background: var(--primary); + color: white; +} + +/* Hero Section */ +.hero { + padding: 8rem 0; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + position: relative; +} + +.hero-img { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 140%; + opacity: 0.15; + pointer-events: none; + z-index: -1; +} + +.hero h1 { + font-size: 5rem; + font-weight: 800; + line-height: 1.1; + margin-bottom: 1.5rem; + background: linear-gradient(to bottom, #fff 40%, #888); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +.hero p { + font-size: 1.25rem; + color: var(--text-dim); + max-width: 600px; + margin-bottom: 3rem; +} + +.btn-group { + display: flex; + gap: 1.5rem; +} + +.btn { + padding: 1rem 2.5rem; + border-radius: 100px; + font-weight: 600; + text-decoration: none; + transition: var(--transition); + font-size: 1rem; +} + +.btn-primary { + background: var(--primary); + color: white; + box-shadow: 0 10px 30px var(--primary-glow); +} + +.btn-primary:hover { + transform: translateY(-5px); + box-shadow: 0 15px 40px var(--primary-glow); +} + +.btn-secondary { + background: rgba(255, 255, 255, 0.05); + color: white; + border: 1px solid var(--glass-border); + backdrop-filter: blur(10px); +} + +.btn-secondary:hover { + background: rgba(255, 255, 255, 0.1); +} + +/* Features Grid */ +.section-title { + text-align: center; + margin-bottom: 4rem; +} + +.section-title h2 { + font-size: 3rem; + margin-bottom: 1rem; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-bottom: 8rem; +} + +.card { + background: var(--bg-card); + border: 1px solid var(--glass-border); + padding: 3rem; + border-radius: 2rem; + transition: var(--transition); + backdrop-filter: blur(20px); +} + +.card:hover { + border-color: var(--primary); + transform: translateY(-10px); + background: rgba(252, 76, 2, 0.03); +} + +.card-icon { + font-size: 2.5rem; + margin-bottom: 1.5rem; + display: block; +} + +.card h3 { + font-size: 1.5rem; + margin-bottom: 1rem; +} + +.card p { + color: var(--text-dim); +} + +/* Code Preview Section */ +.architecture { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4rem; + align-items: center; + margin-bottom: 8rem; + background: rgba(255, 255, 255, 0.02); + padding: 4rem; + border-radius: 3rem; + border: 1px solid var(--glass-border); +} + +.code-window { + background: #000; + border-radius: 1rem; + overflow: hidden; + border: 1px solid var(--glass-border); + box-shadow: 0 30px 60px rgba(0,0,0,0.5); +} + +.code-header { + background: #1A1A1A; + padding: 0.75rem 1rem; + display: flex; + gap: 0.5rem; +} + +.dot { + width: 12px; + height: 12px; + border-radius: 50%; +} + +.red { background: #FF5F56; } +.yellow { background: #FFBD2E; } +.green { background: #27C93F; } + +.code-content { + padding: 1.5rem; + font-family: 'Monaco', 'Consolas', monospace; + font-size: 0.85rem; + color: #f8f8f2; +} + +.code-content pre { + white-space: pre-wrap; +} + +.keyword { color: #ff79c6; } +.string { color: #f1fa8c; } +.comment { color: #6272a4; } + +/* Quick Start */ +.quick-start { + text-align: center; + max-width: 800px; + margin: 0 auto 8rem; +} + +.terminal { + background: #111; + padding: 1.5rem 2rem; + border-radius: 1rem; + font-family: monospace; + margin-top: 2rem; + display: inline-block; + border: 1px solid var(--glass-border); +} + +.terminal span { + color: var(--primary); + margin-right: 1rem; +} + +footer { + padding: 4rem 0; + border-top: 1px solid var(--glass-border); + text-align: center; + color: var(--text-dim); +} + +/* Mobile Responsiveness */ +@media (max-width: 768px) { + .hero h1 { font-size: 3rem; } + .architecture { grid-template-columns: 1fr; padding: 2rem; } + .nav-links { display: none; } +}