diff --git a/docs/md_v2/marketplace/admin/admin.js b/docs/md_v2/marketplace/admin/admin.js
index 861d3ba7..258858da 100644
--- a/docs/md_v2/marketplace/admin/admin.js
+++ b/docs/md_v2/marketplace/admin/admin.js
@@ -1,5 +1,5 @@
// Admin Dashboard - Smart & Powerful
-const API_BASE = 'http://localhost:8100/api';
+const API_BASE = '/api';
class AdminDashboard {
constructor() {
diff --git a/docs/md_v2/marketplace/app-detail.css b/docs/md_v2/marketplace/app-detail.css
new file mode 100644
index 00000000..9f04c13a
--- /dev/null
+++ b/docs/md_v2/marketplace/app-detail.css
@@ -0,0 +1,462 @@
+/* App Detail Page Styles */
+
+.app-detail-container {
+ min-height: 100vh;
+ background: var(--bg-dark);
+}
+
+/* Back Button */
+.header-nav {
+ display: flex;
+ align-items: center;
+}
+
+.back-btn {
+ padding: 0.5rem 1rem;
+ background: transparent;
+ border: 1px solid var(--border-color);
+ color: var(--primary-cyan);
+ text-decoration: none;
+ transition: all 0.2s;
+ font-size: 0.875rem;
+}
+
+.back-btn:hover {
+ border-color: var(--primary-cyan);
+ background: rgba(80, 255, 255, 0.1);
+}
+
+/* App Hero Section */
+.app-hero {
+ max-width: 1800px;
+ margin: 2rem auto;
+ padding: 0 2rem;
+}
+
+.app-hero-content {
+ display: grid;
+ grid-template-columns: 1fr 2fr;
+ gap: 3rem;
+ background: linear-gradient(135deg, #1a1a2e, #0f0f1e);
+ border: 2px solid var(--primary-cyan);
+ padding: 2rem;
+ box-shadow: 0 0 30px rgba(80, 255, 255, 0.15),
+ inset 0 0 20px rgba(80, 255, 255, 0.05);
+}
+
+.app-hero-image {
+ width: 100%;
+ height: 300px;
+ background: linear-gradient(135deg, rgba(80, 255, 255, 0.1), rgba(243, 128, 245, 0.05));
+ background-size: cover;
+ background-position: center;
+ border: 1px solid var(--border-color);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 4rem;
+ color: var(--primary-cyan);
+}
+
+.app-badges {
+ display: flex;
+ gap: 0.5rem;
+ margin-bottom: 1rem;
+}
+
+.app-badge {
+ padding: 0.3rem 0.6rem;
+ background: var(--bg-tertiary);
+ color: var(--text-secondary);
+ font-size: 0.75rem;
+ text-transform: uppercase;
+ font-weight: 600;
+}
+
+.app-badge.featured {
+ background: linear-gradient(135deg, var(--primary-cyan), var(--primary-teal));
+ color: var(--bg-dark);
+ box-shadow: 0 2px 10px rgba(80, 255, 255, 0.3);
+}
+
+.app-badge.sponsored {
+ background: linear-gradient(135deg, var(--warning), #ff8c00);
+ color: var(--bg-dark);
+ box-shadow: 0 2px 10px rgba(245, 158, 11, 0.3);
+}
+
+.app-hero-info h1 {
+ font-size: 2.5rem;
+ color: var(--primary-cyan);
+ margin: 0.5rem 0;
+ text-shadow: 0 0 20px rgba(80, 255, 255, 0.5);
+}
+
+.app-tagline {
+ font-size: 1.1rem;
+ color: var(--text-secondary);
+ margin-bottom: 2rem;
+}
+
+/* Stats */
+.app-stats {
+ display: flex;
+ gap: 2rem;
+ margin: 2rem 0;
+ padding: 1rem 0;
+ border-top: 1px solid var(--border-color);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.stat {
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.stat-value {
+ font-size: 1.5rem;
+ color: var(--primary-cyan);
+ font-weight: 600;
+}
+
+.stat-label {
+ font-size: 0.875rem;
+ color: var(--text-tertiary);
+}
+
+/* Action Buttons */
+.app-actions {
+ display: flex;
+ gap: 1rem;
+ margin: 2rem 0;
+}
+
+.action-btn {
+ padding: 0.75rem 1.5rem;
+ border: 1px solid var(--border-color);
+ background: transparent;
+ color: var(--text-primary);
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.5rem;
+ transition: all 0.2s;
+ cursor: pointer;
+ font-family: inherit;
+ font-size: 0.9rem;
+}
+
+.action-btn.primary {
+ background: linear-gradient(135deg, var(--primary-cyan), var(--primary-teal));
+ color: var(--bg-dark);
+ border-color: var(--primary-cyan);
+ font-weight: 600;
+}
+
+.action-btn.primary:hover {
+ box-shadow: 0 4px 15px rgba(80, 255, 255, 0.3);
+ transform: translateY(-2px);
+}
+
+.action-btn.secondary {
+ border-color: var(--accent-pink);
+ color: var(--accent-pink);
+}
+
+.action-btn.secondary:hover {
+ background: rgba(243, 128, 245, 0.1);
+ box-shadow: 0 4px 15px rgba(243, 128, 245, 0.2);
+}
+
+.action-btn.ghost {
+ border-color: var(--border-color);
+ color: var(--text-secondary);
+}
+
+.action-btn.ghost:hover {
+ border-color: var(--primary-cyan);
+ color: var(--primary-cyan);
+}
+
+/* Pricing */
+.pricing-info {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ font-size: 1.1rem;
+}
+
+.pricing-label {
+ color: var(--text-tertiary);
+}
+
+.pricing-value {
+ color: var(--warning);
+ font-weight: 600;
+}
+
+/* Navigation Tabs */
+.app-nav {
+ max-width: 1800px;
+ margin: 2rem auto 0;
+ padding: 0 2rem;
+ display: flex;
+ gap: 1rem;
+ border-bottom: 2px solid var(--border-color);
+}
+
+.nav-tab {
+ padding: 1rem 1.5rem;
+ background: transparent;
+ border: none;
+ border-bottom: 2px solid transparent;
+ color: var(--text-secondary);
+ cursor: pointer;
+ transition: all 0.2s;
+ font-family: inherit;
+ font-size: 0.9rem;
+ margin-bottom: -2px;
+}
+
+.nav-tab:hover {
+ color: var(--primary-cyan);
+}
+
+.nav-tab.active {
+ color: var(--primary-cyan);
+ border-bottom-color: var(--primary-cyan);
+}
+
+/* Content Sections */
+.app-content {
+ max-width: 1800px;
+ margin: 2rem auto;
+ padding: 0 2rem;
+}
+
+.tab-content {
+ display: none;
+}
+
+.tab-content.active {
+ display: block;
+}
+
+.docs-content {
+ max-width: 1200px;
+ padding: 2rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+}
+
+.docs-content h2 {
+ font-size: 1.8rem;
+ color: var(--primary-cyan);
+ margin-bottom: 1rem;
+ padding-bottom: 0.5rem;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.docs-content h3 {
+ font-size: 1.3rem;
+ color: var(--text-primary);
+ margin: 2rem 0 1rem;
+}
+
+.docs-content h4 {
+ font-size: 1.1rem;
+ color: var(--accent-pink);
+ margin: 1.5rem 0 0.5rem;
+}
+
+.docs-content p {
+ color: var(--text-secondary);
+ line-height: 1.6;
+ margin-bottom: 1rem;
+}
+
+.docs-content code {
+ background: var(--bg-tertiary);
+ padding: 0.2rem 0.4rem;
+ color: var(--primary-cyan);
+ font-family: 'Dank Mono', Monaco, monospace;
+ font-size: 0.9em;
+}
+
+/* Code Blocks */
+.code-block {
+ background: var(--bg-dark);
+ border: 1px solid var(--border-color);
+ margin: 1rem 0;
+ overflow: hidden;
+}
+
+.code-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.5rem 1rem;
+ background: var(--bg-tertiary);
+ border-bottom: 1px solid var(--border-color);
+}
+
+.code-lang {
+ color: var(--primary-cyan);
+ font-size: 0.875rem;
+ text-transform: uppercase;
+}
+
+.copy-btn {
+ padding: 0.25rem 0.5rem;
+ background: transparent;
+ border: 1px solid var(--border-color);
+ color: var(--text-secondary);
+ cursor: pointer;
+ font-size: 0.75rem;
+ transition: all 0.2s;
+}
+
+.copy-btn:hover {
+ border-color: var(--primary-cyan);
+ color: var(--primary-cyan);
+}
+
+.code-block pre {
+ margin: 0;
+ padding: 1rem;
+ overflow-x: auto;
+}
+
+.code-block code {
+ background: transparent;
+ padding: 0;
+ color: var(--text-secondary);
+ font-size: 0.875rem;
+ line-height: 1.5;
+}
+
+/* Feature Grid */
+.feature-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 1rem;
+ margin: 2rem 0;
+}
+
+.feature-card {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ padding: 1.5rem;
+ transition: all 0.2s;
+}
+
+.feature-card:hover {
+ border-color: var(--primary-cyan);
+ background: rgba(80, 255, 255, 0.05);
+}
+
+.feature-card h4 {
+ margin-top: 0;
+}
+
+/* Info Box */
+.info-box {
+ background: linear-gradient(135deg, rgba(80, 255, 255, 0.05), rgba(243, 128, 245, 0.03));
+ border: 1px solid var(--primary-cyan);
+ border-left: 4px solid var(--primary-cyan);
+ padding: 1.5rem;
+ margin: 2rem 0;
+}
+
+.info-box h4 {
+ margin-top: 0;
+ color: var(--primary-cyan);
+}
+
+/* Support Grid */
+.support-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 1rem;
+ margin: 2rem 0;
+}
+
+.support-card {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ padding: 1.5rem;
+ text-align: center;
+}
+
+.support-card h3 {
+ color: var(--primary-cyan);
+ margin-bottom: 0.5rem;
+}
+
+/* Related Apps */
+.related-apps {
+ max-width: 1800px;
+ margin: 4rem auto;
+ padding: 0 2rem;
+}
+
+.related-apps h2 {
+ font-size: 1.5rem;
+ color: var(--text-primary);
+ margin-bottom: 1.5rem;
+}
+
+.related-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ gap: 1rem;
+}
+
+.related-app-card {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ padding: 1rem;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.related-app-card:hover {
+ border-color: var(--primary-cyan);
+ transform: translateY(-2px);
+}
+
+/* Responsive */
+@media (max-width: 1024px) {
+ .app-hero-content {
+ grid-template-columns: 1fr;
+ }
+
+ .app-stats {
+ justify-content: space-around;
+ }
+}
+
+@media (max-width: 768px) {
+ .app-hero-info h1 {
+ font-size: 2rem;
+ }
+
+ .app-actions {
+ flex-direction: column;
+ }
+
+ .app-nav {
+ overflow-x: auto;
+ gap: 0;
+ }
+
+ .nav-tab {
+ white-space: nowrap;
+ }
+
+ .feature-grid,
+ .support-grid {
+ grid-template-columns: 1fr;
+ }
+}
\ No newline at end of file
diff --git a/docs/md_v2/marketplace/app-detail.js b/docs/md_v2/marketplace/app-detail.js
new file mode 100644
index 00000000..d1b3b559
--- /dev/null
+++ b/docs/md_v2/marketplace/app-detail.js
@@ -0,0 +1,324 @@
+// App Detail Page JavaScript
+const API_BASE = '/api';
+
+class AppDetailPage {
+ constructor() {
+ this.appSlug = this.getAppSlugFromURL();
+ this.appData = null;
+ this.init();
+ }
+
+ getAppSlugFromURL() {
+ const params = new URLSearchParams(window.location.search);
+ return params.get('app') || '';
+ }
+
+ async init() {
+ if (!this.appSlug) {
+ window.location.href = 'index.html';
+ return;
+ }
+
+ await this.loadAppDetails();
+ this.setupEventListeners();
+ await this.loadRelatedApps();
+ }
+
+ async loadAppDetails() {
+ try {
+ const response = await fetch(`${API_BASE}/apps/${this.appSlug}`);
+ if (!response.ok) throw new Error('App not found');
+
+ this.appData = await response.json();
+ this.renderAppDetails();
+ } catch (error) {
+ console.error('Error loading app details:', error);
+ // Fallback to loading all apps and finding the right one
+ try {
+ const response = await fetch(`${API_BASE}/apps`);
+ const apps = await response.json();
+ this.appData = apps.find(app => app.slug === this.appSlug || app.name.toLowerCase().replace(/\s+/g, '-') === this.appSlug);
+ if (this.appData) {
+ this.renderAppDetails();
+ } else {
+ window.location.href = 'index.html';
+ }
+ } catch (err) {
+ console.error('Error loading apps:', err);
+ window.location.href = 'index.html';
+ }
+ }
+ }
+
+ renderAppDetails() {
+ if (!this.appData) return;
+
+ // Update title
+ document.title = `${this.appData.name} - Crawl4AI Marketplace`;
+
+ // Hero image
+ const appImage = document.getElementById('app-image');
+ if (this.appData.image) {
+ appImage.style.backgroundImage = `url('${this.appData.image}')`;
+ appImage.innerHTML = '';
+ } else {
+ appImage.innerHTML = `[${this.appData.category || 'APP'}]`;
+ }
+
+ // Basic info
+ document.getElementById('app-name').textContent = this.appData.name;
+ 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) {
+ document.getElementById('app-featured').style.display = 'inline-block';
+ }
+ if (this.appData.sponsored) {
+ document.getElementById('app-sponsored').style.display = 'inline-block';
+ }
+
+ // Stats
+ const rating = this.appData.rating || 0;
+ const stars = '★'.repeat(Math.floor(rating)) + '☆'.repeat(5 - Math.floor(rating));
+ document.getElementById('app-rating').textContent = stars + ` ${rating}/5`;
+ document.getElementById('app-downloads').textContent = this.formatNumber(this.appData.downloads || 0);
+
+ // Action buttons
+ const websiteBtn = document.getElementById('app-website');
+ const githubBtn = document.getElementById('app-github');
+
+ if (this.appData.website_url) {
+ websiteBtn.href = this.appData.website_url;
+ } else {
+ websiteBtn.style.display = 'none';
+ }
+
+ if (this.appData.github_url) {
+ githubBtn.href = this.appData.github_url;
+ } else {
+ githubBtn.style.display = 'none';
+ }
+
+ // Contact
+ document.getElementById('app-contact').textContent = this.appData.contact_email || 'Not available';
+
+ // Integration guide
+ this.renderIntegrationGuide();
+ }
+
+ renderIntegrationGuide() {
+ // Installation code
+ const installCode = document.getElementById('install-code');
+ 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
+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
+from ${this.appData.slug.replace(/-/g, '_')} import ${this.appData.name.replace(/\s+/g, '')}
+
+async def main():
+ # Initialize ${this.appData.name}
+ automation = ${this.appData.name.replace(/\s+/g, '')}()
+
+ async with AsyncWebCrawler() as crawler:
+ result = await crawler.arun(
+ url="https://example.com",
+ browser_config=automation.config,
+ wait_for="css:body"
+ )
+ print(result.markdown)`;
+ } else if (this.appData.category === 'Proxy Services') {
+ usageCode.textContent = `from crawl4ai import AsyncWebCrawler
+import ${this.appData.slug.replace(/-/g, '_')}
+
+# Configure proxy
+proxy_config = {
+ "server": "${this.appData.website_url || 'https://proxy.example.com'}",
+ "username": "your_username",
+ "password": "your_password"
+}
+
+async with AsyncWebCrawler(proxy=proxy_config) as crawler:
+ result = await crawler.arun(
+ url="https://example.com",
+ bypass_cache=True
+ )
+ print(result.status_code)`;
+ } else if (this.appData.category === 'LLM Integration') {
+ usageCode.textContent = `from crawl4ai import AsyncWebCrawler
+from crawl4ai.extraction_strategy import LLMExtractionStrategy
+
+# Configure LLM extraction
+strategy = LLMExtractionStrategy(
+ provider="${this.appData.name.toLowerCase().includes('gpt') ? 'openai' : 'anthropic'}",
+ api_key="your-api-key",
+ model="${this.appData.name.toLowerCase().includes('gpt') ? 'gpt-4' : 'claude-3'}",
+ instruction="Extract structured data"
+)
+
+async with AsyncWebCrawler() as crawler:
+ result = await crawler.arun(
+ url="https://example.com",
+ extraction_strategy=strategy
+ )
+ print(result.extracted_content)`;
+ }
+
+ // Integration example
+ const integrationCode = document.getElementById('integration-code');
+ integrationCode.textContent = this.appData.integration_guide ||
+`# Complete ${this.appData.name} Integration Example
+
+from crawl4ai import AsyncWebCrawler
+from crawl4ai.extraction_strategy import JsonCssExtractionStrategy
+import json
+
+async def crawl_with_${this.appData.slug.replace(/-/g, '_')}():
+ """
+ Complete example showing how to use ${this.appData.name}
+ with Crawl4AI for production web scraping
+ """
+
+ # Define extraction schema
+ schema = {
+ "name": "ProductList",
+ "baseSelector": "div.product",
+ "fields": [
+ {"name": "title", "selector": "h2", "type": "text"},
+ {"name": "price", "selector": ".price", "type": "text"},
+ {"name": "image", "selector": "img", "type": "attribute", "attribute": "src"},
+ {"name": "link", "selector": "a", "type": "attribute", "attribute": "href"}
+ ]
+ }
+
+ # Initialize crawler with ${this.appData.name}
+ async with AsyncWebCrawler(
+ browser_type="chromium",
+ headless=True,
+ verbose=True
+ ) as crawler:
+
+ # Crawl with extraction
+ result = await crawler.arun(
+ url="https://example.com/products",
+ extraction_strategy=JsonCssExtractionStrategy(schema),
+ cache_mode="bypass",
+ wait_for="css:.product",
+ screenshot=True
+ )
+
+ # Process results
+ if result.success:
+ products = json.loads(result.extracted_content)
+ print(f"Found {len(products)} products")
+
+ for product in products[:5]:
+ print(f"- {product['title']}: {product['price']}")
+
+ return products
+
+# Run the crawler
+if __name__ == "__main__":
+ import asyncio
+ asyncio.run(crawl_with_${this.appData.slug.replace(/-/g, '_')}())`;
+ }
+
+ formatNumber(num) {
+ if (num >= 1000000) {
+ return (num / 1000000).toFixed(1) + 'M';
+ } else if (num >= 1000) {
+ return (num / 1000).toFixed(1) + 'K';
+ }
+ return num.toString();
+ }
+
+ setupEventListeners() {
+ // Tab switching
+ const tabs = document.querySelectorAll('.nav-tab');
+ tabs.forEach(tab => {
+ tab.addEventListener('click', () => {
+ // Update active tab
+ tabs.forEach(t => t.classList.remove('active'));
+ tab.classList.add('active');
+
+ // Show corresponding content
+ const tabName = tab.dataset.tab;
+ document.querySelectorAll('.tab-content').forEach(content => {
+ content.classList.remove('active');
+ });
+ document.getElementById(`${tabName}-tab`).classList.add('active');
+ });
+ });
+
+ // Copy integration code
+ document.getElementById('copy-integration').addEventListener('click', () => {
+ const code = document.getElementById('integration-code').textContent;
+ navigator.clipboard.writeText(code).then(() => {
+ const btn = document.getElementById('copy-integration');
+ const originalText = btn.innerHTML;
+ btn.innerHTML = '✓ Copied!';
+ setTimeout(() => {
+ btn.innerHTML = originalText;
+ }, 2000);
+ });
+ });
+
+ // Copy code buttons
+ document.querySelectorAll('.copy-btn').forEach(btn => {
+ btn.addEventListener('click', (e) => {
+ const codeBlock = e.target.closest('.code-block');
+ const code = codeBlock.querySelector('code').textContent;
+ navigator.clipboard.writeText(code).then(() => {
+ btn.textContent = 'Copied!';
+ setTimeout(() => {
+ btn.textContent = 'Copy';
+ }, 2000);
+ });
+ });
+ });
+ }
+
+ async loadRelatedApps() {
+ try {
+ const response = await fetch(`${API_BASE}/apps?category=${encodeURIComponent(this.appData.category)}&limit=4`);
+ const apps = await response.json();
+
+ const relatedApps = apps.filter(app => app.slug !== this.appSlug).slice(0, 3);
+ const grid = document.getElementById('related-apps-grid');
+
+ grid.innerHTML = relatedApps.map(app => `
+
+ `).join('');
+ } catch (error) {
+ console.error('Error loading related apps:', error);
+ }
+ }
+}
+
+// Initialize when DOM is loaded
+document.addEventListener('DOMContentLoaded', () => {
+ new AppDetailPage();
+});
\ No newline at end of file
diff --git a/docs/md_v2/marketplace/frontend/app-detail.js b/docs/md_v2/marketplace/frontend/app-detail.js
index 82422f14..d1b3b559 100644
--- a/docs/md_v2/marketplace/frontend/app-detail.js
+++ b/docs/md_v2/marketplace/frontend/app-detail.js
@@ -1,5 +1,5 @@
// App Detail Page JavaScript
-const API_BASE = 'http://localhost:8100/api';
+const API_BASE = '/api';
class AppDetailPage {
constructor() {
diff --git a/docs/md_v2/marketplace/frontend/marketplace.js b/docs/md_v2/marketplace/frontend/marketplace.js
index cdc22114..94a401bf 100644
--- a/docs/md_v2/marketplace/frontend/marketplace.js
+++ b/docs/md_v2/marketplace/frontend/marketplace.js
@@ -1,5 +1,5 @@
// Marketplace JS - Magazine Layout
-const API_BASE = 'http://localhost:8100/api';
+const API_BASE = '/api';
const CACHE_TTL = 3600000; // 1 hour in ms
class MarketplaceCache {
diff --git a/docs/md_v2/marketplace/index.html b/docs/md_v2/marketplace/index.html
new file mode 100644
index 00000000..c425420a
--- /dev/null
+++ b/docs/md_v2/marketplace/index.html
@@ -0,0 +1,147 @@
+
+
+
+
+
+ Marketplace - Crawl4AI
+
+
+
+
+
+
+
+
+
+
+ >
+
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
> Latest Apps
+
+
+
+
+
+
+
+
+
+
+
> Latest Articles
+
+
+
+
+
+
+
+
+
+
# Trending
+
+
+
+
+
+
+
+ Submit Your Tool
+
Share your integration
+
Submit →
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/md_v2/marketplace/marketplace.css b/docs/md_v2/marketplace/marketplace.css
new file mode 100644
index 00000000..ad26c344
--- /dev/null
+++ b/docs/md_v2/marketplace/marketplace.css
@@ -0,0 +1,957 @@
+/* Marketplace CSS - Magazine Style Terminal Theme */
+@import url('../../assets/styles.css');
+
+:root {
+ --primary-cyan: #50ffff;
+ --primary-teal: #09b5a5;
+ --accent-pink: #f380f5;
+ --bg-dark: #070708;
+ --bg-secondary: #1a1a1a;
+ --bg-tertiary: #3f3f44;
+ --text-primary: #e8e9ed;
+ --text-secondary: #d5cec0;
+ --text-tertiary: #a3abba;
+ --border-color: #3f3f44;
+ --success: #50ff50;
+ --error: #ff3c74;
+ --warning: #f59e0b;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Dank Mono', Monaco, monospace;
+ background: var(--bg-dark);
+ color: var(--text-primary);
+ line-height: 1.6;
+}
+
+/* Global link styles */
+a {
+ color: var(--primary-cyan);
+ text-decoration: none;
+ transition: color 0.2s;
+}
+
+a:hover {
+ color: var(--accent-pink);
+}
+
+.marketplace-container {
+ min-height: 100vh;
+}
+
+/* Header */
+.marketplace-header {
+ background: var(--bg-secondary);
+ border-bottom: 1px solid var(--border-color);
+ padding: 1.5rem 0;
+}
+
+.header-content {
+ max-width: 1800px;
+ margin: 0 auto;
+ padding: 0 2rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.logo-title {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.header-logo {
+ height: 40px;
+ width: auto;
+ filter: brightness(1.2);
+}
+
+.marketplace-header h1 {
+ font-size: 1.5rem;
+ color: var(--primary-cyan);
+ margin: 0;
+}
+
+.ascii-border {
+ color: var(--border-color);
+}
+
+.tagline {
+ font-size: 0.875rem;
+ color: var(--text-tertiary);
+ margin-top: 0.25rem;
+}
+
+.header-stats {
+ display: flex;
+ gap: 2rem;
+}
+
+.stat-item {
+ font-size: 0.875rem;
+ color: var(--text-secondary);
+}
+
+.stat-item span {
+ color: var(--primary-cyan);
+ font-weight: 600;
+}
+
+/* Search and Filter Bar */
+.search-filter-bar {
+ max-width: 1800px;
+ margin: 1.5rem auto;
+ padding: 0 2rem;
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+}
+
+.search-box {
+ flex: 1;
+ max-width: 500px;
+ display: flex;
+ align-items: center;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ padding: 0.75rem 1rem;
+ transition: border-color 0.2s;
+}
+
+.search-box:focus-within {
+ border-color: var(--primary-cyan);
+}
+
+.search-icon {
+ color: var(--text-tertiary);
+ margin-right: 1rem;
+}
+
+#search-input {
+ flex: 1;
+ background: transparent;
+ border: none;
+ color: var(--text-primary);
+ font-family: inherit;
+ font-size: 0.9rem;
+ outline: none;
+}
+
+.search-box kbd {
+ font-size: 0.75rem;
+ padding: 0.2rem 0.5rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ color: var(--text-tertiary);
+}
+
+.category-filter {
+ display: flex;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+.filter-btn {
+ background: transparent;
+ border: 1px solid var(--border-color);
+ color: var(--text-secondary);
+ padding: 0.5rem 1rem;
+ font-family: inherit;
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.filter-btn:hover {
+ border-color: var(--primary-cyan);
+ color: var(--primary-cyan);
+}
+
+.filter-btn.active {
+ background: var(--primary-cyan);
+ color: var(--bg-dark);
+ border-color: var(--primary-cyan);
+}
+
+/* Magazine Layout */
+.magazine-layout {
+ max-width: 1800px;
+ margin: 0 auto;
+ padding: 0 2rem 4rem;
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 2rem;
+}
+
+/* Hero Featured Section */
+.hero-featured {
+ grid-column: 1 / -1;
+ position: relative;
+}
+
+.hero-featured::before {
+ content: '';
+ position: absolute;
+ top: -20px;
+ left: -20px;
+ right: -20px;
+ bottom: -20px;
+ background: radial-gradient(ellipse at center, rgba(80, 255, 255, 0.05), transparent 70%);
+ pointer-events: none;
+ z-index: -1;
+}
+
+.featured-hero-card {
+ background: linear-gradient(135deg, #1a1a2e, #0f0f1e);
+ border: 2px solid var(--primary-cyan);
+ box-shadow: 0 0 30px rgba(80, 255, 255, 0.15),
+ inset 0 0 20px rgba(80, 255, 255, 0.05);
+ height: 380px;
+ position: relative;
+ overflow: hidden;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ display: flex;
+ flex-direction: column;
+}
+
+.featured-hero-card:hover {
+ border-color: var(--accent-pink);
+ box-shadow: 0 0 40px rgba(243, 128, 245, 0.2),
+ inset 0 0 30px rgba(243, 128, 245, 0.05);
+ transform: translateY(-2px);
+}
+
+.hero-image {
+ width: 100%;
+ height: 240px;
+ background: linear-gradient(135deg, rgba(80, 255, 255, 0.1), rgba(243, 128, 245, 0.05));
+ background-size: cover;
+ background-position: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 3rem;
+ color: var(--primary-cyan);
+ flex-shrink: 0;
+ position: relative;
+ filter: brightness(1.1) contrast(1.1);
+}
+
+.hero-image::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 60%;
+ background: linear-gradient(to top, rgba(10, 10, 20, 0.95), transparent);
+}
+
+.hero-content {
+ padding: 1.5rem;
+}
+
+.hero-badge {
+ display: inline-block;
+ padding: 0.3rem 0.6rem;
+ background: linear-gradient(135deg, var(--primary-cyan), var(--primary-teal));
+ color: var(--bg-dark);
+ font-size: 0.7rem;
+ text-transform: uppercase;
+ margin-bottom: 0.5rem;
+ font-weight: 600;
+ box-shadow: 0 2px 10px rgba(80, 255, 255, 0.3);
+}
+
+.hero-title {
+ font-size: 1.6rem;
+ color: var(--primary-cyan);
+ margin: 0.5rem 0;
+ text-shadow: 0 0 20px rgba(80, 255, 255, 0.5);
+}
+
+.hero-description {
+ color: var(--text-secondary);
+ line-height: 1.5;
+}
+
+.hero-meta {
+ display: flex;
+ gap: 1.5rem;
+ margin-top: 1rem;
+ font-size: 0.875rem;
+}
+
+.hero-meta span {
+ color: var(--text-tertiary);
+}
+
+.hero-meta span:first-child {
+ color: var(--warning);
+}
+
+/* Secondary Featured */
+.secondary-featured {
+ grid-column: 1 / -1;
+ height: 380px;
+ display: flex;
+ align-items: stretch;
+}
+
+.featured-secondary-cards {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+ justify-content: space-between;
+}
+
+.secondary-card {
+ background: linear-gradient(135deg, rgba(80, 255, 255, 0.03), rgba(243, 128, 245, 0.02));
+ border: 1px solid rgba(80, 255, 255, 0.3);
+ cursor: pointer;
+ transition: all 0.3s ease;
+ display: flex;
+ overflow: hidden;
+ height: calc((380px - 1.5rem) / 3);
+ flex: 1;
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
+}
+
+.secondary-card:hover {
+ border-color: var(--accent-pink);
+ background: linear-gradient(135deg, rgba(243, 128, 245, 0.05), rgba(80, 255, 255, 0.03));
+ box-shadow: 0 4px 15px rgba(243, 128, 245, 0.2);
+ transform: translateX(-3px);
+}
+
+.secondary-image {
+ width: 120px;
+ background: linear-gradient(135deg, var(--bg-tertiary), var(--bg-secondary));
+ background-size: cover;
+ background-position: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.5rem;
+ color: var(--primary-cyan);
+ flex-shrink: 0;
+}
+
+.secondary-content {
+ flex: 1;
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.secondary-title {
+ font-size: 1rem;
+ color: var(--text-primary);
+ margin-bottom: 0.25rem;
+}
+
+.secondary-desc {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.secondary-meta {
+ font-size: 0.75rem;
+ color: var(--text-tertiary);
+}
+
+.secondary-meta span:last-child {
+ color: var(--warning);
+}
+
+/* Sponsored Section */
+.sponsored-section {
+ grid-column: 1 / -1;
+ background: var(--bg-secondary);
+ border: 1px solid var(--warning);
+ padding: 1rem;
+ position: relative;
+}
+
+.section-label {
+ position: absolute;
+ top: -0.5rem;
+ left: 1rem;
+ background: var(--bg-secondary);
+ padding: 0 0.5rem;
+ color: var(--warning);
+ font-size: 0.65rem;
+ letter-spacing: 0.1em;
+}
+
+.sponsored-cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 1rem;
+}
+
+.sponsor-card {
+ padding: 1rem;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+}
+
+.sponsor-card h4 {
+ color: var(--accent-pink);
+ margin-bottom: 0.5rem;
+}
+
+.sponsor-card p {
+ color: var(--text-secondary);
+ font-size: 0.85rem;
+ margin-bottom: 0.75rem;
+}
+
+.sponsor-card a {
+ color: var(--primary-cyan);
+ text-decoration: none;
+ font-size: 0.85rem;
+}
+
+.sponsor-card a:hover {
+ color: var(--accent-pink);
+}
+
+/* Main Content Grid */
+.main-content {
+ grid-column: 1 / -1;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+}
+
+/* Column Headers */
+.column-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 1rem;
+ border-bottom: 1px solid var(--border-color);
+ padding-bottom: 0.5rem;
+}
+
+.column-header h2 {
+ font-size: 1.1rem;
+ color: var(--text-primary);
+}
+
+.mini-filter {
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ color: var(--text-primary);
+ padding: 0.25rem 0.5rem;
+ font-family: inherit;
+ font-size: 0.75rem;
+}
+
+.ascii-icon {
+ color: var(--primary-cyan);
+}
+
+/* Apps Column */
+.apps-compact-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.app-compact {
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-left: 3px solid var(--border-color);
+ padding: 0.75rem;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.app-compact:hover {
+ border-color: var(--primary-cyan);
+ border-left-color: var(--accent-pink);
+ transform: translateX(2px);
+}
+
+.app-compact-header {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.75rem;
+ color: var(--text-tertiary);
+ margin-bottom: 0.25rem;
+}
+
+.app-compact-header span:first-child {
+ color: var(--primary-cyan);
+}
+
+.app-compact-header span:last-child {
+ color: var(--warning);
+}
+
+.app-compact-title {
+ font-size: 0.9rem;
+ color: var(--text-primary);
+ margin-bottom: 0.25rem;
+}
+
+.app-compact-desc {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+/* Articles Column */
+.articles-compact-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.article-compact {
+ border-left: 2px solid var(--border-color);
+ padding-left: 1rem;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.article-compact:hover {
+ border-left-color: var(--primary-cyan);
+}
+
+.article-meta {
+ font-size: 0.7rem;
+ color: var(--text-tertiary);
+ margin-bottom: 0.25rem;
+}
+
+.article-meta span:first-child {
+ color: var(--accent-pink);
+}
+
+.article-title {
+ font-size: 0.9rem;
+ color: var(--text-primary);
+ margin-bottom: 0.25rem;
+}
+
+.article-author {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+}
+
+/* Trending Column */
+.trending-items {
+ display: flex;
+ flex-direction: column;
+ gap: 0.5rem;
+}
+
+.trending-item {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.5rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.trending-item:hover {
+ border-color: var(--primary-cyan);
+}
+
+.trending-rank {
+ font-size: 1.2rem;
+ color: var(--primary-cyan);
+ width: 2rem;
+ text-align: center;
+}
+
+.trending-info {
+ flex: 1;
+}
+
+.trending-name {
+ font-size: 0.85rem;
+ color: var(--text-primary);
+}
+
+.trending-stats {
+ font-size: 0.7rem;
+ color: var(--text-tertiary);
+}
+
+/* Submit Box */
+.submit-box {
+ margin-top: 1.5rem;
+ background: var(--bg-secondary);
+ border: 1px solid var(--primary-cyan);
+ padding: 1rem;
+ text-align: center;
+}
+
+.submit-box h3 {
+ font-size: 1rem;
+ color: var(--primary-cyan);
+ margin-bottom: 0.5rem;
+}
+
+.submit-box p {
+ font-size: 0.8rem;
+ color: var(--text-secondary);
+ margin-bottom: 0.75rem;
+}
+
+.submit-btn {
+ display: inline-block;
+ padding: 0.5rem 1rem;
+ background: transparent;
+ border: 1px solid var(--primary-cyan);
+ color: var(--primary-cyan);
+ text-decoration: none;
+ transition: all 0.2s;
+}
+
+.submit-btn:hover {
+ background: var(--primary-cyan);
+ color: var(--bg-dark);
+}
+
+/* More Apps Section */
+.more-apps {
+ grid-column: 1 / -1;
+ margin-top: 2rem;
+}
+
+.section-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 1rem;
+}
+
+.more-apps-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 1rem;
+}
+
+.load-more-btn {
+ background: transparent;
+ border: 1px solid var(--border-color);
+ color: var(--text-secondary);
+ padding: 0.5rem 1.5rem;
+ font-family: inherit;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+
+.load-more-btn:hover {
+ border-color: var(--primary-cyan);
+ color: var(--primary-cyan);
+}
+
+/* Footer */
+.marketplace-footer {
+ background: var(--bg-secondary);
+ border-top: 1px solid var(--border-color);
+ margin-top: 4rem;
+ padding: 2rem 0;
+}
+
+.footer-content {
+ max-width: 1800px;
+ margin: 0 auto;
+ padding: 0 2rem;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 2rem;
+}
+
+.footer-section h3 {
+ font-size: 1rem;
+ margin-bottom: 0.5rem;
+ color: var(--primary-cyan);
+}
+
+.footer-section p {
+ font-size: 0.875rem;
+ color: var(--text-secondary);
+ margin-bottom: 1rem;
+}
+
+.sponsor-btn {
+ display: inline-block;
+ padding: 0.5rem 1rem;
+ background: transparent;
+ border: 1px solid var(--primary-cyan);
+ color: var(--primary-cyan);
+ text-decoration: none;
+ transition: all 0.2s;
+}
+
+.sponsor-btn:hover {
+ background: var(--primary-cyan);
+ color: var(--bg-dark);
+}
+
+.footer-bottom {
+ max-width: 1800px;
+ margin: 2rem auto 0;
+ padding: 1rem 2rem 0;
+ border-top: 1px solid var(--border-color);
+ font-size: 0.75rem;
+ color: var(--text-tertiary);
+}
+
+/* Modal */
+.modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.8);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1000;
+}
+
+.modal.hidden {
+ display: none;
+}
+
+.modal-content {
+ background: var(--bg-secondary);
+ border: 1px solid var(--primary-cyan);
+ max-width: 800px;
+ width: 90%;
+ max-height: 80vh;
+ overflow-y: auto;
+ position: relative;
+}
+
+.modal-close {
+ position: absolute;
+ top: 1rem;
+ right: 1rem;
+ background: transparent;
+ border: 1px solid var(--border-color);
+ color: var(--text-primary);
+ padding: 0.25rem 0.5rem;
+ cursor: pointer;
+ font-size: 1.2rem;
+}
+
+.modal-close:hover {
+ border-color: var(--error);
+ color: var(--error);
+}
+
+.app-detail {
+ padding: 2rem;
+}
+
+.app-detail h2 {
+ font-size: 1.5rem;
+ margin-bottom: 1rem;
+ color: var(--primary-cyan);
+}
+
+/* Loading */
+.loading {
+ text-align: center;
+ padding: 2rem;
+ color: var(--text-tertiary);
+}
+
+.no-results {
+ text-align: center;
+ padding: 2rem;
+ color: var(--text-tertiary);
+}
+
+/* Responsive - Tablet */
+@media (min-width: 768px) {
+ .magazine-layout {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .hero-featured {
+ grid-column: 1 / -1;
+ }
+
+ .secondary-featured {
+ grid-column: 1 / -1;
+ }
+
+ .sponsored-section {
+ grid-column: 1 / -1;
+ }
+
+ .main-content {
+ grid-column: 1 / -1;
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+/* Responsive - Desktop */
+@media (min-width: 1024px) {
+ .magazine-layout {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ .hero-featured {
+ grid-column: 1 / 3;
+ grid-row: 1;
+ }
+
+ .secondary-featured {
+ grid-column: 3 / 4;
+ grid-row: 1;
+ }
+
+ .featured-secondary-cards {
+ flex-direction: column;
+ }
+
+ .sponsored-section {
+ grid-column: 1 / -1;
+ }
+
+ .main-content {
+ grid-column: 1 / -1;
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+/* Responsive - Wide Desktop */
+@media (min-width: 1400px) {
+ .magazine-layout {
+ grid-template-columns: repeat(4, 1fr);
+ }
+
+ .hero-featured {
+ grid-column: 1 / 3;
+ }
+
+ .secondary-featured {
+ grid-column: 3 / 5;
+ grid-row: 1;
+ }
+
+ .featured-secondary-cards {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .main-content {
+ grid-template-columns: repeat(4, 1fr);
+ }
+
+ .apps-column {
+ grid-column: span 2;
+ }
+
+ .more-apps-grid {
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ }
+}
+
+/* Responsive - Ultra Wide Desktop (for coders with wide monitors) */
+@media (min-width: 1800px) {
+ .magazine-layout {
+ grid-template-columns: repeat(5, 1fr);
+ }
+
+ .hero-featured {
+ grid-column: 1 / 3;
+ }
+
+ .secondary-featured {
+ grid-column: 3 / 6;
+ }
+
+ .featured-secondary-cards {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ .sponsored-section {
+ grid-column: 1 / -1;
+ }
+
+ .sponsored-cards {
+ grid-template-columns: repeat(5, 1fr);
+ }
+
+ .main-content {
+ grid-template-columns: repeat(5, 1fr);
+ }
+
+ .apps-column {
+ grid-column: span 2;
+ }
+
+ .articles-column {
+ grid-column: span 2;
+ }
+
+ .more-apps-grid {
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ }
+}
+
+/* Responsive - Mobile */
+@media (max-width: 767px) {
+ .header-content {
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .search-filter-bar {
+ flex-direction: column;
+ align-items: stretch;
+ }
+
+ .search-box {
+ max-width: none;
+ }
+
+ .magazine-layout {
+ padding: 0 1rem 2rem;
+ }
+
+ .footer-content {
+ grid-template-columns: 1fr;
+ }
+
+ .secondary-card {
+ flex-direction: column;
+ }
+
+ .secondary-image {
+ width: 100%;
+ height: 150px;
+ }
+}
\ No newline at end of file
diff --git a/docs/md_v2/marketplace/marketplace.js b/docs/md_v2/marketplace/marketplace.js
new file mode 100644
index 00000000..94a401bf
--- /dev/null
+++ b/docs/md_v2/marketplace/marketplace.js
@@ -0,0 +1,395 @@
+// Marketplace JS - Magazine Layout
+const API_BASE = '/api';
+const CACHE_TTL = 3600000; // 1 hour in ms
+
+class MarketplaceCache {
+ constructor() {
+ this.prefix = 'c4ai_market_';
+ }
+
+ get(key) {
+ const item = localStorage.getItem(this.prefix + key);
+ if (!item) return null;
+
+ const data = JSON.parse(item);
+ if (Date.now() > data.expires) {
+ localStorage.removeItem(this.prefix + key);
+ return null;
+ }
+ return data.value;
+ }
+
+ set(key, value, ttl = CACHE_TTL) {
+ const data = {
+ value: value,
+ expires: Date.now() + ttl
+ };
+ localStorage.setItem(this.prefix + key, JSON.stringify(data));
+ }
+
+ clear() {
+ Object.keys(localStorage)
+ .filter(k => k.startsWith(this.prefix))
+ .forEach(k => localStorage.removeItem(k));
+ }
+}
+
+class MarketplaceAPI {
+ constructor() {
+ this.cache = new MarketplaceCache();
+ this.searchTimeout = null;
+ }
+
+ async fetch(endpoint, useCache = true) {
+ const cacheKey = endpoint.replace(/[^\w]/g, '_');
+
+ if (useCache) {
+ const cached = this.cache.get(cacheKey);
+ if (cached) return cached;
+ }
+
+ try {
+ const response = await fetch(`${API_BASE}${endpoint}`);
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
+
+ const data = await response.json();
+ this.cache.set(cacheKey, data);
+ return data;
+ } catch (error) {
+ console.error('API Error:', error);
+ return null;
+ }
+ }
+
+ async getStats() {
+ return this.fetch('/stats');
+ }
+
+ async getCategories() {
+ return this.fetch('/categories');
+ }
+
+ async getApps(params = {}) {
+ const query = new URLSearchParams(params).toString();
+ return this.fetch(`/apps${query ? '?' + query : ''}`);
+ }
+
+ async getArticles(params = {}) {
+ const query = new URLSearchParams(params).toString();
+ return this.fetch(`/articles${query ? '?' + query : ''}`);
+ }
+
+ async getSponsors() {
+ return this.fetch('/sponsors');
+ }
+
+ async search(query) {
+ if (query.length < 2) return {};
+ return this.fetch(`/search?q=${encodeURIComponent(query)}`, false);
+ }
+}
+
+class MarketplaceUI {
+ constructor() {
+ this.api = new MarketplaceAPI();
+ this.currentCategory = 'all';
+ this.currentType = '';
+ this.searchTimeout = null;
+ this.loadedApps = 10;
+ this.init();
+ }
+
+ async init() {
+ await this.loadStats();
+ await this.loadCategories();
+ await this.loadFeaturedContent();
+ await this.loadSponsors();
+ await this.loadMainContent();
+ this.setupEventListeners();
+ }
+
+ async loadStats() {
+ const stats = await this.api.getStats();
+ if (stats) {
+ document.getElementById('total-apps').textContent = stats.total_apps || '0';
+ document.getElementById('total-articles').textContent = stats.total_articles || '0';
+ document.getElementById('total-downloads').textContent = stats.total_downloads || '0';
+ document.getElementById('last-update').textContent = new Date().toLocaleDateString();
+ }
+ }
+
+ async loadCategories() {
+ const categories = await this.api.getCategories();
+ if (!categories) return;
+
+ const filter = document.getElementById('category-filter');
+ categories.forEach(cat => {
+ const btn = document.createElement('button');
+ btn.className = 'filter-btn';
+ btn.dataset.category = cat.slug;
+ btn.textContent = cat.name;
+ btn.onclick = () => this.filterByCategory(cat.slug);
+ filter.appendChild(btn);
+ });
+ }
+
+ async loadFeaturedContent() {
+ // Load hero featured
+ const featured = await this.api.getApps({ featured: true, limit: 4 });
+ if (!featured || !featured.length) return;
+
+ // Hero card (first featured)
+ const hero = featured[0];
+ const heroCard = document.getElementById('featured-hero');
+ if (hero) {
+ const imageUrl = hero.image || '';
+ heroCard.innerHTML = `
+
+ ${!imageUrl ? `[${hero.category || 'APP'}]` : ''}
+
+
+
${hero.type || 'PAID'}
+
${hero.name}
+
${hero.description}
+
+ ★ ${hero.rating || 0}/5
+ ${hero.downloads || 0} downloads
+
+
+ `;
+ heroCard.onclick = () => this.showAppDetail(hero);
+ }
+
+ // Secondary featured cards
+ const secondary = document.getElementById('featured-secondary');
+ secondary.innerHTML = '';
+ if (featured.length > 1) {
+ featured.slice(1, 4).forEach(app => {
+ const card = document.createElement('div');
+ card.className = 'secondary-card';
+ const imageUrl = app.image || '';
+ card.innerHTML = `
+
+ ${!imageUrl ? `[${app.category || 'APP'}]` : ''}
+
+
+
${app.name}
+
${(app.description || '').substring(0, 100)}...
+
+ ${app.type || 'Open Source'} · ★ ${app.rating || 0}/5
+
+
+ `;
+ card.onclick = () => this.showAppDetail(app);
+ secondary.appendChild(card);
+ });
+ }
+ }
+
+ async loadSponsors() {
+ const sponsors = await this.api.getSponsors();
+ if (!sponsors || !sponsors.length) {
+ // Show placeholder if no sponsors
+ const container = document.getElementById('sponsored-content');
+ container.innerHTML = `
+
+ `;
+ return;
+ }
+
+ const container = document.getElementById('sponsored-content');
+ container.innerHTML = sponsors.slice(0, 5).map(sponsor => `
+
+ `).join('');
+ }
+
+ async loadMainContent() {
+ // Load apps column
+ const apps = await this.api.getApps({ limit: 8 });
+ if (apps && apps.length) {
+ const appsGrid = document.getElementById('apps-grid');
+ appsGrid.innerHTML = apps.map(app => `
+
+
+
${app.name}
+
${app.description}
+
+ `).join('');
+ }
+
+ // Load articles column
+ const articles = await this.api.getArticles({ limit: 6 });
+ if (articles && articles.length) {
+ const articlesList = document.getElementById('articles-list');
+ articlesList.innerHTML = articles.map(article => `
+
+
+ ${article.category} · ${new Date(article.published_at).toLocaleDateString()}
+
+
${article.title}
+
by ${article.author}
+
+ `).join('');
+ }
+
+ // Load trending
+ if (apps && apps.length) {
+ const trending = apps.slice(0, 5);
+ const trendingList = document.getElementById('trending-list');
+ trendingList.innerHTML = trending.map((app, i) => `
+
+
${i + 1}
+
+
${app.name}
+
${app.downloads} downloads
+
+
+ `).join('');
+ }
+
+ // Load more apps grid
+ const moreApps = await this.api.getApps({ offset: 8, limit: 12 });
+ if (moreApps && moreApps.length) {
+ const moreGrid = document.getElementById('more-apps-grid');
+ moreGrid.innerHTML = moreApps.map(app => `
+
+ `).join('');
+ }
+ }
+
+ setupEventListeners() {
+ // Search
+ const searchInput = document.getElementById('search-input');
+ searchInput.addEventListener('input', (e) => {
+ clearTimeout(this.searchTimeout);
+ this.searchTimeout = setTimeout(() => this.search(e.target.value), 300);
+ });
+
+ // Keyboard shortcut
+ document.addEventListener('keydown', (e) => {
+ if (e.key === '/' && !searchInput.contains(document.activeElement)) {
+ e.preventDefault();
+ searchInput.focus();
+ }
+ if (e.key === 'Escape' && searchInput.contains(document.activeElement)) {
+ searchInput.blur();
+ searchInput.value = '';
+ }
+ });
+
+ // Type filter
+ const typeFilter = document.getElementById('type-filter');
+ typeFilter.addEventListener('change', (e) => {
+ this.currentType = e.target.value;
+ this.loadMainContent();
+ });
+
+ // Load more
+ const loadMore = document.getElementById('load-more');
+ loadMore.addEventListener('click', () => this.loadMoreApps());
+ }
+
+ async filterByCategory(category) {
+ // Update active state
+ document.querySelectorAll('.filter-btn').forEach(btn => {
+ btn.classList.toggle('active', btn.dataset.category === category);
+ });
+
+ this.currentCategory = category;
+ await this.loadMainContent();
+ }
+
+ async search(query) {
+ if (!query) {
+ await this.loadMainContent();
+ return;
+ }
+
+ const results = await this.api.search(query);
+ if (!results) return;
+
+ // Update apps grid with search results
+ if (results.apps && results.apps.length) {
+ const appsGrid = document.getElementById('apps-grid');
+ appsGrid.innerHTML = results.apps.map(app => `
+
+
+
${app.name}
+
${app.description}
+
+ `).join('');
+ }
+
+ // Update articles with search results
+ if (results.articles && results.articles.length) {
+ const articlesList = document.getElementById('articles-list');
+ articlesList.innerHTML = results.articles.map(article => `
+
+
+ ${article.category} · ${new Date(article.published_at).toLocaleDateString()}
+
+
${article.title}
+
by ${article.author}
+
+ `).join('');
+ }
+ }
+
+ async loadMoreApps() {
+ this.loadedApps += 12;
+ const moreApps = await this.api.getApps({ offset: this.loadedApps, limit: 12 });
+ if (moreApps && moreApps.length) {
+ const moreGrid = document.getElementById('more-apps-grid');
+ moreApps.forEach(app => {
+ const card = document.createElement('div');
+ card.className = 'app-compact';
+ card.innerHTML = `
+
+ ${app.name}
+ `;
+ card.onclick = () => this.showAppDetail(app);
+ moreGrid.appendChild(card);
+ });
+ }
+ }
+
+ showAppDetail(app) {
+ // Navigate to detail page instead of showing modal
+ const slug = app.slug || app.name.toLowerCase().replace(/\s+/g, '-');
+ window.location.href = `app-detail.html?app=${slug}`;
+ }
+
+ showArticle(articleId) {
+ // Could create article detail page similarly
+ console.log('Show article:', articleId);
+ }
+}
+
+// Initialize marketplace
+let marketplace;
+document.addEventListener('DOMContentLoaded', () => {
+ marketplace = new MarketplaceUI();
+});
\ No newline at end of file
diff --git a/mkdocs.yml b/mkdocs.yml
index d39172f6..6406b028 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -14,7 +14,7 @@ nav:
- "Demo Apps": "apps/index.md"
- "C4A-Script Editor": "apps/c4a-script/index.html"
- "LLM Context Builder": "apps/llmtxt/index.html"
- - "Marketplace": "marketplace/frontend/index.html"
+ - "Marketplace": "marketplace/index.html"
- "Marketplace Admin": "marketplace/admin/index.html"
- Setup & Installation:
- "Installation": "core/installation.md"