diff --git a/docs/md_v2/marketplace/app-detail.css b/docs/md_v2/marketplace/app-detail.css index 9f04c13a..590bea03 100644 --- a/docs/md_v2/marketplace/app-detail.css +++ b/docs/md_v2/marketplace/app-detail.css @@ -197,6 +197,41 @@ } /* Navigation Tabs */ +.tabs { + display: flex; + flex-direction: row; + gap: 0; + border-bottom: 2px solid var(--border-color); + margin-bottom: 0; + background: var(--bg-tertiary); +} + +.tab-btn { + padding: 1rem 2rem; + background: transparent; + border: none; + border-bottom: 3px solid transparent; + color: var(--text-secondary); + cursor: pointer; + transition: all 0.2s; + font-family: inherit; + font-size: 0.95rem; + margin-bottom: -2px; + white-space: nowrap; + font-weight: 500; +} + +.tab-btn:hover { + color: var(--primary-cyan); + background: rgba(80, 255, 255, 0.05); +} + +.tab-btn.active { + color: var(--primary-cyan); + border-bottom-color: var(--primary-cyan); + background: var(--bg-secondary); +} + .app-nav { max-width: 1800px; margin: 2rem auto 0; @@ -228,34 +263,167 @@ border-bottom-color: var(--primary-cyan); } -/* Content Sections */ -.app-content { +/* Main Content Wrapper */ +.app-main { max-width: 1800px; margin: 2rem auto; padding: 0 2rem; } +/* Content Sections */ +.app-content { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + padding: 0; +} + .tab-content { display: none; + padding: 2rem; } .tab-content.active { display: block; } -.docs-content { - max-width: 1200px; - padding: 2rem; +/* Overview Layout */ +.overview-columns { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 2rem; +} + +.overview-main h2, .overview-main h3 { + color: var(--primary-cyan); + margin-top: 2rem; + margin-bottom: 1rem; +} + +.overview-main h2:first-child { + margin-top: 0; +} + +.overview-main h2 { + font-size: 1.8rem; + border-bottom: 2px solid var(--border-color); + padding-bottom: 0.5rem; +} + +.overview-main h3 { + font-size: 1.3rem; +} + +.features-list { + list-style: none; + padding: 0; +} + +.features-list li { + padding: 0.5rem 0; + padding-left: 1.5rem; + position: relative; + color: var(--text-secondary); +} + +.features-list li:before { + content: "▸"; + position: absolute; + left: 0; + color: var(--primary-cyan); +} + +.use-cases p { + color: var(--text-secondary); + line-height: 1.6; +} + +/* Sidebar */ +.sidebar { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.sidebar-card { background: var(--bg-secondary); border: 1px solid var(--border-color); + padding: 1.5rem; +} + +.sidebar-card h3 { + font-size: 1.1rem; + color: var(--primary-cyan); + margin: 0 0 1rem 0; + border-bottom: 1px solid var(--border-color); + padding-bottom: 0.5rem; +} + +.stats-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +.stats-grid > div { + text-align: center; +} + +.metadata { + margin: 0; +} + +.metadata div { + display: flex; + justify-content: space-between; + padding: 0.75rem 0; + border-bottom: 1px solid var(--border-color); +} + +.metadata dt { + color: var(--text-tertiary); + font-weight: normal; +} + +.metadata dd { + color: var(--text-primary); + margin: 0; + font-weight: 600; +} + +.sidebar-card p { + color: var(--text-secondary); + margin: 0; +} + +/* Integration Content */ +.integration-content { + max-width: 100%; +} + +.integration-content h2 { + font-size: 1.8rem; + color: var(--primary-cyan); + margin: 0 0 2rem 0; + padding-bottom: 0.5rem; + border-bottom: 2px solid var(--border-color); +} + +.integration-content h3 { + font-size: 1.3rem; + color: var(--text-primary); + margin: 2rem 0 1rem; +} + +.docs-content { + max-width: 100%; } .docs-content h2 { font-size: 1.8rem; color: var(--primary-cyan); - margin-bottom: 1rem; + margin: 0 0 1.5rem 0; padding-bottom: 0.5rem; - border-bottom: 1px solid var(--border-color); + border-bottom: 2px solid var(--border-color); } .docs-content h3 { @@ -290,6 +458,7 @@ border: 1px solid var(--border-color); margin: 1rem 0; overflow: hidden; + position: relative; } .code-header { @@ -308,18 +477,23 @@ } .copy-btn { - padding: 0.25rem 0.5rem; - background: transparent; + position: absolute; + top: 0.5rem; + right: 0.5rem; + padding: 0.4rem 0.8rem; + background: var(--bg-tertiary); border: 1px solid var(--border-color); color: var(--text-secondary); cursor: pointer; font-size: 0.75rem; transition: all 0.2s; + z-index: 10; } .copy-btn:hover { border-color: var(--primary-cyan); color: var(--primary-cyan); + background: var(--bg-secondary); } .code-block pre { @@ -435,6 +609,10 @@ .app-stats { justify-content: space-around; } + + .overview-columns { + grid-template-columns: 1fr; + } } @media (max-width: 768px) { @@ -446,6 +624,16 @@ flex-direction: column; } + .tabs { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + + .tab-btn { + padding: 0.75rem 1.5rem; + font-size: 0.875rem; + } + .app-nav { overflow-x: auto; gap: 0; @@ -459,4 +647,12 @@ .support-grid { grid-template-columns: 1fr; } + + .tab-content { + padding: 1rem; + } + + .app-main { + padding: 0 1rem; + } } \ No newline at end of file diff --git a/docs/md_v2/marketplace/app-detail.html b/docs/md_v2/marketplace/app-detail.html new file mode 100644 index 00000000..ef1138a8 --- /dev/null +++ b/docs/md_v2/marketplace/app-detail.html @@ -0,0 +1,209 @@ + + + + + + App Details - Crawl4AI Marketplace + + + + +
+ +
+
+
+
+ +

+ [ + Marketplace + ] +

+
+
+ +
+
+ + +
+
+
+ +
+
+
+ Open Source + + +
+

App Name

+

App description goes here

+ +
+
+ ★★★★★ + Rating +
+
+ 0 + Downloads +
+
+ Category + Category +
+
+ + +
+
+
+ + +
+
+
+ + + + +
+ +
+
+
+

Overview

+
Overview content goes here.
+ +

Key Features

+
    +
  • Feature 1
  • +
  • Feature 2
  • +
  • Feature 3
  • +
+ +

Use Cases

+
+

Describe how this app can help your workflow.

+
+
+ + +
+
+ +
+
+

Integration Guide

+ +

Installation

+
+
# Installation instructions will appear here
+
+ +

Basic Usage

+
+
# Usage example will appear here
+
+ +

Complete Integration Example

+
+ +
# Complete integration guide will appear here
+
+
+
+ +
+
+

Documentation

+
+

Documentation coming soon.

+
+
+
+ +
+
+

Support

+
+
+

📧 Contact

+

contact@example.com

+
+
+

🐛 Report Issues

+

Found a bug? Report it on GitHub Issues.

+
+
+

💬 Community

+

Join our Discord for help and discussions.

+
+
+
+
+
+ +
+ + + +
+ + + + diff --git a/docs/md_v2/marketplace/app-detail.js b/docs/md_v2/marketplace/app-detail.js index 622f9c88..f470bf51 100644 --- a/docs/md_v2/marketplace/app-detail.js +++ b/docs/md_v2/marketplace/app-detail.js @@ -1,5 +1,15 @@ // App Detail Page JavaScript -const API_BASE = '/marketplace/api'; +const { API_BASE, API_ORIGIN } = (() => { + const { hostname, port, protocol } = window.location; + const isLocalHost = ['localhost', '127.0.0.1', '0.0.0.0'].includes(hostname); + + if (isLocalHost && port && port !== '8100') { + const origin = `${protocol}//127.0.0.1:8100`; + return { API_BASE: `${origin}/marketplace/api`, API_ORIGIN: origin }; + } + + return { API_BASE: '/marketplace/api', API_ORIGIN: '' }; +})(); class AppDetailPage { constructor() { @@ -70,7 +80,6 @@ class AppDetailPage { document.getElementById('app-description').textContent = this.appData.description; document.getElementById('app-type').textContent = this.appData.type || 'Open Source'; document.getElementById('app-category').textContent = this.appData.category; - document.getElementById('app-pricing').textContent = this.appData.pricing || 'Free'; // Badges if (this.appData.featured) { @@ -105,6 +114,15 @@ class AppDetailPage { // Contact document.getElementById('app-contact').textContent = this.appData.contact_email || 'Not available'; + // Sidebar info + document.getElementById('sidebar-downloads').textContent = this.formatNumber(this.appData.downloads || 0); + document.getElementById('sidebar-rating').textContent = (this.appData.rating || 0).toFixed(1); + document.getElementById('sidebar-category').textContent = this.appData.category || '-'; + document.getElementById('sidebar-type').textContent = this.appData.type || '-'; + document.getElementById('sidebar-status').textContent = this.appData.status || 'Active'; + document.getElementById('sidebar-pricing').textContent = this.appData.pricing || 'Free'; + document.getElementById('sidebar-contact').textContent = this.appData.contact_email || 'contact@example.com'; + // Integration guide this.renderIntegrationGuide(); } @@ -112,24 +130,27 @@ class AppDetailPage { renderIntegrationGuide() { // Installation code const installCode = document.getElementById('install-code'); - if (this.appData.type === 'Open Source' && this.appData.github_url) { - installCode.textContent = `# Clone from GitHub + if (installCode) { + if (this.appData.type === 'Open Source' && this.appData.github_url) { + installCode.textContent = `# Clone from GitHub git clone ${this.appData.github_url} # Install dependencies pip install -r requirements.txt`; - } else if (this.appData.name.toLowerCase().includes('api')) { - installCode.textContent = `# Install via pip + } else if (this.appData.name.toLowerCase().includes('api')) { + installCode.textContent = `# Install via pip pip install ${this.appData.slug} # Or install from source pip install git+${this.appData.github_url || 'https://github.com/example/repo'}`; + } } // Usage code - customize based on category const usageCode = document.getElementById('usage-code'); - if (this.appData.category === 'Browser Automation') { - usageCode.textContent = `from crawl4ai import AsyncWebCrawler + if (usageCode) { + if (this.appData.category === 'Browser Automation') { + usageCode.textContent = `from crawl4ai import AsyncWebCrawler from ${this.appData.slug.replace(/-/g, '_')} import ${this.appData.name.replace(/\s+/g, '')} async def main(): @@ -178,11 +199,13 @@ async with AsyncWebCrawler() as crawler: extraction_strategy=strategy ) print(result.extracted_content)`; + } } // Integration example const integrationCode = document.getElementById('integration-code'); - integrationCode.textContent = this.appData.integration_guide || + if (integrationCode) { + integrationCode.textContent = this.appData.integration_guide || `# Complete ${this.appData.name} Integration Example from crawl4ai import AsyncWebCrawler @@ -237,6 +260,7 @@ async def crawl_with_${this.appData.slug.replace(/-/g, '_')}(): if __name__ == "__main__": import asyncio asyncio.run(crawl_with_${this.appData.slug.replace(/-/g, '_')}())`; + } } formatNumber(num) { @@ -250,7 +274,7 @@ if __name__ == "__main__": setupEventListeners() { // Tab switching - const tabs = document.querySelectorAll('.nav-tab'); + const tabs = document.querySelectorAll('.tab-btn'); tabs.forEach(tab => { tab.addEventListener('click', () => { // Update active tab diff --git a/docs/md_v2/marketplace/frontend/app-detail.js b/docs/md_v2/marketplace/frontend/app-detail.js index 622f9c88..5bc86d2b 100644 --- a/docs/md_v2/marketplace/frontend/app-detail.js +++ b/docs/md_v2/marketplace/frontend/app-detail.js @@ -1,5 +1,15 @@ // App Detail Page JavaScript -const API_BASE = '/marketplace/api'; +const { API_BASE, API_ORIGIN } = (() => { + const { hostname, port, protocol } = window.location; + const isLocalHost = ['localhost', '127.0.0.1', '0.0.0.0'].includes(hostname); + + if (isLocalHost && port && port !== '8100') { + const origin = `${protocol}//127.0.0.1:8100`; + return { API_BASE: `${origin}/marketplace/api`, API_ORIGIN: origin }; + } + + return { API_BASE: '/marketplace/api', API_ORIGIN: '' }; +})(); class AppDetailPage { constructor() {