← back to Handbag Authentication

public/mobile.html

737 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <title>Handbag Data - Mobile</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            -webkit-tap-highlight-color: transparent;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background: #f5f5f7;
            color: #1d1d1f;
            overflow-x: hidden;
        }

        /* Header */
        .mobile-header {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border-bottom: 1px solid rgba(0, 0, 0, 0.1);
            z-index: 1000;
            padding: env(safe-area-inset-top) 16px 12px;
        }

        .header-content {
            display: flex;
            align-items: center;
            justify-content: space-between;
        }

        .logo {
            font-size: 20px;
            font-weight: 700;
            color: #1d1d1f;
        }

        .menu-btn {
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            padding: 8px;
        }

        /* Search Bar */
        .search-container {
            position: fixed;
            top: calc(env(safe-area-inset-top) + 52px);
            left: 0;
            right: 0;
            padding: 12px 16px;
            background: #f5f5f7;
            z-index: 999;
        }

        .search-bar {
            display: flex;
            align-items: center;
            background: white;
            border-radius: 12px;
            padding: 10px 16px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
        }

        .search-bar input {
            flex: 1;
            border: none;
            outline: none;
            font-size: 16px;
            background: transparent;
        }

        .search-icon {
            margin-right: 8px;
            opacity: 0.6;
        }

        /* Filter Pills */
        .filter-pills {
            position: fixed;
            top: calc(env(safe-area-inset-top) + 116px);
            left: 0;
            right: 0;
            padding: 8px 16px;
            background: #f5f5f7;
            overflow-x: auto;
            white-space: nowrap;
            z-index: 998;
            -webkit-overflow-scrolling: touch;
        }

        .filter-pills::-webkit-scrollbar {
            display: none;
        }

        .pill {
            display: inline-block;
            padding: 8px 16px;
            background: white;
            border-radius: 20px;
            margin-right: 8px;
            font-size: 14px;
            border: 1px solid #e0e0e0;
            cursor: pointer;
            transition: all 0.2s;
        }

        .pill.active {
            background: #1d1d1f;
            color: white;
            border-color: #1d1d1f;
        }

        /* Main Content */
        .main-content {
            margin-top: calc(env(safe-area-inset-top) + 180px);
            padding: 16px;
            padding-bottom: calc(env(safe-area-inset-bottom) + 80px);
        }

        /* Stats Cards */
        .stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 12px;
            margin-bottom: 24px;
        }

        .stat-card {
            background: white;
            border-radius: 16px;
            padding: 16px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
        }

        .stat-value {
            font-size: 28px;
            font-weight: 700;
            color: #1d1d1f;
            margin-bottom: 4px;
        }

        .stat-label {
            font-size: 12px;
            color: #86868b;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        /* Product Card */
        .product-card {
            background: white;
            border-radius: 16px;
            overflow: hidden;
            margin-bottom: 16px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
        }

        .product-image {
            width: 100%;
            height: 240px;
            object-fit: cover;
            background: #f0f0f0;
        }

        .product-info {
            padding: 16px;
        }

        .product-brand {
            font-size: 12px;
            color: #86868b;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            margin-bottom: 4px;
        }

        .product-name {
            font-size: 16px;
            font-weight: 600;
            color: #1d1d1f;
            margin-bottom: 8px;
            line-height: 1.3;
        }

        .product-price {
            font-size: 18px;
            font-weight: 700;
            color: #1d1d1f;
            margin-bottom: 12px;
        }

        .product-tags {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
        }

        .tag {
            padding: 4px 10px;
            background: #f5f5f7;
            border-radius: 12px;
            font-size: 11px;
            color: #1d1d1f;
        }

        /* 360 Viewer Badge */
        .badge-360 {
            position: absolute;
            top: 12px;
            right: 12px;
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 6px 12px;
            border-radius: 20px;
            font-size: 11px;
            font-weight: 600;
            backdrop-filter: blur(10px);
        }

        /* Bottom Navigation */
        .bottom-nav {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border-top: 1px solid rgba(0, 0, 0, 0.1);
            padding: 8px 0 calc(env(safe-area-inset-bottom) + 8px);
            z-index: 1000;
        }

        .nav-items {
            display: flex;
            justify-content: space-around;
        }

        .nav-item {
            flex: 1;
            text-align: center;
            padding: 8px;
            color: #86868b;
            text-decoration: none;
            transition: color 0.2s;
        }

        .nav-item.active {
            color: #1d1d1f;
        }

        .nav-icon {
            font-size: 24px;
            margin-bottom: 4px;
        }

        .nav-label {
            font-size: 10px;
            display: block;
        }

        /* Loading Spinner */
        .loading {
            text-align: center;
            padding: 40px;
            color: #86868b;
        }

        .spinner {
            border: 3px solid #f3f3f3;
            border-top: 3px solid #1d1d1f;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 0 auto 16px;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        /* Pull to Refresh */
        .pull-to-refresh {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #86868b;
            font-size: 14px;
            transform: translateY(-100%);
            transition: transform 0.3s;
        }

        .pull-to-refresh.active {
            transform: translateY(0);
        }

        /* Modal for 360 Viewer */
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.95);
            z-index: 2000;
            padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom);
        }

        .modal.active {
            display: flex;
            flex-direction: column;
        }

        .modal-header {
            padding: 16px;
            color: white;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .close-btn {
            background: none;
            border: none;
            color: white;
            font-size: 28px;
            cursor: pointer;
            padding: 8px;
        }

        .viewer-360 {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
        }

        .viewer-360 img {
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
        }

        .viewer-controls {
            padding: 16px;
            color: white;
            text-align: center;
        }

        .angle-indicator {
            font-size: 24px;
            font-weight: 700;
            margin-bottom: 8px;
        }

        .swipe-hint {
            font-size: 12px;
            opacity: 0.7;
        }

        /* Dark Mode Support */
        @media (prefers-color-scheme: dark) {
            body {
                background: #000;
                color: #f5f5f7;
            }

            .mobile-header,
            .search-container,
            .filter-pills,
            .bottom-nav {
                background: rgba(29, 29, 29, 0.95);
                border-color: rgba(255, 255, 255, 0.1);
            }

            .search-bar,
            .stat-card,
            .product-card {
                background: #1d1d1f;
            }

            .pill {
                background: #2d2d2d;
                border-color: #3d3d3d;
                color: #f5f5f7;
            }

            .pill.active {
                background: #f5f5f7;
                color: #1d1d1f;
            }

            .tag {
                background: #2d2d2d;
                color: #f5f5f7;
            }
        }
    </style>
</head>
<body>
    <!-- Header -->
    <div class="mobile-header">
        <div class="header-content">
            <div class="logo">👜 Handbags</div>
            <button class="menu-btn" onclick="toggleMenu()">☰</button>
        </div>
    </div>

    <!-- Search -->
    <div class="search-container">
        <div class="search-bar">
            <span class="search-icon">🔍</span>
            <input type="text" placeholder="Search brands, styles..." id="searchInput" onkeyup="filterProducts()">
        </div>
    </div>

    <!-- Filter Pills -->
    <div class="filter-pills">
        <span class="pill active" onclick="filterByCategory('all')">All</span>
        <span class="pill" onclick="filterByCategory('luxury')">Luxury</span>
        <span class="pill" onclick="filterByCategory('designer')">Designer</span>
        <span class="pill" onclick="filterByCategory('360')">360° View</span>
        <span class="pill" onclick="filterByCategory('french')">French Brands</span>
        <span class="pill" onclick="filterByCategory('italian')">Italian Brands</span>
    </div>

    <!-- Main Content -->
    <div class="main-content">
        <!-- Stats -->
        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-value" id="totalItems">4,056</div>
                <div class="stat-label">Total Items</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="totalBrands">100+</div>
                <div class="stat-label">Brands</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">586K</div>
                <div class="stat-label">360° Images</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">$45-37K</div>
                <div class="stat-label">Price Range</div>
            </div>
        </div>

        <!-- Products List -->
        <div id="productsList">
            <div class="loading">
                <div class="spinner"></div>
                Loading handbags...
            </div>
        </div>
    </div>

    <!-- Bottom Navigation -->
    <div class="bottom-nav">
        <div class="nav-items">
            <a href="#" class="nav-item active">
                <div class="nav-icon">🏠</div>
                <span class="nav-label">Home</span>
            </a>
            <a href="mobile-camera.html" class="nav-item">
                <div class="nav-icon">📸</div>
                <span class="nav-label">Camera</span>
            </a>
            <a href="#" class="nav-item" onclick="showFilter()">
                <div class="nav-icon">🔍</div>
                <span class="nav-label">Search</span>
            </a>
            <a href="#" class="nav-item" onclick="show360Gallery()">
                <div class="nav-icon">360°</div>
                <span class="nav-label">360° View</span>
            </a>
            <a href="#" class="nav-item" onclick="showStats()">
                <div class="nav-icon">📊</div>
                <span class="nav-label">Stats</span>
            </a>
        </div>
    </div>

    <!-- 360 Viewer Modal -->
    <div class="modal" id="viewer360Modal">
        <div class="modal-header">
            <h3 id="modalTitle">360° View</h3>
            <button class="close-btn" onclick="close360Viewer()">×</button>
        </div>
        <div class="viewer-360" id="viewer360">
            <img id="viewer360Image" src="" alt="360 view">
        </div>
        <div class="viewer-controls">
            <div class="angle-indicator" id="angleIndicator">0°</div>
            <div class="swipe-hint">← Swipe to rotate →</div>
        </div>
    </div>

    <script>
        // Sample data structure
        const sampleProducts = [
            {
                id: 1,
                brand: 'Hermès',
                name: 'Birkin 30 Togo Leather',
                price: 12500,
                image: '/api/placeholder/400/400',
                has360: true,
                type: 'luxury',
                tags: ['French', 'Iconic', 'Investment']
            },
            {
                id: 2,
                brand: 'Chanel',
                name: 'Classic Flap Medium',
                price: 8800,
                image: '/api/placeholder/400/400',
                has360: true,
                type: 'luxury',
                tags: ['French', 'Timeless', 'Quilted']
            },
            {
                id: 3,
                brand: 'Louis Vuitton',
                name: 'Neverfull MM Monogram',
                price: 1850,
                image: '/api/placeholder/400/400',
                has360: false,
                type: 'luxury',
                tags: ['French', 'Tote', 'Canvas']
            },
            {
                id: 4,
                brand: 'Gucci',
                name: 'GG Marmont Small',
                price: 2450,
                image: '/api/placeholder/400/400',
                has360: true,
                type: 'designer',
                tags: ['Italian', 'Crossbody', 'Leather']
            },
            {
                id: 5,
                brand: 'Prada',
                name: 'Galleria Saffiano Medium',
                price: 3200,
                image: '/api/placeholder/400/400',
                has360: true,
                type: 'luxury',
                tags: ['Italian', 'Professional', 'Structured']
            }
        ];

        let currentFilter = 'all';
        let currentAngle = 0;

        // Initialize on load
        window.addEventListener('load', function() {
            loadProducts();
            setupTouchEvents();
        });

        // Load products from API
        async function loadProducts() {
            try {
                // In production, fetch from API
                // const response = await fetch('/api/handbags');
                // const products = await response.json();

                // For now, use sample data
                setTimeout(() => {
                    displayProducts(sampleProducts);
                }, 1000);
            } catch (error) {
                console.error('Error loading products:', error);
                document.getElementById('productsList').innerHTML =
                    '<p style="text-align:center;color:#86868b;">Error loading products</p>';
            }
        }

        // Display products
        function displayProducts(products) {
            const container = document.getElementById('productsList');
            container.innerHTML = products.map(product => `
                <div class="product-card" onclick="viewProduct(${product.id})">
                    <div style="position:relative">
                        <img src="${product.image}" alt="${product.name}" class="product-image">
                        ${product.has360 ? '<div class="badge-360">360° VIEW</div>' : ''}
                    </div>
                    <div class="product-info">
                        <div class="product-brand">${product.brand}</div>
                        <div class="product-name">${product.name}</div>
                        <div class="product-price">$${product.price.toLocaleString()}</div>
                        <div class="product-tags">
                            ${product.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
                        </div>
                    </div>
                </div>
            `).join('');
        }

        // Filter products
        function filterByCategory(category) {
            currentFilter = category;

            // Update pill states
            document.querySelectorAll('.pill').forEach(pill => {
                pill.classList.remove('active');
            });
            event.target.classList.add('active');

            // Filter products
            let filtered = sampleProducts;
            if (category !== 'all') {
                if (category === '360') {
                    filtered = sampleProducts.filter(p => p.has360);
                } else if (category === 'french') {
                    filtered = sampleProducts.filter(p => p.tags.includes('French'));
                } else if (category === 'italian') {
                    filtered = sampleProducts.filter(p => p.tags.includes('Italian'));
                } else {
                    filtered = sampleProducts.filter(p => p.type === category);
                }
            }

            displayProducts(filtered);
        }

        // Search products
        function filterProducts() {
            const searchTerm = document.getElementById('searchInput').value.toLowerCase();
            const filtered = sampleProducts.filter(p =>
                p.brand.toLowerCase().includes(searchTerm) ||
                p.name.toLowerCase().includes(searchTerm) ||
                p.tags.some(tag => tag.toLowerCase().includes(searchTerm))
            );
            displayProducts(filtered);
        }

        // View product details
        function viewProduct(id) {
            const product = sampleProducts.find(p => p.id === id);
            if (product && product.has360) {
                open360Viewer(product);
            } else {
                alert('Product details coming soon!');
            }
        }

        // Open 360 viewer
        function open360Viewer(product) {
            document.getElementById('modalTitle').textContent = product.brand + ' - ' + product.name;
            document.getElementById('viewer360Image').src = product.image;
            document.getElementById('viewer360Modal').classList.add('active');
            currentAngle = 0;
            updateAngleIndicator();
        }

        // Close 360 viewer
        function close360Viewer() {
            document.getElementById('viewer360Modal').classList.remove('active');
        }

        // Touch events for 360 rotation
        function setupTouchEvents() {
            const viewer = document.getElementById('viewer360');
            let startX = 0;

            viewer.addEventListener('touchstart', (e) => {
                startX = e.touches[0].clientX;
            });

            viewer.addEventListener('touchmove', (e) => {
                const deltaX = e.touches[0].clientX - startX;
                const angleChange = Math.floor(deltaX / 5);
                currentAngle = (currentAngle + angleChange + 360) % 360;
                updateAngleIndicator();
                // In production: load image at current angle
                startX = e.touches[0].clientX;
            });
        }

        // Update angle indicator
        function updateAngleIndicator() {
            document.getElementById('angleIndicator').textContent = currentAngle + '°';
        }

        // Navigation functions
        function showFilter() {
            document.getElementById('searchInput').focus();
        }

        function show360Gallery() {
            filterByCategory('360');
        }

        function showStats() {
            alert('Detailed stats coming soon!');
        }

        function toggleMenu() {
            alert('Menu coming soon!');
        }

        // Service Worker for offline capability
        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('/sw.js').catch(err => {
                console.log('ServiceWorker registration failed:', err);
            });
        }
    </script>
</body>
</html>