diff --git a/static/admin/js/components.js b/static/admin/js/components.js
index 6d6f4ce0..fb8b40d0 100644
--- a/static/admin/js/components.js
+++ b/static/admin/js/components.js
@@ -32,8 +32,9 @@ function adminComponents() {
{ id: 'cards', name: 'Cards', icon: 'collection' },
{ id: 'badges', name: 'Badges', icon: 'tag' },
{ id: 'tables', name: 'Tables', icon: 'table' },
- { id: 'modals', name: 'Modals', icon: 'window' },
- { id: 'alerts', name: 'Alerts', icon: 'exclamation' }
+ { id: 'modals', name: 'Modals', icon: 'view-grid-add' },
+ { id: 'alerts', name: 'Alerts', icon: 'exclamation' },
+ { id: 'charts', name: 'Charts', icon: 'chart-pie' }
],
// Sample form data for examples
@@ -53,6 +54,10 @@ function adminComponents() {
required: 'This field is required'
},
+ // Modal state variables for examples
+ showExampleModal: false,
+ showFormModal: false,
+
// ✅ CRITICAL: Proper initialization with guard
async init() {
componentsLog.info('=== COMPONENTS PAGE INITIALIZING ===');
@@ -72,6 +77,11 @@ function adminComponents() {
this.setActiveSectionFromHash();
});
+ // Initialize charts after DOM is ready
+ this.$nextTick(() => {
+ this.initializeCharts();
+ });
+
componentsLog.info('=== COMPONENTS PAGE INITIALIZATION COMPLETE ===');
},
@@ -114,11 +124,18 @@ function adminComponents() {
async copyCode(code) {
try {
await navigator.clipboard.writeText(code);
- Utils.showToast('Code copied to clipboard!', 'success');
+ // Use the global Utils.showToast function
+ if (typeof Utils !== 'undefined' && Utils.showToast) {
+ Utils.showToast('Code copied to clipboard!', 'success');
+ } else {
+ componentsLog.warn('Utils.showToast not available');
+ }
componentsLog.debug('Code copied to clipboard');
} catch (error) {
componentsLog.error('Failed to copy code:', error);
- Utils.showToast('Failed to copy code', 'error');
+ if (typeof Utils !== 'undefined' && Utils.showToast) {
+ Utils.showToast('Failed to copy code', 'error');
+ }
}
},
@@ -132,7 +149,145 @@ function adminComponents() {
warning: 'Please review your input.',
info: 'Here is some information.'
};
- Utils.showToast(messages[type] || messages.info, type);
+
+ if (typeof Utils !== 'undefined' && Utils.showToast) {
+ Utils.showToast(messages[type] || messages.info, type);
+ } else {
+ componentsLog.error('Utils.showToast not available');
+ alert(messages[type] || messages.info); // Fallback to alert
+ }
+ },
+
+ /**
+ * Initialize Chart.js charts
+ */
+ initializeCharts() {
+ try {
+ // Check if Chart.js is loaded
+ if (typeof Chart === 'undefined') {
+ componentsLog.warn('Chart.js not loaded, skipping chart initialization');
+ return;
+ }
+
+ componentsLog.info('Initializing charts...');
+
+ // Pie Chart
+ const pieCanvas = document.getElementById('examplePieChart');
+ if (pieCanvas) {
+ const pieConfig = {
+ type: 'doughnut',
+ data: {
+ datasets: [{
+ data: [33, 33, 33],
+ backgroundColor: ['#0694a2', '#7e3af2', '#1c64f2'],
+ label: 'Dataset 1',
+ }],
+ labels: ['Shoes', 'Shirts', 'Bags'],
+ },
+ options: {
+ responsive: true,
+ cutoutPercentage: 80,
+ legend: {
+ display: false,
+ },
+ },
+ };
+ new Chart(pieCanvas, pieConfig);
+ componentsLog.debug('Pie chart initialized');
+ }
+
+ // Line Chart
+ const lineCanvas = document.getElementById('exampleLineChart');
+ if (lineCanvas) {
+ const lineConfig = {
+ type: 'line',
+ data: {
+ labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+ datasets: [{
+ label: 'Organic',
+ backgroundColor: '#0694a2',
+ borderColor: '#0694a2',
+ data: [43, 48, 40, 54, 67, 73, 70],
+ fill: false,
+ }, {
+ label: 'Paid',
+ fill: false,
+ backgroundColor: '#7e3af2',
+ borderColor: '#7e3af2',
+ data: [24, 50, 64, 74, 52, 51, 65],
+ }],
+ },
+ options: {
+ responsive: true,
+ legend: {
+ display: false,
+ },
+ tooltips: {
+ mode: 'index',
+ intersect: false,
+ },
+ hover: {
+ mode: 'nearest',
+ intersect: true,
+ },
+ scales: {
+ x: {
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Month',
+ },
+ },
+ y: {
+ display: true,
+ scaleLabel: {
+ display: true,
+ labelString: 'Value',
+ },
+ },
+ },
+ },
+ };
+ new Chart(lineCanvas, lineConfig);
+ componentsLog.debug('Line chart initialized');
+ }
+
+ // Bar Chart
+ const barCanvas = document.getElementById('exampleBarChart');
+ if (barCanvas) {
+ const barConfig = {
+ type: 'bar',
+ data: {
+ labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+ datasets: [{
+ label: 'Shoes',
+ backgroundColor: '#0694a2',
+ borderColor: '#0694a2',
+ borderWidth: 1,
+ data: [43, 48, 40, 54, 67, 73, 70],
+ }, {
+ label: 'Bags',
+ backgroundColor: '#7e3af2',
+ borderColor: '#7e3af2',
+ borderWidth: 1,
+ data: [24, 50, 64, 74, 52, 51, 65],
+ }],
+ },
+ options: {
+ responsive: true,
+ legend: {
+ display: false,
+ },
+ },
+ };
+ new Chart(barCanvas, barConfig);
+ componentsLog.debug('Bar chart initialized');
+ }
+
+ componentsLog.info('All charts initialized successfully');
+ } catch (error) {
+ componentsLog.error('Error initializing charts:', error);
+ }
}
};
}
diff --git a/static/admin/js/vendor-theme.js b/static/admin/js/vendor-theme.js
new file mode 100644
index 00000000..0f77c1ef
--- /dev/null
+++ b/static/admin/js/vendor-theme.js
@@ -0,0 +1,278 @@
+// static/admin/js/vendor-theme.js
+/**
+ * Vendor Theme Management Component
+ * Follows the established Alpine.js pattern from FRONTEND_ALPINE_PAGE_TEMPLATE.md
+ */
+
+const THEME_LOG_LEVEL = 3;
+
+const themeLog = {
+ error: (...args) => THEME_LOG_LEVEL >= 1 && console.error('❌ [THEME ERROR]', ...args),
+ warn: (...args) => THEME_LOG_LEVEL >= 2 && console.warn('⚠️ [THEME WARN]', ...args),
+ info: (...args) => THEME_LOG_LEVEL >= 3 && console.info('ℹ️ [THEME INFO]', ...args),
+ debug: (...args) => THEME_LOG_LEVEL >= 4 && console.log('🔍 [THEME DEBUG]', ...args)
+};
+
+// Theme presets
+const THEME_PRESETS = {
+ modern: {
+ colors: {
+ primary: "#6366f1",
+ secondary: "#8b5cf6",
+ accent: "#ec4899"
+ },
+ fonts: {
+ heading: "Inter, sans-serif",
+ body: "Inter, sans-serif"
+ },
+ layout: {
+ style: "grid",
+ header: "fixed"
+ }
+ },
+ classic: {
+ colors: {
+ primary: "#1e40af",
+ secondary: "#7c3aed",
+ accent: "#dc2626"
+ },
+ fonts: {
+ heading: "Georgia, serif",
+ body: "Arial, sans-serif"
+ },
+ layout: {
+ style: "list",
+ header: "static"
+ }
+ },
+ minimal: {
+ colors: {
+ primary: "#000000",
+ secondary: "#404040",
+ accent: "#666666"
+ },
+ fonts: {
+ heading: "Helvetica, sans-serif",
+ body: "Helvetica, sans-serif"
+ },
+ layout: {
+ style: "grid",
+ header: "transparent"
+ }
+ },
+ vibrant: {
+ colors: {
+ primary: "#f59e0b",
+ secondary: "#ef4444",
+ accent: "#8b5cf6"
+ },
+ fonts: {
+ heading: "Poppins, sans-serif",
+ body: "Open Sans, sans-serif"
+ },
+ layout: {
+ style: "masonry",
+ header: "fixed"
+ }
+ }
+};
+
+function vendorThemeData() {
+ return {
+ // ✅ CRITICAL: Inherit base layout functionality
+ ...data(),
+
+ // ✅ CRITICAL: Set page identifier
+ currentPage: 'vendor-theme',
+
+ // Page state
+ loading: false,
+ saving: false,
+ vendor: null,
+ vendorCode: window.location.pathname.split('/')[3], // Extract from /admin/vendors/{code}/theme
+
+ // Theme data
+ themeData: {
+ colors: {
+ primary: "#6366f1",
+ secondary: "#8b5cf6",
+ accent: "#ec4899"
+ },
+ fonts: {
+ heading: "Inter, sans-serif",
+ body: "Inter, sans-serif"
+ },
+ layout: {
+ style: "grid",
+ header: "fixed"
+ },
+ custom_css: ""
+ },
+
+ originalTheme: null, // For detecting changes
+
+ // ✅ CRITICAL: Proper initialization with guard
+ async init() {
+ themeLog.info('=== VENDOR THEME PAGE INITIALIZING ===');
+
+ // Prevent multiple initializations
+ if (window._vendorThemeInitialized) {
+ themeLog.warn('Page already initialized, skipping...');
+ return;
+ }
+ window._vendorThemeInitialized = true;
+
+ // Load data
+ await this.loadVendor();
+ await this.loadTheme();
+
+ themeLog.info('=== VENDOR THEME PAGE INITIALIZATION COMPLETE ===');
+ },
+
+ // Load vendor info
+ async loadVendor() {
+ themeLog.info('Loading vendor:', this.vendorCode);
+
+ try {
+ // ✅ CRITICAL: Use lowercase apiClient
+ const response = await apiClient.get(`/api/v1/admin/vendors/${this.vendorCode}`);
+ this.vendor = response;
+ themeLog.info('Vendor loaded:', this.vendor.name);
+ } catch (error) {
+ themeLog.error('Failed to load vendor:', error);
+ Utils.showToast('Failed to load vendor', 'error');
+ }
+ },
+
+ // Load theme configuration
+ async loadTheme() {
+ themeLog.info('Loading theme...');
+ this.loading = true;
+
+ try {
+ const startTime = Date.now();
+
+ // Get vendor's theme config from vendor object
+ if (this.vendor && this.vendor.theme_config) {
+ this.themeData = {
+ colors: this.vendor.theme_config.colors || this.themeData.colors,
+ fonts: this.vendor.theme_config.fonts || this.themeData.fonts,
+ layout: this.vendor.theme_config.layout || this.themeData.layout,
+ custom_css: this.vendor.theme_config.custom_css || ""
+ };
+ } else {
+ themeLog.info('No theme config found, using defaults');
+ }
+
+ // Store original for change detection
+ this.originalTheme = JSON.parse(JSON.stringify(this.themeData));
+
+ const duration = Date.now() - startTime;
+ themeLog.info(`Theme loaded in ${duration}ms`, this.themeData);
+
+ } catch (error) {
+ themeLog.error('Failed to load theme:', error);
+ Utils.showToast('Failed to load theme', 'error');
+ } finally {
+ this.loading = false;
+ }
+ },
+
+ // Save theme configuration
+ async saveTheme() {
+ themeLog.info('Saving theme...');
+ this.saving = true;
+
+ try {
+ const startTime = Date.now();
+
+ // Update vendor with new theme_config
+ const updateData = {
+ theme_config: this.themeData
+ };
+
+ const response = await apiClient.put(
+ `/api/v1/admin/vendors/${this.vendorCode}`,
+ updateData
+ );
+
+ const duration = Date.now() - startTime;
+ themeLog.info(`Theme saved in ${duration}ms`);
+
+ // Update vendor data
+ this.vendor = response;
+ this.originalTheme = JSON.parse(JSON.stringify(this.themeData));
+
+ Utils.showToast('Theme saved successfully', 'success');
+
+ } catch (error) {
+ themeLog.error('Failed to save theme:', error);
+ Utils.showToast('Failed to save theme', 'error');
+ } finally {
+ this.saving = false;
+ }
+ },
+
+ // Apply preset theme
+ applyPreset(presetName) {
+ themeLog.info('Applying preset:', presetName);
+
+ if (!THEME_PRESETS[presetName]) {
+ themeLog.error('Unknown preset:', presetName);
+ return;
+ }
+
+ const preset = THEME_PRESETS[presetName];
+
+ // Apply preset values
+ this.themeData.colors = { ...preset.colors };
+ this.themeData.fonts = { ...preset.fonts };
+ this.themeData.layout = { ...preset.layout };
+
+ Utils.showToast(`Applied ${presetName} theme preset`, 'success');
+ },
+
+ // Reset to default theme
+ resetToDefault() {
+ themeLog.info('Resetting to default theme');
+
+ // Confirm with user
+ if (!confirm('Are you sure you want to reset to the default theme? This will discard all customizations.')) {
+ return;
+ }
+
+ this.themeData = {
+ colors: {
+ primary: "#6366f1",
+ secondary: "#8b5cf6",
+ accent: "#ec4899"
+ },
+ fonts: {
+ heading: "Inter, sans-serif",
+ body: "Inter, sans-serif"
+ },
+ layout: {
+ style: "grid",
+ header: "fixed"
+ },
+ custom_css: ""
+ };
+
+ Utils.showToast('Theme reset to default', 'info');
+ },
+
+ // Check if theme has unsaved changes
+ hasChanges() {
+ if (!this.originalTheme) return false;
+ return JSON.stringify(this.themeData) !== JSON.stringify(this.originalTheme);
+ },
+
+ // Format date helper
+ formatDate(dateString) {
+ if (!dateString) return '-';
+ return Utils.formatDate(dateString);
+ }
+ };
+}
+
+themeLog.info('Vendor theme module loaded');
\ No newline at end of file
diff --git a/static/admin/partials/base-layout.html b/static/admin/partials/base-layout.html
deleted file mode 100644
index 335fa4bd..00000000
--- a/static/admin/partials/base-layout.html
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
-
-
-
- Admin Panel - Multi-Tenant Platform
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/admin/users.html b/static/admin/users.html
deleted file mode 100644
index 74c5f6ae..00000000
--- a/static/admin/users.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- User management
-
-
- <-- User management -->
-
-
diff --git a/static/admin/vendor-edit.html b/static/admin/vendor-edit.html
deleted file mode 100644
index 33e60b3d..00000000
--- a/static/admin/vendor-edit.html
+++ /dev/null
@@ -1,498 +0,0 @@
-
-
-
-
-
- Edit Vendor - Admin Portal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Loading vendor details...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ⚠️ Warning:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Previous Owner:
-
-
-
-
-
-
-
-
→
-
-
-
-
-
- ℹ️ Note:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ⚠️ Warning: This will transfer complete ownership to another user.
- The current owner will be demoted to Manager role.
-
-
-
- Current Owner:
- ()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/admin/vendors.html b/static/admin/vendors.html
deleted file mode 100644
index ac13edf3..00000000
--- a/static/admin/vendors.html
+++ /dev/null
@@ -1,201 +0,0 @@
-
-
-
-
-
- Vendors - Admin Portal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Vendor Management
-
-
-
-
-
-
-
-
-
- Vendor Management
-
-
- This page will display vendor list and management tools.
-
-
- Features to be implemented:
-
-
- - • View all vendors with filtering and search
- - • Create new vendors with detailed forms
- - • Edit vendor information
- - • Verify/unverify vendors
- - • View vendor statistics
-
-
-
-
-
-
-
-
-
-
- | Vendor Code |
- Name |
- Subdomain |
- Status |
- Created |
- Actions |
-
-
-
-
-
-
-
-
- No vendors found
- Create your first vendor to get started
-
- |
-
-
-
-
-
- |
-
- |
- |
- |
-
-
-
- |
- |
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/css/admin/admin.css b/static/css/admin/admin.css
deleted file mode 100644
index 649c2adc..00000000
--- a/static/css/admin/admin.css
+++ /dev/null
@@ -1,894 +0,0 @@
-/* static/css/admin/admin.css */
-/* Admin-specific styles */
-
-/* Admin Header */
-.admin-header {
- background: white;
- border-bottom: 1px solid var(--border-color);
- padding: 16px 24px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- box-shadow: var(--shadow-sm);
- position: sticky;
- top: 0;
- z-index: 100;
-}
-
-.admin-header h1 {
- font-size: var(--font-2xl);
- color: var(--text-primary);
- font-weight: 600;
-}
-
-.header-left {
- display: flex;
- align-items: center;
- gap: var(--spacing-md);
-}
-
-.header-right {
- display: flex;
- align-items: center;
- gap: var(--spacing-md);
-}
-
-.user-info {
- font-size: var(--font-base);
- color: var(--text-secondary);
-}
-
-.user-info strong {
- color: var(--text-primary);
- font-weight: 600;
-}
-
-.btn-logout {
- padding: 8px 16px;
- background: var(--danger-color);
- color: white;
- border: none;
- border-radius: var(--radius-md);
- cursor: pointer;
- font-size: var(--font-base);
- font-weight: 500;
- transition: all var(--transition-base);
-}
-
-.btn-logout:hover {
- background: #c0392b;
- transform: translateY(-1px);
-}
-
-/* Admin Container */
-.admin-container {
- display: flex;
- min-height: calc(100vh - 64px);
-}
-
-/* Admin Sidebar */
-.admin-sidebar {
- width: 250px;
- background: white;
- border-right: 1px solid var(--border-color);
- padding: var(--spacing-lg) 0;
- overflow-y: auto;
-}
-
-.nav-menu {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.nav-item {
- margin-bottom: 4px;
-}
-
-.nav-link {
- display: flex;
- align-items: center;
- padding: 12px 24px;
- color: var(--text-secondary);
- text-decoration: none;
- font-size: var(--font-base);
- font-weight: 500;
- transition: all var(--transition-base);
- border-right: 3px solid transparent;
-}
-
-.nav-link:hover {
- background: var(--gray-50);
- color: var(--primary-color);
-}
-
-.nav-link.active {
- background: var(--primary-color);
- color: white;
- border-right-color: var(--primary-dark);
-}
-
-.nav-icon {
- margin-right: var(--spacing-sm);
- font-size: var(--font-lg);
-}
-
-/* Admin Content */
-.admin-content {
- flex: 1;
- padding: var(--spacing-lg);
- overflow-y: auto;
- background: var(--bg-secondary);
-}
-
-/* Stats Grid */
-.stats-grid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
- gap: var(--spacing-lg);
- margin-bottom: var(--spacing-xl);
-}
-
-.stat-card {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
- transition: all var(--transition-base);
-}
-
-.stat-card:hover {
- transform: translateY(-4px);
- box-shadow: var(--shadow-lg);
-}
-
-.stat-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--spacing-md);
-}
-
-.stat-icon {
- font-size: 32px;
- opacity: 0.8;
-}
-
-.stat-title {
- font-size: var(--font-base);
- color: var(--text-secondary);
- font-weight: 500;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.stat-value {
- font-size: 32px;
- font-weight: 700;
- color: var(--text-primary);
- margin-bottom: var(--spacing-sm);
- line-height: 1;
-}
-
-.stat-subtitle {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.stat-change {
- display: inline-flex;
- align-items: center;
- font-size: var(--font-sm);
- font-weight: 600;
- margin-left: var(--spacing-sm);
-}
-
-.stat-change.positive {
- color: var(--success-color);
-}
-
-.stat-change.negative {
- color: var(--danger-color);
-}
-
-/* Content Sections */
-.content-section {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
- margin-bottom: var(--spacing-lg);
-}
-
-.section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--spacing-lg);
- padding-bottom: var(--spacing-md);
- border-bottom: 2px solid var(--gray-100);
-}
-
-.section-title {
- font-size: var(--font-xl);
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.section-actions {
- display: flex;
- gap: var(--spacing-sm);
-}
-
-/* Data Tables */
-.data-table {
- width: 100%;
- border-collapse: collapse;
-}
-
-.data-table thead {
- background: var(--gray-50);
-}
-
-.data-table th {
- text-align: left;
- padding: 12px;
- font-size: var(--font-sm);
- font-weight: 600;
- color: var(--text-secondary);
- text-transform: uppercase;
- letter-spacing: 0.5px;
- border-bottom: 2px solid var(--border-color);
-}
-
-.data-table td {
- padding: 12px;
- border-bottom: 1px solid var(--border-color);
- font-size: var(--font-base);
-}
-
-.data-table tbody tr {
- transition: background var(--transition-fast);
-}
-
-.data-table tbody tr:hover {
- background: var(--gray-50);
-}
-
-.data-table tbody tr:last-child td {
- border-bottom: none;
-}
-
-.table-actions {
- display: flex;
- gap: var(--spacing-sm);
-}
-
-.table-actions .btn {
- padding: 6px 12px;
- font-size: var(--font-sm);
-}
-
-/* Empty State */
-.empty-state {
- text-align: center;
- padding: var(--spacing-2xl) var(--spacing-lg);
- color: var(--text-muted);
-}
-
-.empty-state-icon {
- font-size: 48px;
- margin-bottom: var(--spacing-md);
- opacity: 0.5;
-}
-
-.empty-state h3 {
- font-size: var(--font-xl);
- color: var(--text-secondary);
- margin-bottom: var(--spacing-sm);
-}
-
-.empty-state p {
- font-size: var(--font-base);
- color: var(--text-muted);
-}
-
-/* Loading State */
-.loading {
- text-align: center;
- padding: var(--spacing-2xl);
- color: var(--text-muted);
-}
-
-.loading-text {
- margin-top: var(--spacing-md);
- font-size: var(--font-base);
-}
-
-/* Search and Filters */
-.filter-bar {
- display: flex;
- gap: var(--spacing-md);
- margin-bottom: var(--spacing-lg);
- flex-wrap: wrap;
-}
-
-.filter-group {
- flex: 1;
- min-width: 200px;
-}
-
-.search-box {
- position: relative;
- flex: 2;
- min-width: 300px;
-}
-
-.search-input {
- width: 100%;
- padding-left: 40px;
-}
-
-.search-icon {
- position: absolute;
- left: 12px;
- top: 50%;
- transform: translateY(-50%);
- color: var(--text-muted);
-}
-
-/* Action Buttons */
-.action-buttons {
- display: flex;
- gap: var(--spacing-sm);
- justify-content: flex-end;
-}
-
-/* Modal/Dialog */
-/* Modal Styles */
-.modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1000;
-}
-
-.modal-content {
- background: white;
- border-radius: 8px;
- max-width: 600px;
- width: 90%;
- max-height: 90vh;
- overflow-y: auto;
- box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
-}
-
-.modal-header {
- padding: 20px;
- border-bottom: 1px solid #e5e7eb;
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.modal-header h3 {
- margin: 0;
- font-size: 1.25rem;
-}
-
-.btn-close {
- background: none;
- border: none;
- font-size: 28px;
- line-height: 1;
- cursor: pointer;
- color: #6b7280;
-}
-
-.btn-close:hover {
- color: #1f2937;
-}
-
-.modal-body {
- padding: 20px;
-}
-
-.modal-footer {
- padding: 20px;
- border-top: 1px solid #e5e7eb;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
-}
-
-.info-box {
- background-color: #eff6ff;
- border: 1px solid #3b82f6;
- border-radius: 6px;
- padding: 12px;
- color: #1e40af;
-}
-
-.checkbox-label {
- display: flex;
- align-items: center;
- gap: 8px;
- cursor: pointer;
-}
-
-.checkbox-label input[type="checkbox"] {
- width: auto;
- margin: 0;
-}
-
-.form-section-divider {
- border-top: 2px solid #e5e7eb;
- margin: 32px 0;
-}
-
-/* Small modal variant for confirmations */
-.modal-sm {
- max-width: 500px;
-}
-
-/* Info box styling */
-.info-box {
- background: #e3f2fd;
- border-left: 4px solid #2196f3;
- padding: 12px 16px;
- border-radius: 4px;
- font-size: 14px;
-}
-
-/* Quick actions spacing */
-.quick-actions {
- display: flex;
- gap: 12px;
- flex-wrap: wrap;
-}
-
-/* Success Modal Styles */
-.modal-header-success {
- background: linear-gradient(135deg, #4caf50 0%, #45a049 100%);
- color: white;
- border-radius: 8px 8px 0 0;
-}
-
-.modal-header-success .btn-close {
- color: white;
- opacity: 0.9;
-}
-
-.modal-header-success .btn-close:hover {
- opacity: 1;
-}
-
-.success-icon-wrapper {
- display: flex;
- justify-content: center;
- margin: 20px 0;
-}
-
-.success-icon {
- width: 80px;
- height: 80px;
- border-radius: 50%;
- background: linear-gradient(135deg, #4caf50 0%, #45a049 100%);
- color: white;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 48px;
- font-weight: bold;
- animation: successPulse 0.6s ease-out;
- box-shadow: 0 4px 20px rgba(76, 175, 80, 0.3);
-}
-
-@keyframes successPulse {
- 0% {
- transform: scale(0.5);
- opacity: 0;
- }
- 50% {
- transform: scale(1.1);
- }
- 100% {
- transform: scale(1);
- opacity: 1;
- }
-}
-
-.transfer-details {
- background: #f8f9fa;
- border-radius: 8px;
- padding: 20px;
- margin: 20px 0;
-}
-
-.detail-row {
- display: flex;
- flex-direction: column;
- gap: 8px;
- padding: 12px;
- background: white;
- border-radius: 6px;
- margin-bottom: 12px;
-}
-
-.detail-label {
- font-size: 12px;
- font-weight: 600;
- text-transform: uppercase;
- color: #666;
- letter-spacing: 0.5px;
-}
-
-.detail-value {
- font-size: 15px;
-}
-
-.detail-value strong {
- color: #333;
- font-size: 16px;
-}
-
-.detail-arrow {
- text-align: center;
- font-size: 24px;
- color: #4caf50;
- font-weight: bold;
- margin: 8px 0;
-}
-
-.modal-md {
- max-width: 600px;
-}
-
-.btn-block {
- width: 100%;
- padding: 12px;
- font-size: 16px;
- font-weight: 600;
-}
-
-/* Alert variants in modals */
-.modal-body .alert {
- margin-top: 16px;
- padding: 12px 16px;
- border-radius: 6px;
- border: none;
-}
-
-.modal-body .alert-info {
- background: #e3f2fd;
- color: #1976d2;
-}
-
-.modal-body .alert-info strong {
- color: #0d47a1;
-}
-
-/* Text utilities */
-.text-center {
- text-align: center;
-}
-
-.text-muted {
- color: #6c757d;
- font-size: 14px;
-}
-
-.mb-3 {
- margin-bottom: 1rem;
-}
-
-.mb-4 {
- margin-bottom: 1.5rem;
-}
-
-.mt-3 {
- margin-top: 1rem;
-}
-
-/* Pagination */
-.pagination {
- display: flex;
- justify-content: center;
- align-items: center;
- gap: var(--spacing-sm);
- margin-top: var(--spacing-lg);
-}
-
-.pagination-btn {
- padding: 8px 12px;
- border: 1px solid var(--border-color);
- background: white;
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all var(--transition-base);
-}
-
-.pagination-btn:hover:not(:disabled) {
- background: var(--gray-50);
- border-color: var(--primary-color);
-}
-
-.pagination-btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.pagination-btn.active {
- background: var(--primary-color);
- color: white;
- border-color: var(--primary-color);
-}
-
-.pagination-info {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-/* Responsive Design */
-@media (max-width: 1024px) {
- .admin-sidebar {
- width: 200px;
- }
-
- .stats-grid {
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- }
-}
-
-@media (max-width: 768px) {
- .admin-container {
- flex-direction: column;
- }
-
- .admin-sidebar {
- width: 100%;
- border-right: none;
- border-bottom: 1px solid var(--border-color);
- }
-
- .admin-content {
- padding: var(--spacing-md);
- }
-
- .stats-grid {
- grid-template-columns: 1fr;
- }
-
- .section-header {
- flex-direction: column;
- align-items: flex-start;
- gap: var(--spacing-md);
- }
-
- .filter-bar {
- flex-direction: column;
- }
-
- .filter-group,
- .search-box {
- width: 100%;
- }
-
- .data-table {
- font-size: var(--font-sm);
- }
-
- .data-table th,
- .data-table td {
- padding: 8px;
- }
-}
-
-@media (max-width: 480px) {
- .admin-header {
- padding: 12px 16px;
- }
-
- .admin-header h1 {
- font-size: var(--font-lg);
- }
-
- .stat-value {
- font-size: var(--font-3xl);
- }
-
- .content-section {
- padding: var(--spacing-md);
- }
-
- /* Make table scrollable on small screens */
- .table-wrapper {
- overflow-x: auto;
- }
-
- .data-table {
- min-width: 600px;
- }
-}
-
-/* Print Styles */
-@media print {
- .admin-sidebar,
- .admin-header .header-right,
- .section-actions,
- .table-actions {
- display: none;
- }
-
- .admin-content {
- padding: 0;
- }
-
- .content-section {
- box-shadow: none;
- border: 1px solid var(--border-color);
- }
-
-/* Value with copy button */
-.value-with-copy {
- display: flex;
- gap: var(--spacing-sm);
- align-items: center;
- flex: 1;
-}
-
-.credential-item.highlight {
- background: #fff3cd;
- border: 2px solid var(--warning-color);
-}
-
-.credential-item.highlight .value {
- background: white;
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.btn-copy {
- background: var(--gray-100);
- border: 1px solid var(--border-color);
- padding: 6px 12px;
- border-radius: var(--radius-sm);
- cursor: pointer;
- color: var(--text-secondary);
- font-size: var(--font-xs);
- transition: all var(--transition-base);
- white-space: nowrap;
-}
-
-.btn-copy:hover {
- background: var(--primary-color);
- border-color: var(--primary-color);
- color: white;
-}
-
-/* Text color utilities */
-.text-danger {
- color: var(--danger-color) !important;
-}
-
-.text-warning {
- color: var(--warning-color) !important;
-}
-
-.text-success {
- color: var(--success-color) !important;
-}
-
-/* Disabled button styles */
-.btn-icon:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.btn-icon:disabled:hover {
- background: white;
- border-color: var(--border-color);
- transform: none;
-}
-
-/* Alert improvements */
-.alert {
- animation: slideDown 0.3s ease;
-}
-
-@keyframes slideDown {
- from {
- opacity: 0;
- transform: translateY(-10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* Form Section Styles */
-.form-section-title {
- font-size: 1.125rem;
- font-weight: 600;
- color: #1f2937;
- margin-bottom: 16px;
- padding-bottom: 8px;
- border-bottom: 2px solid #e5e7eb;
-}
-
-.form-control-disabled {
- background-color: #f3f4f6;
- cursor: not-allowed;
- color: #6b7280;
-}
-
-.form-help {
- font-size: 0.875rem;
- color: #6b7280;
- margin-top: 4px;
-}
-
-.text-muted {
- color: #6b7280;
-}
-
-.mb-2 {
- margin-bottom: 0.5rem;
-}
-
-.mb-3 {
- margin-bottom: 1rem;
-}
-
-.mt-3 {
- margin-top: 1rem;
-}
-
-/* Alert Styles */
-.alert {
- padding: 12px 16px;
- border-radius: 6px;
- margin-bottom: 16px;
-}
-
-.alert-warning {
- background-color: #fef3c7;
- border: 1px solid #f59e0b;
- color: #92400e;
-}
-
-.alert-warning strong {
- color: #78350f;
-}
-
-/* Quick Actions */
-.quick-actions {
- display: flex;
- gap: 12px;
- flex-wrap: wrap;
-}
-
-.quick-actions .btn {
- min-width: 180px;
-}
-
-/* Button Sizes */
-.btn-sm {
- padding: 6px 12px;
- font-size: 0.875rem;
-}
-
-/* Required Field Indicator */
-.required {
- color: #ef4444;
- font-weight: bold;
-}
\ No newline at end of file
diff --git a/static/css/shared/auth.css b/static/css/shared/auth.css
deleted file mode 100644
index 2d12e6d7..00000000
--- a/static/css/shared/auth.css
+++ /dev/null
@@ -1,622 +0,0 @@
-/* static/css/shared/auth.css */
-/* Authentication pages (login, register) styles */
-
-/* Auth Page Layout */
-.auth-page {
- min-height: 100vh;
- display: flex;
- justify-content: center;
- align-items: center;
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- padding: var(--spacing-lg);
-}
-
-.auth-page::before {
- content: '';
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background:
- radial-gradient(circle at 20% 80%, rgba(255,255,255,0.1) 0%, transparent 50%),
- radial-gradient(circle at 80% 20%, rgba(255,255,255,0.1) 0%, transparent 50%);
- pointer-events: none;
-}
-
-/* Login Container */
-.login-container,
-.auth-container {
- background: white;
- border-radius: var(--radius-xl);
- box-shadow: var(--shadow-xl);
- width: 100%;
- max-width: 420px;
- padding: var(--spacing-xl);
- position: relative;
- z-index: 1;
- animation: slideUp 0.4s ease;
-}
-
-@keyframes slideUp {
- from {
- opacity: 0;
- transform: translateY(20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-/* Login Header */
-.login-header,
-.auth-header {
- text-align: center;
- margin-bottom: var(--spacing-xl);
-}
-
-.auth-logo {
- width: 80px;
- height: 80px;
- margin: 0 auto var(--spacing-md);
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- border-radius: var(--radius-xl);
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 40px;
- color: white;
- box-shadow: var(--shadow-md);
-}
-
-.login-header h1,
-.auth-header h1 {
- font-size: var(--font-3xl);
- color: var(--text-primary);
- margin-bottom: var(--spacing-sm);
- font-weight: 700;
-}
-
-.login-header p,
-.auth-header p {
- color: var(--text-secondary);
- font-size: var(--font-base);
-}
-
-/* Vendor Info Display */
-.vendor-info {
- background: var(--gray-50);
- padding: 12px 16px;
- border-radius: var(--radius-lg);
- margin-bottom: var(--spacing-lg);
- text-align: center;
- border: 1px solid var(--border-color);
-}
-
-.vendor-info strong {
- color: var(--primary-color);
- font-size: var(--font-lg);
- font-weight: 600;
-}
-
-/* No Vendor Message */
-.no-vendor-message {
- text-align: center;
- padding: var(--spacing-2xl) var(--spacing-lg);
- color: var(--text-secondary);
-}
-
-.no-vendor-message h2 {
- font-size: var(--font-2xl);
- color: var(--text-primary);
- margin-bottom: var(--spacing-md);
-}
-
-.no-vendor-message p {
- margin-bottom: var(--spacing-lg);
- color: var(--text-muted);
-}
-
-/* Auth Form */
-.auth-form,
-.login-form {
- margin-bottom: var(--spacing-lg);
-}
-
-.form-group {
- margin-bottom: var(--spacing-lg);
-}
-
-.form-group label {
- display: block;
- font-weight: 600;
- color: var(--text-primary);
- margin-bottom: var(--spacing-sm);
- font-size: var(--font-base);
-}
-
-.form-group input {
- width: 100%;
- padding: 14px 16px;
- border: 2px solid var(--border-color);
- border-radius: var(--radius-lg);
- font-size: var(--font-md);
- transition: all var(--transition-base);
- background: white;
-}
-
-.form-group input:focus {
- outline: none;
- border-color: var(--primary-color);
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
-}
-
-.form-group input.error {
- border-color: var(--danger-color);
-}
-
-.form-group input::placeholder {
- color: var(--text-muted);
-}
-
-/* Password Toggle */
-.password-group {
- position: relative;
-}
-
-.password-toggle {
- position: absolute;
- right: 12px;
- top: 50%;
- transform: translateY(-50%);
- background: none;
- border: none;
- cursor: pointer;
- color: var(--text-muted);
- padding: var(--spacing-sm);
- font-size: var(--font-lg);
-}
-
-.password-toggle:hover {
- color: var(--text-primary);
-}
-
-/* Remember Me & Forgot Password */
-.form-options {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--spacing-lg);
- font-size: var(--font-sm);
-}
-
-.remember-me {
- display: flex;
- align-items: center;
- gap: var(--spacing-sm);
-}
-
-.remember-me input[type="checkbox"] {
- width: auto;
- margin: 0;
-}
-
-.forgot-password {
- color: var(--primary-color);
- text-decoration: none;
- font-weight: 500;
-}
-
-.forgot-password:hover {
- text-decoration: underline;
-}
-
-/* Submit Button */
-.btn-login,
-.btn-auth {
- width: 100%;
- padding: 14px 24px;
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- color: white;
- border: none;
- border-radius: var(--radius-lg);
- font-size: var(--font-lg);
- font-weight: 600;
- cursor: pointer;
- transition: all var(--transition-base);
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
-}
-
-.btn-login:hover:not(:disabled),
-.btn-auth:hover:not(:disabled) {
- transform: translateY(-2px);
- box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
-}
-
-.btn-login:active:not(:disabled),
-.btn-auth:active:not(:disabled) {
- transform: translateY(0);
-}
-
-.btn-login:disabled,
-.btn-auth:disabled {
- opacity: 0.6;
- cursor: not-allowed;
- transform: none;
-}
-
-/* Social Login Buttons */
-.social-login {
- margin-top: var(--spacing-lg);
- padding-top: var(--spacing-lg);
- border-top: 1px solid var(--border-color);
-}
-
-.social-login-text {
- text-align: center;
- color: var(--text-muted);
- font-size: var(--font-sm);
- margin-bottom: var(--spacing-md);
-}
-
-.social-buttons {
- display: flex;
- gap: var(--spacing-md);
-}
-
-.btn-social {
- flex: 1;
- padding: 12px;
- border: 2px solid var(--border-color);
- background: white;
- border-radius: var(--radius-lg);
- cursor: pointer;
- transition: all var(--transition-base);
- font-size: var(--font-base);
- font-weight: 500;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: var(--spacing-sm);
-}
-
-.btn-social:hover {
- border-color: var(--primary-color);
- background: var(--gray-50);
-}
-
-/* Login Footer */
-.login-footer,
-.auth-footer {
- text-align: center;
- margin-top: var(--spacing-lg);
- padding-top: var(--spacing-lg);
- border-top: 1px solid var(--border-color);
-}
-
-.login-footer a,
-.auth-footer a {
- color: var(--primary-color);
- text-decoration: none;
- font-size: var(--font-base);
- font-weight: 500;
-}
-
-.login-footer a:hover,
-.auth-footer a:hover {
- text-decoration: underline;
-}
-
-.auth-footer-text {
- font-size: var(--font-sm);
- color: var(--text-muted);
- margin-bottom: var(--spacing-sm);
-}
-
-/* Back Button */
-.btn-back {
- display: inline-block;
- padding: 10px 20px;
- background: var(--secondary-color);
- color: white;
- text-decoration: none;
- border-radius: var(--radius-md);
- font-weight: 500;
- transition: all var(--transition-base);
-}
-
-.btn-back:hover {
- background: #5a6268;
- transform: translateY(-1px);
-}
-
-/* Error and Success Messages */
-.alert {
- padding: 12px 16px;
- border-radius: var(--radius-lg);
- margin-bottom: var(--spacing-lg);
- font-size: var(--font-base);
- display: none;
- animation: slideDown 0.3s ease;
-}
-
-@keyframes slideDown {
- from {
- opacity: 0;
- transform: translateY(-10px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-.alert.show {
- display: block;
-}
-
-.alert-success {
- background: #d4edda;
- color: #155724;
- border: 1px solid #c3e6cb;
-}
-
-.alert-error {
- background: #f8d7da;
- color: #721c24;
- border: 1px solid #f5c6cb;
-}
-
-.alert-warning {
- background: #fff3cd;
- color: #856404;
- border: 1px solid #ffeaa7;
-}
-
-.alert-info {
- background: #d1ecf1;
- color: #0c5460;
- border: 1px solid #bee5eb;
-}
-
-/* Field Errors */
-.error-message {
- color: var(--danger-color);
- font-size: var(--font-sm);
- margin-top: var(--spacing-xs);
- display: none;
- animation: fadeIn 0.2s ease;
-}
-
-@keyframes fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
-}
-
-.error-message.show {
- display: block;
-}
-
-/* Loading State */
-.loading-spinner {
- display: inline-block;
- width: 16px;
- height: 16px;
- border: 2px solid currentColor;
- border-radius: 50%;
- border-top-color: transparent;
- animation: spinner 0.6s linear infinite;
- margin-right: var(--spacing-sm);
- vertical-align: middle;
-}
-
-@keyframes spinner {
- to { transform: rotate(360deg); }
-}
-
-/* Divider */
-.divider {
- display: flex;
- align-items: center;
- text-align: center;
- margin: var(--spacing-lg) 0;
-}
-
-.divider::before,
-.divider::after {
- content: '';
- flex: 1;
- border-bottom: 1px solid var(--border-color);
-}
-
-.divider span {
- padding: 0 var(--spacing-md);
- color: var(--text-muted);
- font-size: var(--font-sm);
-}
-
-/* Credentials Display (for vendor creation success) */
-.credentials-card {
- background: #fff3cd;
- border: 2px solid var(--warning-color);
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- margin-top: var(--spacing-lg);
-}
-
-.credentials-card h3 {
- margin-bottom: var(--spacing-md);
- color: #856404;
- font-size: var(--font-xl);
-}
-
-.credential-item {
- background: white;
- padding: 12px 16px;
- border-radius: var(--radius-md);
- margin-bottom: 12px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- border: 1px solid var(--border-color);
-}
-
-.credential-item label {
- font-weight: 600;
- color: var(--text-primary);
- font-size: var(--font-base);
-}
-
-.credential-item .value {
- font-family: 'Courier New', monospace;
- background: var(--gray-50);
- padding: 6px 12px;
- border-radius: var(--radius-sm);
- color: var(--text-primary);
- font-size: var(--font-base);
- word-break: break-all;
-}
-
-.warning-text {
- color: #856404;
- font-size: var(--font-sm);
- margin-top: var(--spacing-md);
- font-weight: 600;
- display: flex;
- align-items: center;
- gap: var(--spacing-sm);
-}
-
-.warning-text::before {
- content: '⚠️';
- font-size: var(--font-lg);
-}
-
-/* Copy Button */
-.btn-copy {
- background: none;
- border: 1px solid var(--border-color);
- padding: 4px 8px;
- border-radius: var(--radius-sm);
- cursor: pointer;
- color: var(--text-secondary);
- font-size: var(--font-xs);
- transition: all var(--transition-base);
-}
-
-.btn-copy:hover {
- background: var(--gray-50);
- border-color: var(--primary-color);
- color: var(--primary-color);
-}
-
-/* Responsive Design */
-@media (max-width: 480px) {
- .login-container,
- .auth-container {
- padding: var(--spacing-lg);
- max-width: 100%;
- }
-
- .auth-logo {
- width: 60px;
- height: 60px;
- font-size: 32px;
- }
-
- .login-header h1,
- .auth-header h1 {
- font-size: var(--font-2xl);
- }
-
- .btn-login,
- .btn-auth {
- padding: 12px 20px;
- font-size: var(--font-base);
- }
-
- .social-buttons {
- flex-direction: column;
- }
-
- .credential-item {
- flex-direction: column;
- align-items: flex-start;
- gap: var(--spacing-sm);
- }
-
- .credential-item .value {
- width: 100%;
- text-align: left;
- }
-}
-
-/* Dark Mode Support (optional) */
-@media (prefers-color-scheme: dark) {
- .auth-page {
- background: linear-gradient(135deg, #1a202c 0%, #2d3748 100%);
- }
-
- .login-container,
- .auth-container {
- background: #2d3748;
- color: #e2e8f0;
- }
-
- .login-header h1,
- .auth-header h1,
- .form-group label {
- color: #e2e8f0;
- }
-
- .login-header p,
- .auth-header p {
- color: #a0aec0;
- }
-
- .form-group input {
- background: #1a202c;
- border-color: #4a5568;
- color: #e2e8f0;
- }
-
- .form-group input::placeholder {
- color: #718096;
- }
-
- .vendor-info {
- background: #1a202c;
- border-color: #4a5568;
- }
-
- .credential-item {
- background: #1a202c;
- border-color: #4a5568;
- }
-
- .credential-item .value {
- background: #2d3748;
- }
-}
-
-/* Print Styles */
-@media print {
- .auth-page::before {
- display: none;
- }
-
- .login-container,
- .auth-container {
- box-shadow: none;
- border: 1px solid var(--border-color);
- }
-
- .btn-login,
- .btn-auth,
- .social-login,
- .login-footer,
- .auth-footer {
- display: none;
- }
-}
\ No newline at end of file
diff --git a/static/css/shared/base.css b/static/css/shared/base.css
deleted file mode 100644
index fa29e17f..00000000
--- a/static/css/shared/base.css
+++ /dev/null
@@ -1,514 +0,0 @@
-/* static/css/shared/base.css */
-/* Base styles shared across all pages */
-
-/* Import responsive utilities */
-@import url('responsive-utilities.css');
-
-/* Rest of your base.css... */
-:root {
- /* Color Palette */
- --primary-color: #667eea;
- --primary-dark: #764ba2;
- --secondary-color: #6c757d;
- --success-color: #28a745;
- --danger-color: #e74c3c;
- --warning-color: #ffc107;
- --info-color: #17a2b8;
-
- /* Grays */
- --gray-50: #f9fafb;
- --gray-100: #f5f7fa;
- --gray-200: #e1e8ed;
- --gray-300: #d1d9e0;
- --gray-400: #b0bac5;
- --gray-500: #8796a5;
- --gray-600: #687785;
- --gray-700: #4a5568;
- --gray-800: #2d3748;
- --gray-900: #1a202c;
-
- /* Text Colors */
- --text-primary: #333333;
- --text-secondary: #666666;
- --text-muted: #999999;
-
- /* Background Colors */
- --bg-primary: #ffffff;
- --bg-secondary: #f5f7fa;
- --bg-overlay: rgba(0, 0, 0, 0.5);
-
- /* Border Colors */
- --border-color: #e1e8ed;
- --border-focus: #667eea;
-
- /* Shadows */
- --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
- --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
- --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15);
- --shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.3);
-
- /* Transitions */
- --transition-fast: 0.15s ease;
- --transition-base: 0.2s ease;
- --transition-slow: 0.3s ease;
-
- /* Border Radius */
- --radius-sm: 4px;
- --radius-md: 6px;
- --radius-lg: 8px;
- --radius-xl: 12px;
- --radius-full: 9999px;
-
- /* Spacing */
- --spacing-xs: 4px;
- --spacing-sm: 8px;
- --spacing-md: 16px;
- --spacing-lg: 24px;
- --spacing-xl: 32px;
- --spacing-2xl: 48px;
-
- /* Font Sizes */
- --font-xs: 12px;
- --font-sm: 13px;
- --font-base: 14px;
- --font-md: 15px;
- --font-lg: 16px;
- --font-xl: 18px;
- --font-2xl: 20px;
- --font-3xl: 24px;
- --font-4xl: 32px;
-}
-
-/* Reset and Base Styles */
-* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
-}
-
-html {
- font-size: 16px;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-body {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
- font-size: var(--font-base);
- line-height: 1.5;
- color: var(--text-primary);
- background: var(--bg-secondary);
-}
-
-/* Typography */
-h1, h2, h3, h4, h5, h6 {
- margin: 0;
- font-weight: 600;
- line-height: 1.2;
- color: var(--text-primary);
-}
-
-h1 { font-size: var(--font-4xl); }
-h2 { font-size: var(--font-3xl); }
-h3 { font-size: var(--font-2xl); }
-h4 { font-size: var(--font-xl); }
-h5 { font-size: var(--font-lg); }
-h6 { font-size: var(--font-base); }
-
-p {
- margin: 0 0 1rem;
-}
-
-a {
- color: var(--primary-color);
- text-decoration: none;
- transition: color var(--transition-base);
-}
-
-a:hover {
- color: var(--primary-dark);
-}
-
-/* Buttons */
-.btn {
- display: inline-block;
- padding: 10px 20px;
- font-size: var(--font-base);
- font-weight: 600;
- text-align: center;
- border: none;
- border-radius: var(--radius-md);
- cursor: pointer;
- transition: all var(--transition-base);
- text-decoration: none;
- line-height: 1.5;
-}
-
-.btn:disabled {
- opacity: 0.6;
- cursor: not-allowed;
-}
-
-.btn-primary {
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- color: white;
-}
-
-.btn-primary:hover:not(:disabled) {
- transform: translateY(-2px);
- box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
-}
-
-.btn-secondary {
- background: var(--secondary-color);
- color: white;
-}
-
-.btn-secondary:hover:not(:disabled) {
- background: #5a6268;
-}
-
-.btn-success {
- background: var(--success-color);
- color: white;
-}
-
-.btn-danger {
- background: var(--danger-color);
- color: white;
-}
-
-.btn-warning {
- background: var(--warning-color);
- color: var(--gray-900);
-}
-
-.btn-outline {
- background: transparent;
- border: 2px solid var(--primary-color);
- color: var(--primary-color);
-}
-
-.btn-outline:hover:not(:disabled) {
- background: var(--primary-color);
- color: white;
-}
-
-.btn-sm {
- padding: 6px 12px;
- font-size: var(--font-sm);
-}
-
-.btn-lg {
- padding: 14px 28px;
- font-size: var(--font-lg);
-}
-
-/* Form Elements */
-.form-group {
- margin-bottom: var(--spacing-lg);
-}
-
-.form-label {
- display: block;
- font-weight: 600;
- margin-bottom: var(--spacing-sm);
- color: var(--text-primary);
- font-size: var(--font-base);
-}
-
-.form-control,
-.form-input,
-.form-select,
-.form-textarea {
- width: 100%;
- padding: 12px 16px;
- font-size: var(--font-base);
- line-height: 1.5;
- color: var(--text-primary);
- background: white;
- border: 2px solid var(--border-color);
- border-radius: var(--radius-md);
- transition: border-color var(--transition-base);
-}
-
-.form-control:focus,
-.form-input:focus,
-.form-select:focus,
-.form-textarea:focus {
- outline: none;
- border-color: var(--border-focus);
-}
-
-.form-control.error,
-.form-input.error {
- border-color: var(--danger-color);
-}
-
-.form-textarea {
- resize: vertical;
- min-height: 80px;
-}
-
-.form-help {
- display: block;
- margin-top: var(--spacing-xs);
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.error-message {
- display: none;
- margin-top: var(--spacing-xs);
- font-size: var(--font-sm);
- color: var(--danger-color);
-}
-
-.error-message.show {
- display: block;
-}
-
-/* Cards */
-.card {
- background: white;
- border-radius: var(--radius-lg);
- box-shadow: var(--shadow-md);
- overflow: hidden;
-}
-
-.card-header {
- padding: var(--spacing-lg);
- border-bottom: 1px solid var(--border-color);
-}
-
-.card-body {
- padding: var(--spacing-lg);
-}
-
-.card-footer {
- padding: var(--spacing-lg);
- border-top: 1px solid var(--border-color);
- background: var(--gray-50);
-}
-
-/* Badges */
-.badge {
- display: inline-block;
- padding: 4px 10px;
- font-size: var(--font-xs);
- font-weight: 600;
- line-height: 1;
- border-radius: var(--radius-full);
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.badge-primary {
- background: rgba(102, 126, 234, 0.1);
- color: var(--primary-color);
-}
-
-.badge-success {
- background: #d4edda;
- color: #155724;
-}
-
-.badge-danger {
- background: #f8d7da;
- color: #721c24;
-}
-
-.badge-warning {
- background: #fff3cd;
- color: #856404;
-}
-
-.badge-info {
- background: #d1ecf1;
- color: #0c5460;
-}
-
-.badge-secondary {
- background: var(--gray-200);
- color: var(--gray-700);
-}
-
-/* Alerts */
-.alert {
- padding: 12px 16px;
- border-radius: var(--radius-md);
- margin-bottom: var(--spacing-lg);
- font-size: var(--font-base);
- border: 1px solid transparent;
-}
-
-.alert-success {
- background: #d4edda;
- color: #155724;
- border-color: #c3e6cb;
-}
-
-.alert-danger,
-.alert-error {
- background: #f8d7da;
- color: #721c24;
- border-color: #f5c6cb;
-}
-
-.alert-warning {
- background: #fff3cd;
- color: #856404;
- border-color: #ffeaa7;
-}
-
-.alert-info {
- background: #d1ecf1;
- color: #0c5460;
- border-color: #bee5eb;
-}
-
-/* Tables */
-.table {
- width: 100%;
- border-collapse: collapse;
-}
-
-.table th {
- text-align: left;
- padding: 12px;
- background: var(--gray-100);
- font-size: var(--font-sm);
- font-weight: 600;
- color: var(--text-secondary);
- text-transform: uppercase;
- letter-spacing: 0.5px;
- border-bottom: 2px solid var(--border-color);
-}
-
-.table td {
- padding: 12px;
- border-bottom: 1px solid var(--border-color);
- font-size: var(--font-base);
-}
-
-.table tr:hover {
- background: var(--gray-50);
-}
-
-.table-striped tbody tr:nth-child(odd) {
- background: var(--gray-50);
-}
-
-/* Utilities */
-.text-center { text-align: center; }
-.text-left { text-align: left; }
-.text-right { text-align: right; }
-
-.text-muted { color: var(--text-muted); }
-.text-primary { color: var(--primary-color); }
-.text-success { color: var(--success-color); }
-.text-danger { color: var(--danger-color); }
-.text-warning { color: var(--warning-color); }
-
-.font-bold { font-weight: 700; }
-.font-semibold { font-weight: 600; }
-.font-normal { font-weight: 400; }
-
-.mt-0 { margin-top: 0; }
-.mt-1 { margin-top: var(--spacing-sm); }
-.mt-2 { margin-top: var(--spacing-md); }
-.mt-3 { margin-top: var(--spacing-lg); }
-.mt-4 { margin-top: var(--spacing-xl); }
-
-.mb-0 { margin-bottom: 0; }
-.mb-1 { margin-bottom: var(--spacing-sm); }
-.mb-2 { margin-bottom: var(--spacing-md); }
-.mb-3 { margin-bottom: var(--spacing-lg); }
-.mb-4 { margin-bottom: var(--spacing-xl); }
-
-.p-0 { padding: 0; }
-.p-1 { padding: var(--spacing-sm); }
-.p-2 { padding: var(--spacing-md); }
-.p-3 { padding: var(--spacing-lg); }
-.p-4 { padding: var(--spacing-xl); }
-
-.d-none { display: none; }
-.d-block { display: block; }
-.d-inline { display: inline; }
-.d-inline-block { display: inline-block; }
-.d-flex { display: flex; }
-
-.flex-column { flex-direction: column; }
-.flex-row { flex-direction: row; }
-.justify-start { justify-content: flex-start; }
-.justify-end { justify-content: flex-end; }
-.justify-center { justify-content: center; }
-.justify-between { justify-content: space-between; }
-.align-start { align-items: flex-start; }
-.align-end { align-items: flex-end; }
-.align-center { align-items: center; }
-
-.gap-1 { gap: var(--spacing-sm); }
-.gap-2 { gap: var(--spacing-md); }
-.gap-3 { gap: var(--spacing-lg); }
-
-/* Loading Spinner */
-.loading-spinner {
- display: inline-block;
- width: 16px;
- height: 16px;
- border: 2px solid currentColor;
- border-radius: 50%;
- border-top-color: transparent;
- animation: spinner 0.6s linear infinite;
- vertical-align: middle;
-}
-
-@keyframes spinner {
- to { transform: rotate(360deg); }
-}
-
-.loading-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: var(--bg-overlay);
- display: flex;
- justify-content: center;
- align-items: center;
- z-index: 9999;
-}
-
-.loading-spinner-lg {
- width: 48px;
- height: 48px;
- border-width: 4px;
-}
-
-/* Responsive */
-@media (max-width: 768px) {
- :root {
- --font-base: 14px;
- --font-lg: 15px;
- --font-xl: 16px;
- --font-2xl: 18px;
- --font-3xl: 20px;
- --font-4xl: 24px;
- }
-
- .btn {
- padding: 8px 16px;
- }
-
- .card-body {
- padding: var(--spacing-md);
- }
-}
-
-@media (max-width: 480px) {
- .btn {
- width: 100%;
- }
-}
\ No newline at end of file
diff --git a/static/css/shared/components.css b/static/css/shared/components.css
deleted file mode 100644
index 05297c02..00000000
--- a/static/css/shared/components.css
+++ /dev/null
@@ -1,728 +0,0 @@
-/**
- * Universal Components Styles
- * Shared component styles for Admin, Vendor, and Shop sections
- */
-
-/* =============================================================================
- MODAL SYSTEM STYLES
- ============================================================================= */
-
-/* Modal Backdrop */
-.modal-backdrop {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 9999;
- animation: fadeIn 0.2s ease-in;
-}
-
-@keyframes fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-
-/* Modal Container */
-.modal-container {
- background: white;
- border-radius: 8px;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
- max-width: 500px;
- width: 90%;
- max-height: 90vh;
- overflow-y: auto;
- animation: slideUp 0.3s ease-out;
-}
-
-@keyframes slideUp {
- from {
- transform: translateY(20px);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
-}
-
-/* Modal Header */
-.modal-header {
- padding: 20px 24px;
- border-bottom: 1px solid #e5e7eb;
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
-
-.modal-title {
- font-size: 1.25rem;
- font-weight: 600;
- color: #111827;
- margin: 0;
-}
-
-.modal-close {
- background: none;
- border: none;
- font-size: 1.5rem;
- color: #6b7280;
- cursor: pointer;
- padding: 0;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 4px;
- transition: all 0.2s;
-}
-
-.modal-close:hover {
- background-color: #f3f4f6;
- color: #111827;
-}
-
-/* Modal Body */
-.modal-body {
- padding: 24px;
-}
-
-.modal-message {
- font-size: 0.95rem;
- color: #374151;
- line-height: 1.6;
- margin-bottom: 12px;
-}
-
-.modal-warning {
- background-color: #fef3c7;
- border-left: 4px solid #f59e0b;
- padding: 12px 16px;
- border-radius: 4px;
- margin-top: 16px;
-}
-
-.modal-warning p {
- margin: 0;
- color: #92400e;
- font-size: 0.875rem;
-}
-
-.modal-details {
- background-color: #f9fafb;
- border: 1px solid #e5e7eb;
- border-radius: 4px;
- padding: 12px;
- margin-top: 12px;
- font-family: 'Courier New', monospace;
- font-size: 0.875rem;
- color: #374151;
- white-space: pre-wrap;
- word-break: break-word;
-}
-
-/* Modal Footer */
-.modal-footer {
- padding: 16px 24px;
- border-top: 1px solid #e5e7eb;
- display: flex;
- justify-content: flex-end;
- gap: 12px;
-}
-
-/* Modal Icon Styles */
-.modal-icon {
- width: 48px;
- height: 48px;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 0 auto 16px;
- font-size: 24px;
-}
-
-.modal-icon.success {
- background-color: #d1fae5;
- color: #059669;
-}
-
-.modal-icon.error {
- background-color: #fee2e2;
- color: #dc2626;
-}
-
-.modal-icon.warning {
- background-color: #fef3c7;
- color: #f59e0b;
-}
-
-/* Loading Overlay */
-.loading-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.3);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10000;
-}
-
-.loading-spinner {
- width: 48px;
- height: 48px;
- border: 4px solid #e5e7eb;
- border-top-color: #3b82f6;
- border-radius: 50%;
- animation: spin 0.8s linear infinite;
-}
-
-@keyframes spin {
- to {
- transform: rotate(360deg);
- }
-}
-
-/* =============================================================================
- BUTTON STYLES
- ============================================================================= */
-
-.btn {
- padding: 10px 20px;
- border: none;
- border-radius: 6px;
- font-size: 0.95rem;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s;
- display: inline-flex;
- align-items: center;
- gap: 8px;
- text-decoration: none;
-}
-
-.btn:disabled {
- opacity: 0.5;
- cursor: not-allowed;
-}
-
-.btn-primary {
- background-color: #3b82f6;
- color: white;
-}
-
-.btn-primary:hover:not(:disabled) {
- background-color: #2563eb;
-}
-
-.btn-secondary {
- background-color: #6b7280;
- color: white;
-}
-
-.btn-secondary:hover:not(:disabled) {
- background-color: #4b5563;
-}
-
-.btn-success {
- background-color: #10b981;
- color: white;
-}
-
-.btn-success:hover:not(:disabled) {
- background-color: #059669;
-}
-
-.btn-danger {
- background-color: #ef4444;
- color: white;
-}
-
-.btn-danger:hover:not(:disabled) {
- background-color: #dc2626;
-}
-
-.btn-warning {
- background-color: #f59e0b;
- color: white;
-}
-
-.btn-warning:hover:not(:disabled) {
- background-color: #d97706;
-}
-
-.btn-outline {
- background-color: transparent;
- border: 1px solid #d1d5db;
- color: #374151;
-}
-
-.btn-outline:hover:not(:disabled) {
- background-color: #f9fafb;
- border-color: #9ca3af;
-}
-
-.btn-ghost {
- background-color: transparent;
- color: #6b7280;
-}
-
-.btn-ghost:hover:not(:disabled) {
- background-color: #f3f4f6;
-}
-
-.btn-sm {
- padding: 6px 12px;
- font-size: 0.875rem;
-}
-
-.btn-lg {
- padding: 12px 24px;
- font-size: 1.05rem;
-}
-
-/* =============================================================================
- ADMIN LAYOUT STYLES
- ============================================================================= */
-
-.admin-header {
- background-color: #1f2937;
- color: white;
- padding: 0 24px;
- height: 64px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- position: sticky;
- top: 0;
- z-index: 100;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.header-left {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-
-.header-title {
- font-size: 1.25rem;
- font-weight: 600;
- margin: 0;
-}
-
-.menu-toggle {
- background: none;
- border: none;
- color: white;
- font-size: 1.5rem;
- cursor: pointer;
- padding: 8px;
- display: none;
-}
-
-.header-right {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-
-.user-name {
- font-size: 0.95rem;
- color: #e5e7eb;
-}
-
-.btn-logout {
- background-color: #374151;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 0.9rem;
- transition: background-color 0.2s;
-}
-
-.btn-logout:hover {
- background-color: #4b5563;
-}
-
-.admin-sidebar {
- width: 260px;
- background-color: #f9fafb;
- border-right: 1px solid #e5e7eb;
- height: calc(100vh - 64px);
- position: fixed;
- left: 0;
- top: 64px;
- overflow-y: auto;
- transition: transform 0.3s ease;
-}
-
-.sidebar-nav {
- padding: 16px 0;
-}
-
-.nav-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 24px;
- color: #374151;
- text-decoration: none;
- transition: all 0.2s;
- font-size: 0.95rem;
-}
-
-.nav-item:hover {
- background-color: #e5e7eb;
- color: #111827;
-}
-
-.nav-item.active {
- background-color: #3b82f6;
- color: white;
- border-left: 4px solid #2563eb;
-}
-
-.nav-item i {
- width: 20px;
- text-align: center;
-}
-
-.admin-content {
- margin-left: 260px;
- padding: 24px;
- min-height: calc(100vh - 64px);
-}
-
-/* =============================================================================
- VENDOR LAYOUT STYLES
- ============================================================================= */
-
-.vendor-header {
- background-color: #059669;
- color: white;
- padding: 0 24px;
- height: 64px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- position: sticky;
- top: 0;
- z-index: 100;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.vendor-header .btn-logout {
- background-color: #047857;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 6px;
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 0.9rem;
- transition: background-color 0.2s;
-}
-
-.vendor-header .btn-logout:hover {
- background-color: #065f46;
-}
-
-.vendor-header .menu-toggle {
- background: none;
- border: none;
- color: white;
- font-size: 1.5rem;
- cursor: pointer;
- padding: 8px;
- display: none;
-}
-
-.vendor-sidebar {
- width: 260px;
- background-color: #f9fafb;
- border-right: 1px solid #e5e7eb;
- height: calc(100vh - 64px);
- position: fixed;
- left: 0;
- top: 64px;
- overflow-y: auto;
- transition: transform 0.3s ease;
-}
-
-.vendor-content {
- margin-left: 260px;
- padding: 24px;
- min-height: calc(100vh - 64px);
-}
-
-/* =============================================================================
- SHOP LAYOUT STYLES
- ============================================================================= */
-
-.shop-header {
- background-color: white;
- border-bottom: 1px solid #e5e7eb;
- padding: 16px 24px;
- position: sticky;
- top: 0;
- z-index: 100;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
-}
-
-.shop-header-top {
- display: flex;
- align-items: center;
- justify-content: space-between;
- max-width: 1280px;
- margin: 0 auto;
-}
-
-.shop-logo {
- font-size: 1.5rem;
- font-weight: 700;
- color: #111827;
- text-decoration: none;
-}
-
-.shop-search {
- flex: 1;
- max-width: 500px;
- margin: 0 32px;
-}
-
-.search-form {
- display: flex;
- gap: 8px;
-}
-
-.search-input {
- flex: 1;
- padding: 10px 16px;
- border: 1px solid #d1d5db;
- border-radius: 6px;
- font-size: 0.95rem;
-}
-
-.search-input:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-.shop-actions {
- display: flex;
- align-items: center;
- gap: 16px;
-}
-
-.cart-button {
- position: relative;
- background: none;
- border: none;
- cursor: pointer;
- padding: 8px;
- font-size: 1.5rem;
- color: #374151;
-}
-
-.cart-button:hover {
- color: #111827;
-}
-
-.cart-count {
- position: absolute;
- top: 0;
- right: 0;
- background-color: #ef4444;
- color: white;
- font-size: 0.75rem;
- font-weight: 600;
- padding: 2px 6px;
- border-radius: 10px;
- min-width: 20px;
- text-align: center;
-}
-
-.shop-nav {
- display: flex;
- gap: 24px;
- max-width: 1280px;
- margin: 16px auto 0;
- padding-top: 16px;
- border-top: 1px solid #e5e7eb;
-}
-
-.shop-nav-item {
- color: #6b7280;
- text-decoration: none;
- font-size: 0.95rem;
- padding: 8px 0;
- transition: color 0.2s;
-}
-
-.shop-nav-item:hover {
- color: #111827;
-}
-
-.shop-nav-item.active {
- color: #3b82f6;
- font-weight: 500;
- border-bottom: 2px solid #3b82f6;
-}
-
-.shop-content {
- max-width: 1280px;
- margin: 0 auto;
- padding: 32px 24px;
-}
-
-/* =============================================================================
- SHOP ACCOUNT LAYOUT STYLES
- ============================================================================= */
-
-.account-layout {
- display: grid;
- grid-template-columns: 260px 1fr;
- gap: 32px;
- max-width: 1280px;
- margin: 0 auto;
- padding: 32px 24px;
-}
-
-.account-sidebar {
- background-color: #f9fafb;
- border: 1px solid #e5e7eb;
- border-radius: 8px;
- padding: 16px;
- height: fit-content;
-}
-
-.account-nav-item {
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 12px 16px;
- color: #374151;
- text-decoration: none;
- border-radius: 6px;
- transition: all 0.2s;
- font-size: 0.95rem;
-}
-
-.account-nav-item:hover {
- background-color: #e5e7eb;
-}
-
-.account-nav-item.active {
- background-color: #3b82f6;
- color: white;
-}
-
-.account-content {
- background-color: white;
- border: 1px solid #e5e7eb;
- border-radius: 8px;
- padding: 32px;
-}
-
-/* =============================================================================
- RESPONSIVE STYLES
- ============================================================================= */
-
-@media (max-width: 768px) {
- .menu-toggle {
- display: block;
- }
-
- .vendor-header .menu-toggle {
- display: block;
- }
-
- .admin-sidebar,
- .vendor-sidebar {
- transform: translateX(-100%);
- }
-
- .admin-sidebar.open,
- .vendor-sidebar.open {
- transform: translateX(0);
- }
-
- .admin-content,
- .vendor-content {
- margin-left: 0;
- }
-
- .shop-search {
- display: none;
- }
-
- .account-layout {
- grid-template-columns: 1fr;
- }
-
- .account-sidebar {
- display: none;
- }
-
- .modal-container {
- width: 95%;
- margin: 16px;
- }
-
- .modal-footer {
- flex-direction: column;
- }
-
- .modal-footer .btn {
- width: 100%;
- }
-}
-
-/* =============================================================================
- UTILITY CLASSES
- ============================================================================= */
-
-.text-center {
- text-align: center;
-}
-
-.mb-0 { margin-bottom: 0; }
-.mb-1 { margin-bottom: 8px; }
-.mb-2 { margin-bottom: 16px; }
-.mb-3 { margin-bottom: 24px; }
-.mb-4 { margin-bottom: 32px; }
-
-.mt-0 { margin-top: 0; }
-.mt-1 { margin-top: 8px; }
-.mt-2 { margin-top: 16px; }
-.mt-3 { margin-top: 24px; }
-.mt-4 { margin-top: 32px; }
-
-.hidden {
- display: none !important;
-}
-
-.pointer {
- cursor: pointer;
-}
\ No newline at end of file
diff --git a/static/css/shared/modals.css b/static/css/shared/modals.css
deleted file mode 100644
index 35ce7cd1..00000000
--- a/static/css/shared/modals.css
+++ /dev/null
@@ -1,428 +0,0 @@
-/**
- * Enhanced Modal Styles
- * Additional styling and animations for modal system
- */
-
-/* =============================================================================
- MODAL ANIMATIONS
- ============================================================================= */
-
-/* Fade In Animation */
-@keyframes modalFadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
-}
-
-/* Slide Down Animation */
-@keyframes modalSlideDown {
- from {
- transform: translateY(-50px);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
-}
-
-/* Slide Up Animation */
-@keyframes modalSlideUp {
- from {
- transform: translateY(50px);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
-}
-
-/* Scale Animation */
-@keyframes modalScale {
- from {
- transform: scale(0.9);
- opacity: 0;
- }
- to {
- transform: scale(1);
- opacity: 1;
- }
-}
-
-/* Shake Animation for errors */
-@keyframes modalShake {
- 0%, 100% {
- transform: translateX(0);
- }
- 10%, 30%, 50%, 70%, 90% {
- transform: translateX(-10px);
- }
- 20%, 40%, 60%, 80% {
- transform: translateX(10px);
- }
-}
-
-/* =============================================================================
- MODAL VARIANTS
- ============================================================================= */
-
-/* Modal with slide down animation */
-.modal-container.slide-down {
- animation: modalSlideDown 0.3s ease-out;
-}
-
-/* Modal with scale animation */
-.modal-container.scale {
- animation: modalScale 0.3s ease-out;
-}
-
-/* Modal with shake animation (for errors) */
-.modal-container.shake {
- animation: modalShake 0.5s ease-in-out;
-}
-
-/* =============================================================================
- MODAL SIZES
- ============================================================================= */
-
-.modal-container.modal-sm {
- max-width: 400px;
-}
-
-.modal-container.modal-md {
- max-width: 500px;
-}
-
-.modal-container.modal-lg {
- max-width: 700px;
-}
-
-.modal-container.modal-xl {
- max-width: 900px;
-}
-
-.modal-container.modal-full {
- max-width: 95%;
- max-height: 95vh;
-}
-
-/* =============================================================================
- MODAL THEMES
- ============================================================================= */
-
-/* Success Modal Theme */
-.modal-container.modal-success .modal-header {
- background-color: #d1fae5;
- border-bottom-color: #a7f3d0;
-}
-
-.modal-container.modal-success .modal-title {
- color: #065f46;
-}
-
-/* Error Modal Theme */
-.modal-container.modal-error .modal-header {
- background-color: #fee2e2;
- border-bottom-color: #fecaca;
-}
-
-.modal-container.modal-error .modal-title {
- color: #991b1b;
-}
-
-/* Warning Modal Theme */
-.modal-container.modal-warning .modal-header {
- background-color: #fef3c7;
- border-bottom-color: #fde68a;
-}
-
-.modal-container.modal-warning .modal-title {
- color: #92400e;
-}
-
-/* Info Modal Theme */
-.modal-container.modal-info .modal-header {
- background-color: #dbeafe;
- border-bottom-color: #bfdbfe;
-}
-
-.modal-container.modal-info .modal-title {
- color: #1e40af;
-}
-
-/* =============================================================================
- MODAL CONTENT STYLES
- ============================================================================= */
-
-/* Modal List */
-.modal-list {
- list-style: none;
- padding: 0;
- margin: 16px 0;
-}
-
-.modal-list-item {
- padding: 12px;
- border-bottom: 1px solid #e5e7eb;
- display: flex;
- align-items: center;
- gap: 12px;
-}
-
-.modal-list-item:last-child {
- border-bottom: none;
-}
-
-.modal-list-item i {
- width: 20px;
- text-align: center;
- color: #6b7280;
-}
-
-/* Modal Form Elements */
-.modal-form-group {
- margin-bottom: 16px;
-}
-
-.modal-label {
- display: block;
- margin-bottom: 8px;
- font-weight: 500;
- color: #374151;
- font-size: 0.95rem;
-}
-
-.modal-input,
-.modal-textarea,
-.modal-select {
- width: 100%;
- padding: 10px 12px;
- border: 1px solid #d1d5db;
- border-radius: 6px;
- font-size: 0.95rem;
- transition: all 0.2s;
-}
-
-.modal-input:focus,
-.modal-textarea:focus,
-.modal-select:focus {
- outline: none;
- border-color: #3b82f6;
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
-}
-
-.modal-textarea {
- min-height: 100px;
- resize: vertical;
-}
-
-.modal-input.error,
-.modal-textarea.error,
-.modal-select.error {
- border-color: #ef4444;
-}
-
-.modal-error-text {
- color: #ef4444;
- font-size: 0.875rem;
- margin-top: 4px;
-}
-
-.modal-help-text {
- color: #6b7280;
- font-size: 0.875rem;
- margin-top: 4px;
-}
-
-/* =============================================================================
- MODAL ALERTS
- ============================================================================= */
-
-.modal-alert {
- padding: 12px 16px;
- border-radius: 6px;
- margin-bottom: 16px;
- display: flex;
- align-items: start;
- gap: 12px;
-}
-
-.modal-alert i {
- margin-top: 2px;
-}
-
-.modal-alert.alert-success {
- background-color: #d1fae5;
- color: #065f46;
- border: 1px solid #a7f3d0;
-}
-
-.modal-alert.alert-error {
- background-color: #fee2e2;
- color: #991b1b;
- border: 1px solid #fecaca;
-}
-
-.modal-alert.alert-warning {
- background-color: #fef3c7;
- color: #92400e;
- border: 1px solid #fde68a;
-}
-
-.modal-alert.alert-info {
- background-color: #dbeafe;
- color: #1e40af;
- border: 1px solid #bfdbfe;
-}
-
-/* =============================================================================
- MODAL PROGRESS
- ============================================================================= */
-
-.modal-progress {
- width: 100%;
- height: 8px;
- background-color: #e5e7eb;
- border-radius: 4px;
- overflow: hidden;
- margin: 16px 0;
-}
-
-.modal-progress-bar {
- height: 100%;
- background-color: #3b82f6;
- transition: width 0.3s ease;
-}
-
-.modal-progress-bar.success {
- background-color: #10b981;
-}
-
-.modal-progress-bar.error {
- background-color: #ef4444;
-}
-
-.modal-progress-bar.warning {
- background-color: #f59e0b;
-}
-
-/* =============================================================================
- LOADING SPINNER VARIANTS
- ============================================================================= */
-
-.loading-spinner.spinner-sm {
- width: 32px;
- height: 32px;
- border-width: 3px;
-}
-
-.loading-spinner.spinner-lg {
- width: 64px;
- height: 64px;
- border-width: 5px;
-}
-
-.loading-spinner.spinner-success {
- border-top-color: #10b981;
-}
-
-.loading-spinner.spinner-error {
- border-top-color: #ef4444;
-}
-
-.loading-spinner.spinner-warning {
- border-top-color: #f59e0b;
-}
-
-/* =============================================================================
- MODAL BACKDROP VARIANTS
- ============================================================================= */
-
-.modal-backdrop.backdrop-dark {
- background-color: rgba(0, 0, 0, 0.7);
-}
-
-.modal-backdrop.backdrop-light {
- background-color: rgba(0, 0, 0, 0.3);
-}
-
-.modal-backdrop.backdrop-blur {
- backdrop-filter: blur(4px);
-}
-
-/* =============================================================================
- RESPONSIVE ENHANCEMENTS
- ============================================================================= */
-
-@media (max-width: 640px) {
- .modal-container {
- width: 100%;
- max-width: 100%;
- max-height: 100vh;
- border-radius: 0;
- margin: 0;
- }
-
- .modal-header {
- padding: 16px 20px;
- }
-
- .modal-body {
- padding: 20px;
- }
-
- .modal-footer {
- padding: 12px 20px;
- flex-direction: column-reverse;
- }
-
- .modal-footer .btn {
- width: 100%;
- }
-
- .modal-alert {
- flex-direction: column;
- }
-}
-
-/* =============================================================================
- ACCESSIBILITY
- ============================================================================= */
-
-.modal-backdrop:focus {
- outline: none;
-}
-
-.modal-container:focus {
- outline: 2px solid #3b82f6;
- outline-offset: -2px;
-}
-
-/* Reduce motion for users who prefer it */
-@media (prefers-reduced-motion: reduce) {
- .modal-backdrop,
- .modal-container,
- .loading-spinner {
- animation: none !important;
- transition: none !important;
- }
-}
-
-/* High contrast mode support */
-@media (prefers-contrast: high) {
- .modal-container {
- border: 2px solid currentColor;
- }
-
- .modal-header {
- border-bottom-width: 2px;
- }
-
- .modal-footer {
- border-top-width: 2px;
- }
-}
\ No newline at end of file
diff --git a/static/css/shared/responsive-utilities.css b/static/css/shared/responsive-utilities.css
deleted file mode 100644
index f65082ee..00000000
--- a/static/css/shared/responsive-utilities.css
+++ /dev/null
@@ -1,370 +0,0 @@
-/* static/css/shared/responsive-utilities.css */
-/* Responsive utility classes - Framework-like responsiveness without the framework */
-
-/* ================================
- BREAKPOINTS (Mobile-first)
- ================================ */
-:root {
- --breakpoint-sm: 640px;
- --breakpoint-md: 768px;
- --breakpoint-lg: 1024px;
- --breakpoint-xl: 1280px;
- --breakpoint-2xl: 1536px;
-}
-
-/* ================================
- CONTAINER
- ================================ */
-.container {
- width: 100%;
- margin-left: auto;
- margin-right: auto;
- padding-left: var(--spacing-md);
- padding-right: var(--spacing-md);
-}
-
-@media (min-width: 640px) {
- .container { max-width: 640px; }
-}
-
-@media (min-width: 768px) {
- .container { max-width: 768px; }
-}
-
-@media (min-width: 1024px) {
- .container { max-width: 1024px; }
-}
-
-@media (min-width: 1280px) {
- .container { max-width: 1280px; }
-}
-
-/* ================================
- DISPLAY UTILITIES
- ================================ */
-.hidden { display: none !important; }
-.block { display: block !important; }
-.inline-block { display: inline-block !important; }
-.inline { display: inline !important; }
-.flex { display: flex !important; }
-.inline-flex { display: inline-flex !important; }
-.grid { display: grid !important; }
-
-/* Responsive Display */
-@media (max-width: 639px) {
- .sm\:hidden { display: none !important; }
- .sm\:block { display: block !important; }
- .sm\:flex { display: flex !important; }
- .sm\:grid { display: grid !important; }
-}
-
-@media (min-width: 640px) and (max-width: 767px) {
- .md\:hidden { display: none !important; }
- .md\:block { display: block !important; }
- .md\:flex { display: flex !important; }
- .md\:grid { display: grid !important; }
-}
-
-@media (min-width: 768px) and (max-width: 1023px) {
- .lg\:hidden { display: none !important; }
- .lg\:block { display: block !important; }
- .lg\:flex { display: flex !important; }
- .lg\:grid { display: grid !important; }
-}
-
-@media (min-width: 1024px) {
- .xl\:hidden { display: none !important; }
- .xl\:block { display: block !important; }
- .xl\:flex { display: flex !important; }
- .xl\:grid { display: grid !important; }
-}
-
-/* ================================
- FLEXBOX UTILITIES
- ================================ */
-.flex-row { flex-direction: row; }
-.flex-col { flex-direction: column; }
-.flex-row-reverse { flex-direction: row-reverse; }
-.flex-col-reverse { flex-direction: column-reverse; }
-
-.flex-wrap { flex-wrap: wrap; }
-.flex-nowrap { flex-wrap: nowrap; }
-
-.items-start { align-items: flex-start; }
-.items-center { align-items: center; }
-.items-end { align-items: flex-end; }
-.items-stretch { align-items: stretch; }
-
-.justify-start { justify-content: flex-start; }
-.justify-center { justify-content: center; }
-.justify-end { justify-content: flex-end; }
-.justify-between { justify-content: space-between; }
-.justify-around { justify-content: space-around; }
-.justify-evenly { justify-content: space-evenly; }
-
-.flex-1 { flex: 1 1 0%; }
-.flex-auto { flex: 1 1 auto; }
-.flex-none { flex: none; }
-
-.gap-0 { gap: 0; }
-.gap-1 { gap: var(--spacing-xs); }
-.gap-2 { gap: var(--spacing-sm); }
-.gap-3 { gap: var(--spacing-md); }
-.gap-4 { gap: var(--spacing-lg); }
-.gap-5 { gap: var(--spacing-xl); }
-.gap-6 { gap: var(--spacing-2xl); }
-
-/* ================================
- GRID UTILITIES
- ================================ */
-.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
-.grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
-.grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
-.grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
-.grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
-.grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }
-
-/* Responsive Grid */
-@media (min-width: 640px) {
- .sm\:grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
- .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .sm\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
- .sm\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
-}
-
-@media (min-width: 768px) {
- .md\:grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
- .md\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .md\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
- .md\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
-}
-
-@media (min-width: 1024px) {
- .lg\:grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
- .lg\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
- .lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
- .lg\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
-}
-
-/* ================================
- SPACING UTILITIES
- ================================ */
-/* Margin */
-.m-0 { margin: 0; }
-.m-1 { margin: var(--spacing-xs); }
-.m-2 { margin: var(--spacing-sm); }
-.m-3 { margin: var(--spacing-md); }
-.m-4 { margin: var(--spacing-lg); }
-.m-5 { margin: var(--spacing-xl); }
-.m-auto { margin: auto; }
-
-.mx-auto { margin-left: auto; margin-right: auto; }
-.my-auto { margin-top: auto; margin-bottom: auto; }
-
-.mt-0 { margin-top: 0; }
-.mt-1 { margin-top: var(--spacing-xs); }
-.mt-2 { margin-top: var(--spacing-sm); }
-.mt-3 { margin-top: var(--spacing-md); }
-.mt-4 { margin-top: var(--spacing-lg); }
-.mt-5 { margin-top: var(--spacing-xl); }
-
-.mb-0 { margin-bottom: 0; }
-.mb-1 { margin-bottom: var(--spacing-xs); }
-.mb-2 { margin-bottom: var(--spacing-sm); }
-.mb-3 { margin-bottom: var(--spacing-md); }
-.mb-4 { margin-bottom: var(--spacing-lg); }
-.mb-5 { margin-bottom: var(--spacing-xl); }
-
-.ml-0 { margin-left: 0; }
-.ml-1 { margin-left: var(--spacing-xs); }
-.ml-2 { margin-left: var(--spacing-sm); }
-.ml-3 { margin-left: var(--spacing-md); }
-.ml-4 { margin-left: var(--spacing-lg); }
-.ml-auto { margin-left: auto; }
-
-.mr-0 { margin-right: 0; }
-.mr-1 { margin-right: var(--spacing-xs); }
-.mr-2 { margin-right: var(--spacing-sm); }
-.mr-3 { margin-right: var(--spacing-md); }
-.mr-4 { margin-right: var(--spacing-lg); }
-.mr-auto { margin-right: auto; }
-
-/* Padding */
-.p-0 { padding: 0; }
-.p-1 { padding: var(--spacing-xs); }
-.p-2 { padding: var(--spacing-sm); }
-.p-3 { padding: var(--spacing-md); }
-.p-4 { padding: var(--spacing-lg); }
-.p-5 { padding: var(--spacing-xl); }
-
-.px-0 { padding-left: 0; padding-right: 0; }
-.px-1 { padding-left: var(--spacing-xs); padding-right: var(--spacing-xs); }
-.px-2 { padding-left: var(--spacing-sm); padding-right: var(--spacing-sm); }
-.px-3 { padding-left: var(--spacing-md); padding-right: var(--spacing-md); }
-.px-4 { padding-left: var(--spacing-lg); padding-right: var(--spacing-lg); }
-
-.py-0 { padding-top: 0; padding-bottom: 0; }
-.py-1 { padding-top: var(--spacing-xs); padding-bottom: var(--spacing-xs); }
-.py-2 { padding-top: var(--spacing-sm); padding-bottom: var(--spacing-sm); }
-.py-3 { padding-top: var(--spacing-md); padding-bottom: var(--spacing-md); }
-.py-4 { padding-top: var(--spacing-lg); padding-bottom: var(--spacing-lg); }
-
-/* ================================
- WIDTH & HEIGHT UTILITIES
- ================================ */
-.w-full { width: 100%; }
-.w-auto { width: auto; }
-.w-1\/2 { width: 50%; }
-.w-1\/3 { width: 33.333333%; }
-.w-2\/3 { width: 66.666667%; }
-.w-1\/4 { width: 25%; }
-.w-3\/4 { width: 75%; }
-
-.h-full { height: 100%; }
-.h-auto { height: auto; }
-.h-screen { height: 100vh; }
-
-.min-h-screen { min-height: 100vh; }
-.max-w-full { max-width: 100%; }
-
-/* ================================
- TEXT UTILITIES
- ================================ */
-.text-left { text-align: left; }
-.text-center { text-align: center; }
-.text-right { text-align: right; }
-
-.text-xs { font-size: var(--font-xs); }
-.text-sm { font-size: var(--font-sm); }
-.text-base { font-size: var(--font-base); }
-.text-lg { font-size: var(--font-lg); }
-.text-xl { font-size: var(--font-xl); }
-.text-2xl { font-size: var(--font-2xl); }
-.text-3xl { font-size: var(--font-3xl); }
-
-.font-normal { font-weight: 400; }
-.font-medium { font-weight: 500; }
-.font-semibold { font-weight: 600; }
-.font-bold { font-weight: 700; }
-
-.uppercase { text-transform: uppercase; }
-.lowercase { text-transform: lowercase; }
-.capitalize { text-transform: capitalize; }
-
-.truncate {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-/* ================================
- POSITION UTILITIES
- ================================ */
-.relative { position: relative; }
-.absolute { position: absolute; }
-.fixed { position: fixed; }
-.sticky { position: sticky; }
-
-.top-0 { top: 0; }
-.right-0 { right: 0; }
-.bottom-0 { bottom: 0; }
-.left-0 { left: 0; }
-
-.z-0 { z-index: 0; }
-.z-10 { z-index: 10; }
-.z-20 { z-index: 20; }
-.z-30 { z-index: 30; }
-.z-40 { z-index: 40; }
-.z-50 { z-index: 50; }
-
-/* ================================
- OVERFLOW UTILITIES
- ================================ */
-.overflow-auto { overflow: auto; }
-.overflow-hidden { overflow: hidden; }
-.overflow-visible { overflow: visible; }
-.overflow-scroll { overflow: scroll; }
-
-.overflow-x-auto { overflow-x: auto; }
-.overflow-y-auto { overflow-y: auto; }
-
-/* ================================
- BORDER UTILITIES
- ================================ */
-.rounded-none { border-radius: 0; }
-.rounded-sm { border-radius: var(--radius-sm); }
-.rounded { border-radius: var(--radius-md); }
-.rounded-lg { border-radius: var(--radius-lg); }
-.rounded-xl { border-radius: var(--radius-xl); }
-.rounded-full { border-radius: var(--radius-full); }
-
-.border { border: 1px solid var(--border-color); }
-.border-0 { border: 0; }
-.border-2 { border: 2px solid var(--border-color); }
-
-/* ================================
- SHADOW UTILITIES
- ================================ */
-.shadow-none { box-shadow: none; }
-.shadow-sm { box-shadow: var(--shadow-sm); }
-.shadow { box-shadow: var(--shadow-md); }
-.shadow-lg { box-shadow: var(--shadow-lg); }
-.shadow-xl { box-shadow: var(--shadow-xl); }
-
-/* ================================
- RESPONSIVE HELPERS
- ================================ */
-/* Hide on mobile, show on desktop */
-.mobile-hidden {
- display: none;
-}
-
-@media (min-width: 768px) {
- .mobile-hidden {
- display: block;
- }
-}
-
-/* Show on mobile, hide on desktop */
-.desktop-hidden {
- display: block;
-}
-
-@media (min-width: 768px) {
- .desktop-hidden {
- display: none;
- }
-}
-
-/* Tablet specific */
-@media (min-width: 640px) and (max-width: 1023px) {
- .tablet-only {
- display: block;
- }
-}
-
-/* ================================
- CURSOR & POINTER EVENTS
- ================================ */
-.cursor-pointer { cursor: pointer; }
-.cursor-default { cursor: default; }
-.cursor-not-allowed { cursor: not-allowed; }
-.pointer-events-none { pointer-events: none; }
-
-/* ================================
- OPACITY UTILITIES
- ================================ */
-.opacity-0 { opacity: 0; }
-.opacity-25 { opacity: 0.25; }
-.opacity-50 { opacity: 0.5; }
-.opacity-75 { opacity: 0.75; }
-.opacity-100 { opacity: 1; }
-
-/* ================================
- TRANSITION UTILITIES
- ================================ */
-.transition { transition: all var(--transition-base); }
-.transition-fast { transition: all var(--transition-fast); }
-.transition-slow { transition: all var(--transition-slow); }
-.transition-none { transition: none; }
\ No newline at end of file
diff --git a/static/css/vendor/vendor.css b/static/css/vendor/vendor.css
deleted file mode 100644
index a684a443..00000000
--- a/static/css/vendor/vendor.css
+++ /dev/null
@@ -1,601 +0,0 @@
-/* static/css/vendor/vendor.css */
-/* Vendor-specific styles */
-
-/* Vendor Header */
-.vendor-header {
- background: white;
- border-bottom: 1px solid var(--border-color);
- padding: 16px 24px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- box-shadow: var(--shadow-sm);
- position: sticky;
- top: 0;
- z-index: 100;
-}
-
-.vendor-header h1 {
- font-size: var(--font-2xl);
- color: var(--text-primary);
- font-weight: 600;
-}
-
-.vendor-logo {
- display: flex;
- align-items: center;
- gap: var(--spacing-md);
-}
-
-.vendor-logo-img {
- width: 40px;
- height: 40px;
- border-radius: var(--radius-md);
- object-fit: cover;
-}
-
-.vendor-name {
- font-size: var(--font-xl);
- font-weight: 700;
- color: var(--primary-color);
-}
-
-/* Vendor Container */
-.vendor-container {
- display: flex;
- min-height: calc(100vh - 64px);
-}
-
-/* Vendor Sidebar */
-.vendor-sidebar {
- width: 260px;
- background: white;
- border-right: 1px solid var(--border-color);
- padding: var(--spacing-lg) 0;
- overflow-y: auto;
-}
-
-.vendor-sidebar-header {
- padding: 0 var(--spacing-lg) var(--spacing-lg);
- border-bottom: 1px solid var(--border-color);
- margin-bottom: var(--spacing-md);
-}
-
-.vendor-status {
- display: flex;
- gap: var(--spacing-sm);
- margin-top: var(--spacing-sm);
-}
-
-/* Vendor Content */
-.vendor-content {
- flex: 1;
- padding: var(--spacing-lg);
- overflow-y: auto;
- background: var(--bg-secondary);
-}
-
-/* Vendor Dashboard Widgets */
-.dashboard-widgets {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: var(--spacing-lg);
- margin-bottom: var(--spacing-xl);
-}
-
-.widget {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
-}
-
-.widget-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--spacing-md);
-}
-
-.widget-title {
- font-size: var(--font-lg);
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.widget-icon {
- font-size: var(--font-2xl);
- color: var(--primary-color);
-}
-
-.widget-content {
- margin-bottom: var(--spacing-md);
-}
-
-.widget-footer {
- padding-top: var(--spacing-md);
- border-top: 1px solid var(--border-color);
-}
-
-.widget-stat {
- font-size: var(--font-4xl);
- font-weight: 700;
- color: var(--text-primary);
- line-height: 1;
- margin-bottom: var(--spacing-sm);
-}
-
-.widget-label {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-/* Welcome Card */
-.welcome-card {
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- color: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-xl);
- box-shadow: var(--shadow-lg);
- margin-bottom: var(--spacing-xl);
- text-align: center;
-}
-
-.welcome-icon {
- font-size: 64px;
- margin-bottom: var(--spacing-lg);
- opacity: 0.9;
-}
-
-.welcome-card h2 {
- color: white;
- font-size: var(--font-3xl);
- margin-bottom: var(--spacing-md);
-}
-
-.welcome-card p {
- color: rgba(255, 255, 255, 0.9);
- font-size: var(--font-lg);
- margin-bottom: var(--spacing-sm);
-}
-
-/* Vendor Info Card */
-.vendor-info-card {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- margin-top: var(--spacing-lg);
-}
-
-.info-item {
- display: flex;
- justify-content: space-between;
- padding: 12px 0;
- border-bottom: 1px solid var(--border-color);
-}
-
-.info-item:last-child {
- border-bottom: none;
-}
-
-.info-label {
- font-weight: 600;
- color: var(--text-secondary);
- font-size: var(--font-base);
-}
-
-.info-value {
- color: var(--text-primary);
- font-size: var(--font-base);
- text-align: right;
-}
-
-/* Coming Soon Badge */
-.coming-soon {
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- color: white;
- padding: 12px 24px;
- border-radius: var(--radius-lg);
- display: inline-block;
- font-weight: 600;
- margin-top: var(--spacing-lg);
- box-shadow: var(--shadow-md);
-}
-
-/* Product Grid */
-.product-grid {
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
- gap: var(--spacing-lg);
- margin-bottom: var(--spacing-xl);
-}
-
-.product-card {
- background: white;
- border-radius: var(--radius-lg);
- overflow: hidden;
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
- transition: all var(--transition-base);
- cursor: pointer;
-}
-
-.product-card:hover {
- transform: translateY(-4px);
- box-shadow: var(--shadow-lg);
-}
-
-.product-image {
- width: 100%;
- height: 200px;
- object-fit: cover;
- background: var(--gray-100);
-}
-
-.product-info {
- padding: var(--spacing-md);
-}
-
-.product-title {
- font-size: var(--font-lg);
- font-weight: 600;
- color: var(--text-primary);
- margin-bottom: var(--spacing-sm);
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.product-price {
- font-size: var(--font-xl);
- font-weight: 700;
- color: var(--primary-color);
- margin-bottom: var(--spacing-sm);
-}
-
-.product-description {
- font-size: var(--font-sm);
- color: var(--text-muted);
- line-height: 1.5;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- overflow: hidden;
-}
-
-.product-actions {
- padding: var(--spacing-md);
- border-top: 1px solid var(--border-color);
- display: flex;
- gap: var(--spacing-sm);
-}
-
-/* Order List */
-.order-list {
- display: flex;
- flex-direction: column;
- gap: var(--spacing-md);
-}
-
-.order-card {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
- transition: all var(--transition-base);
-}
-
-.order-card:hover {
- box-shadow: var(--shadow-lg);
-}
-
-.order-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: var(--spacing-md);
- padding-bottom: var(--spacing-md);
- border-bottom: 1px solid var(--border-color);
-}
-
-.order-number {
- font-size: var(--font-lg);
- font-weight: 600;
- color: var(--text-primary);
-}
-
-.order-date {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.order-body {
- margin-bottom: var(--spacing-md);
-}
-
-.order-items {
- font-size: var(--font-sm);
- color: var(--text-secondary);
-}
-
-.order-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.order-total {
- font-size: var(--font-xl);
- font-weight: 700;
- color: var(--text-primary);
-}
-
-/* Tabs */
-.tabs {
- display: flex;
- gap: var(--spacing-sm);
- margin-bottom: var(--spacing-lg);
- border-bottom: 2px solid var(--border-color);
-}
-
-.tab {
- padding: 12px 24px;
- background: none;
- border: none;
- border-bottom: 2px solid transparent;
- cursor: pointer;
- font-size: var(--font-base);
- font-weight: 500;
- color: var(--text-secondary);
- transition: all var(--transition-base);
- margin-bottom: -2px;
-}
-
-.tab:hover {
- color: var(--primary-color);
-}
-
-.tab.active {
- color: var(--primary-color);
- border-bottom-color: var(--primary-color);
-}
-
-/* File Upload */
-.upload-area {
- border: 2px dashed var(--border-color);
- border-radius: var(--radius-lg);
- padding: var(--spacing-xl);
- text-align: center;
- cursor: pointer;
- transition: all var(--transition-base);
-}
-
-.upload-area:hover,
-.upload-area.dragover {
- border-color: var(--primary-color);
- background: rgba(102, 126, 234, 0.05);
-}
-
-.upload-icon {
- font-size: 48px;
- color: var(--text-muted);
- margin-bottom: var(--spacing-md);
-}
-
-.upload-text {
- font-size: var(--font-base);
- color: var(--text-secondary);
- margin-bottom: var(--spacing-sm);
-}
-
-.upload-hint {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.file-list {
- margin-top: var(--spacing-md);
-}
-
-.file-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: var(--spacing-md);
- background: var(--gray-50);
- border-radius: var(--radius-md);
- margin-bottom: var(--spacing-sm);
-}
-
-.file-name {
- font-size: var(--font-base);
- color: var(--text-primary);
-}
-
-.file-size {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.file-remove {
- background: none;
- border: none;
- color: var(--danger-color);
- cursor: pointer;
- font-size: var(--font-lg);
- padding: var(--spacing-sm);
-}
-
-/* Progress Bar */
-.progress {
- width: 100%;
- height: 8px;
- background: var(--gray-200);
- border-radius: var(--radius-full);
- overflow: hidden;
-}
-
-.progress-bar {
- height: 100%;
- background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
- transition: width var(--transition-base);
-}
-
-.progress-text {
- text-align: center;
- font-size: var(--font-sm);
- color: var(--text-muted);
- margin-top: var(--spacing-sm);
-}
-
-/* Settings Form */
-.settings-section {
- background: white;
- border-radius: var(--radius-lg);
- padding: var(--spacing-lg);
- box-shadow: var(--shadow-md);
- border: 1px solid var(--border-color);
- margin-bottom: var(--spacing-lg);
-}
-
-.settings-header {
- margin-bottom: var(--spacing-lg);
- padding-bottom: var(--spacing-md);
- border-bottom: 2px solid var(--border-color);
-}
-
-.settings-title {
- font-size: var(--font-xl);
- font-weight: 600;
- color: var(--text-primary);
- margin-bottom: var(--spacing-sm);
-}
-
-.settings-description {
- font-size: var(--font-sm);
- color: var(--text-muted);
-}
-
-.settings-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
- gap: var(--spacing-lg);
- margin-bottom: var(--spacing-lg);
-}
-
-/* Responsive Design */
-@media (max-width: 1024px) {
- .vendor-sidebar {
- width: 220px;
- }
-
- .dashboard-widgets {
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
- }
-
- .product-grid {
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
- }
-}
-
-@media (max-width: 768px) {
- .vendor-container {
- flex-direction: column;
- }
-
- .vendor-sidebar {
- width: 100%;
- border-right: none;
- border-bottom: 1px solid var(--border-color);
- padding: var(--spacing-md) 0;
- }
-
- .vendor-content {
- padding: var(--spacing-md);
- }
-
- .dashboard-widgets,
- .product-grid {
- grid-template-columns: 1fr;
- }
-
- .welcome-card {
- padding: var(--spacing-lg);
- }
-
- .welcome-icon {
- font-size: 48px;
- }
-
- .welcome-card h2 {
- font-size: var(--font-2xl);
- }
-
- .tabs {
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- }
-
- .tab {
- white-space: nowrap;
- }
-
- .settings-row {
- grid-template-columns: 1fr;
- }
-}
-
-@media (max-width: 480px) {
- .vendor-header {
- padding: 12px 16px;
- }
-
- .vendor-header h1 {
- font-size: var(--font-lg);
- }
-
- .vendor-name {
- font-size: var(--font-lg);
- }
-
- .widget-stat {
- font-size: var(--font-3xl);
- }
-
- .settings-section {
- padding: var(--spacing-md);
- }
-
- .info-item {
- flex-direction: column;
- gap: var(--spacing-xs);
- }
-
- .info-value {
- text-align: left;
- }
-}
-
-/* Print Styles */
-@media print {
- .vendor-sidebar,
- .vendor-header .header-right,
- .product-actions,
- .order-footer .btn {
- display: none;
- }
-
- .vendor-content {
- padding: 0;
- }
-
- .settings-section,
- .order-card,
- .product-card {
- box-shadow: none;
- border: 1px solid var(--border-color);
- break-inside: avoid;
- }
-}
\ No newline at end of file
diff --git a/static/js/shared/alpine-components.js b/static/js/shared/alpine-components.js
deleted file mode 100644
index 6080b090..00000000
--- a/static/js/shared/alpine-components.js
+++ /dev/null
@@ -1,581 +0,0 @@
-/**
- * Alpine.js Components for Multi-Tenant E-commerce Platform
- * Universal component system for Admin, Vendor, and Shop sections
- */
-
-// =============================================================================
-// BASE MODAL SYSTEM
-// Universal modal functions used by all sections
-// =============================================================================
-
-window.baseModalSystem = function() {
- return {
- // Confirmation Modal State
- confirmModal: {
- show: false,
- title: '',
- message: '',
- warning: '',
- buttonText: 'Confirm',
- buttonClass: 'btn-danger',
- onConfirm: null,
- onCancel: null
- },
-
- // Success Modal State
- successModal: {
- show: false,
- title: 'Success',
- message: '',
- redirectUrl: null,
- redirectDelay: 2000
- },
-
- // Error Modal State
- errorModal: {
- show: false,
- title: 'Error',
- message: '',
- details: ''
- },
-
- // Loading State
- loading: false,
-
- /**
- * Show confirmation modal
- * @param {Object} options - Modal configuration
- */
- showConfirmModal(options) {
- this.confirmModal = {
- show: true,
- title: options.title || 'Confirm Action',
- message: options.message || 'Are you sure?',
- warning: options.warning || '',
- buttonText: options.buttonText || 'Confirm',
- buttonClass: options.buttonClass || 'btn-danger',
- onConfirm: options.onConfirm || null,
- onCancel: options.onCancel || null
- };
- },
-
- /**
- * Close confirmation modal
- */
- closeConfirmModal() {
- if (this.confirmModal.onCancel) {
- this.confirmModal.onCancel();
- }
- this.confirmModal.show = false;
- },
-
- /**
- * Handle confirmation action
- */
- async handleConfirm() {
- if (this.confirmModal.onConfirm) {
- this.closeConfirmModal();
- await this.confirmModal.onConfirm();
- }
- },
-
- /**
- * Show success modal
- * @param {Object} options - Modal configuration
- */
- showSuccessModal(options) {
- this.successModal = {
- show: true,
- title: options.title || 'Success',
- message: options.message || 'Operation completed successfully',
- redirectUrl: options.redirectUrl || null,
- redirectDelay: options.redirectDelay || 2000
- };
-
- // Auto-redirect if URL provided
- if (this.successModal.redirectUrl) {
- setTimeout(() => {
- window.location.href = this.successModal.redirectUrl;
- }, this.successModal.redirectDelay);
- }
- },
-
- /**
- * Close success modal
- */
- closeSuccessModal() {
- this.successModal.show = false;
- },
-
- /**
- * Show error modal
- * @param {Object} options - Modal configuration
- */
- showErrorModal(options) {
- this.errorModal = {
- show: true,
- title: options.title || 'Error',
- message: options.message || 'An error occurred',
- details: options.details || ''
- };
- },
-
- /**
- * Close error modal
- */
- closeErrorModal() {
- this.errorModal.show = false;
- },
-
- /**
- * Show loading overlay
- */
- showLoading() {
- this.loading = true;
- },
-
- /**
- * Hide loading overlay
- */
- hideLoading() {
- this.loading = false;
- }
- };
-};
-
-// =============================================================================
-// ADMIN LAYOUT COMPONENT
-// Header, Sidebar, Navigation, Modals for Admin Section
-// =============================================================================
-
-window.adminLayout = function() {
- return {
- ...window.baseModalSystem(),
-
- // Admin-specific state
- user: null,
- menuOpen: false,
- currentPage: '',
-
- /**
- * Initialize admin layout
- */
- async init() {
- this.currentPage = this.getCurrentPage();
- await this.loadUserData();
- },
-
- /**
- * Load current admin user data
- */
- async loadUserData() {
- try {
- const response = await apiClient.get('/admin/auth/me');
- this.user = response;
- } catch (error) {
- console.error('Failed to load user data:', error);
- // Redirect to login if not authenticated
- if (error.status === 401) {
- window.location.href = '/admin/login.html';
- }
- }
- },
-
- /**
- * Get current page name from URL
- */
- getCurrentPage() {
- const path = window.location.pathname;
- const page = path.split('/').pop().replace('.html', '');
- return page || 'dashboard';
- },
-
- /**
- * Check if menu item is active
- */
- isActive(page) {
- return this.currentPage === page;
- },
-
- /**
- * Toggle mobile menu
- */
- toggleMenu() {
- this.menuOpen = !this.menuOpen;
- },
-
- /**
- * Show logout confirmation
- */
- confirmLogout() {
- this.showConfirmModal({
- title: 'Confirm Logout',
- message: 'Are you sure you want to logout?',
- buttonText: 'Logout',
- buttonClass: 'btn-primary',
- onConfirm: () => this.logout()
- });
- },
-
- /**
- * Perform logout
- */
- async logout() {
- try {
- this.showLoading();
- await apiClient.post('/admin/auth/logout');
- window.location.href = '/admin/login.html';
- } catch (error) {
- this.hideLoading();
- this.showErrorModal({
- message: 'Logout failed',
- details: error.message
- });
- }
- }
- };
-};
-
-// =============================================================================
-// VENDOR LAYOUT COMPONENT
-// Header, Sidebar, Navigation, Modals for Vendor Dashboard
-// =============================================================================
-
-window.vendorLayout = function() {
- return {
- ...window.baseModalSystem(),
-
- // Vendor-specific state
- user: null,
- vendor: null,
- menuOpen: false,
- currentPage: '',
-
- /**
- * Initialize vendor layout
- */
- async init() {
- this.currentPage = this.getCurrentPage();
- await this.loadUserData();
- },
-
- /**
- * Load current vendor user data
- */
- async loadUserData() {
- try {
- const response = await apiClient.get('/vendor/auth/me');
- this.user = response.user;
- this.vendor = response.vendor;
- } catch (error) {
- console.error('Failed to load user data:', error);
- if (error.status === 401) {
- window.location.href = '/vendor/login.html';
- }
- }
- },
-
- /**
- * Get current page name from URL
- */
- getCurrentPage() {
- const path = window.location.pathname;
- const page = path.split('/').pop().replace('.html', '');
- return page || 'dashboard';
- },
-
- /**
- * Check if menu item is active
- */
- isActive(page) {
- return this.currentPage === page;
- },
-
- /**
- * Toggle mobile menu
- */
- toggleMenu() {
- this.menuOpen = !this.menuOpen;
- },
-
- /**
- * Show logout confirmation
- */
- confirmLogout() {
- this.showConfirmModal({
- title: 'Confirm Logout',
- message: 'Are you sure you want to logout?',
- buttonText: 'Logout',
- buttonClass: 'btn-primary',
- onConfirm: () => this.logout()
- });
- },
-
- /**
- * Perform logout
- */
- async logout() {
- try {
- this.showLoading();
- await apiClient.post('/vendor/auth/logout');
- window.location.href = '/vendor/login.html';
- } catch (error) {
- this.hideLoading();
- this.showErrorModal({
- message: 'Logout failed',
- details: error.message
- });
- }
- }
- };
-};
-
-// =============================================================================
-// SHOP LAYOUT COMPONENT
-// Header, Cart, Search, Navigation for Customer-Facing Shop
-// =============================================================================
-
-window.shopLayout = function() {
- return {
- ...window.baseModalSystem(),
-
- // Shop-specific state
- vendor: null,
- cart: null,
- cartCount: 0,
- sessionId: null,
- searchQuery: '',
- mobileMenuOpen: false,
-
- /**
- * Initialize shop layout
- */
- async init() {
- this.sessionId = this.getOrCreateSessionId();
- await this.detectVendor();
- if (this.vendor) {
- await this.loadCart();
- }
- },
-
- /**
- * Detect vendor from subdomain or vendor code
- */
- async detectVendor() {
- try {
- const hostname = window.location.hostname;
- const subdomain = hostname.split('.')[0];
-
- // Try to get vendor by subdomain first
- if (subdomain && subdomain !== 'localhost' && subdomain !== 'www') {
- this.vendor = await apiClient.get(`/public/vendors/by-subdomain/${subdomain}`);
- } else {
- // Fallback: Try to get vendor code from URL or localStorage
- const urlParams = new URLSearchParams(window.location.search);
- const vendorCode = urlParams.get('vendor') || localStorage.getItem('vendorCode');
-
- if (vendorCode) {
- this.vendor = await apiClient.get(`/public/vendors/by-code/${vendorCode}`);
- localStorage.setItem('vendorCode', vendorCode);
- }
- }
- } catch (error) {
- console.error('Failed to detect vendor:', error);
- this.showErrorModal({
- message: 'Vendor not found',
- details: 'Unable to identify the store. Please check the URL.'
- });
- }
- },
-
- /**
- * Get or create session ID for cart
- */
- getOrCreateSessionId() {
- let sessionId = localStorage.getItem('cartSessionId');
- if (!sessionId) {
- sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
- localStorage.setItem('cartSessionId', sessionId);
- }
- return sessionId;
- },
-
- /**
- * Load cart from API
- */
- async loadCart() {
- if (!this.vendor) return;
-
- try {
- this.cart = await apiClient.get(
- `/public/vendors/${this.vendor.id}/cart/${this.sessionId}`
- );
- this.updateCartCount();
- } catch (error) {
- console.error('Failed to load cart:', error);
- this.cart = { items: [] };
- this.cartCount = 0;
- }
- },
-
- /**
- * Update cart item count
- */
- updateCartCount() {
- if (this.cart && this.cart.items) {
- this.cartCount = this.cart.items.reduce((sum, item) => sum + item.quantity, 0);
- } else {
- this.cartCount = 0;
- }
- },
-
- /**
- * Add item to cart
- */
- async addToCart(productId, quantity = 1) {
- if (!this.vendor) {
- this.showErrorModal({ message: 'Vendor not found' });
- return;
- }
-
- try {
- this.showLoading();
- await apiClient.post(
- `/public/vendors/${this.vendor.id}/cart/${this.sessionId}/items`,
- { product_id: productId, quantity }
- );
- await this.loadCart();
- this.hideLoading();
- this.showSuccessModal({
- title: 'Added to Cart',
- message: 'Product added successfully'
- });
- } catch (error) {
- this.hideLoading();
- this.showErrorModal({
- message: 'Failed to add to cart',
- details: error.message
- });
- }
- },
-
- /**
- * Toggle mobile menu
- */
- toggleMobileMenu() {
- this.mobileMenuOpen = !this.mobileMenuOpen;
- },
-
- /**
- * Handle search
- */
- handleSearch() {
- if (this.searchQuery.trim()) {
- window.location.href = `/shop/products.html?search=${encodeURIComponent(this.searchQuery)}`;
- }
- },
-
- /**
- * Go to cart page
- */
- goToCart() {
- window.location.href = '/shop/cart.html';
- }
- };
-};
-
-// =============================================================================
-// SHOP ACCOUNT LAYOUT COMPONENT
-// Layout for customer account area (orders, profile, addresses)
-// =============================================================================
-
-window.shopAccountLayout = function() {
- return {
- ...window.shopLayout(),
-
- // Account-specific state
- customer: null,
- currentPage: '',
-
- /**
- * Initialize shop account layout
- */
- async init() {
- this.currentPage = this.getCurrentPage();
- this.sessionId = this.getOrCreateSessionId();
- await this.detectVendor();
- await this.loadCustomerData();
- if (this.vendor) {
- await this.loadCart();
- }
- },
-
- /**
- * Load customer data
- */
- async loadCustomerData() {
- if (!this.vendor) return;
-
- try {
- const response = await apiClient.get(
- `/public/vendors/${this.vendor.id}/customers/me`
- );
- this.customer = response;
- } catch (error) {
- console.error('Failed to load customer data:', error);
- // Redirect to login if not authenticated
- if (error.status === 401) {
- window.location.href = `/shop/account/login.html?redirect=${encodeURIComponent(window.location.pathname)}`;
- }
- }
- },
-
- /**
- * Get current page name from URL
- */
- getCurrentPage() {
- const path = window.location.pathname;
- const page = path.split('/').pop().replace('.html', '');
- return page || 'orders';
- },
-
- /**
- * Check if menu item is active
- */
- isActive(page) {
- return this.currentPage === page;
- },
-
- /**
- * Show logout confirmation
- */
- confirmLogout() {
- this.showConfirmModal({
- title: 'Confirm Logout',
- message: 'Are you sure you want to logout?',
- buttonText: 'Logout',
- buttonClass: 'btn-primary',
- onConfirm: () => this.logoutCustomer()
- });
- },
-
- /**
- * Perform customer logout
- */
- async logoutCustomer() {
- if (!this.vendor) return;
-
- try {
- this.showLoading();
- await apiClient.post(`/public/vendors/${this.vendor.id}/customers/logout`);
- window.location.href = '/shop/home.html';
- } catch (error) {
- this.hideLoading();
- this.showErrorModal({
- message: 'Logout failed',
- details: error.message
- });
- }
- }
- };
-};
\ No newline at end of file
diff --git a/static/js/shared/media-upload.js b/static/js/shared/media-upload.js
deleted file mode 100644
index cabbf399..00000000
--- a/static/js/shared/media-upload.js
+++ /dev/null
@@ -1 +0,0 @@
-// File upload utilities
diff --git a/static/js/shared/modal-system.js b/static/js/shared/modal-system.js
deleted file mode 100644
index 0ae3fbf6..00000000
--- a/static/js/shared/modal-system.js
+++ /dev/null
@@ -1,209 +0,0 @@
-/**
- * Modal System Helper Functions
- * Utility functions for modal operations across all sections
- */
-
-window.modalHelpers = {
- /**
- * Show a simple confirmation dialog
- * Returns a Promise that resolves with true/false
- */
- async confirm(options) {
- return new Promise((resolve) => {
- const component = Alpine.$data(document.body);
-
- component.showConfirmModal({
- title: options.title || 'Confirm Action',
- message: options.message || 'Are you sure?',
- warning: options.warning || '',
- buttonText: options.buttonText || 'Confirm',
- buttonClass: options.buttonClass || 'btn-danger',
- onConfirm: () => resolve(true),
- onCancel: () => resolve(false)
- });
- });
- },
-
- /**
- * Show a success message
- */
- success(message, options = {}) {
- const component = Alpine.$data(document.body);
-
- component.showSuccessModal({
- title: options.title || 'Success',
- message: message,
- redirectUrl: options.redirectUrl || null,
- redirectDelay: options.redirectDelay || 2000
- });
- },
-
- /**
- * Show an error message
- */
- error(message, details = '') {
- const component = Alpine.$data(document.body);
-
- component.showErrorModal({
- title: 'Error',
- message: message,
- details: details
- });
- },
-
- /**
- * Show API error with proper formatting
- */
- apiError(error) {
- const component = Alpine.$data(document.body);
-
- let message = 'An error occurred';
- let details = '';
-
- if (error.message) {
- message = error.message;
- }
-
- if (error.details) {
- details = typeof error.details === 'string'
- ? error.details
- : JSON.stringify(error.details, null, 2);
- } else if (error.error_code) {
- details = `Error Code: ${error.error_code}`;
- }
-
- component.showErrorModal({
- title: 'Error',
- message: message,
- details: details
- });
- },
-
- /**
- * Show loading overlay
- */
- showLoading() {
- const component = Alpine.$data(document.body);
- component.showLoading();
- },
-
- /**
- * Hide loading overlay
- */
- hideLoading() {
- const component = Alpine.$data(document.body);
- component.hideLoading();
- },
-
- /**
- * Execute an async operation with loading state
- */
- async withLoading(asyncFunction) {
- try {
- this.showLoading();
- const result = await asyncFunction();
- return result;
- } finally {
- this.hideLoading();
- }
- },
-
- /**
- * Execute an async operation with error handling
- */
- async withErrorHandling(asyncFunction, errorMessage = 'Operation failed') {
- try {
- return await asyncFunction();
- } catch (error) {
- console.error('Operation error:', error);
- this.apiError({
- message: errorMessage,
- details: error.message || error.toString()
- });
- throw error;
- }
- },
-
- /**
- * Execute an async operation with both loading and error handling
- */
- async execute(asyncFunction, options = {}) {
- const {
- errorMessage = 'Operation failed',
- successMessage = null,
- redirectUrl = null
- } = options;
-
- try {
- this.showLoading();
- const result = await asyncFunction();
-
- if (successMessage) {
- this.success(successMessage, { redirectUrl });
- }
-
- return result;
- } catch (error) {
- console.error('Operation error:', error);
- this.apiError({
- message: errorMessage,
- details: error.message || error.toString()
- });
- throw error;
- } finally {
- this.hideLoading();
- }
- },
-
- /**
- * Confirm a destructive action
- */
- async confirmDelete(itemName, itemType = 'item') {
- return this.confirm({
- title: `Delete ${itemType}`,
- message: `Are you sure you want to delete "${itemName}"?`,
- warning: 'This action cannot be undone.',
- buttonText: 'Delete',
- buttonClass: 'btn-danger'
- });
- },
-
- /**
- * Confirm logout
- */
- async confirmLogout() {
- return this.confirm({
- title: 'Confirm Logout',
- message: 'Are you sure you want to logout?',
- buttonText: 'Logout',
- buttonClass: 'btn-primary'
- });
- },
-
- /**
- * Show validation errors
- */
- validationError(errors) {
- let message = 'Please correct the following errors:';
- let details = '';
-
- if (Array.isArray(errors)) {
- details = errors.join('\n');
- } else if (typeof errors === 'object') {
- details = Object.entries(errors)
- .map(([field, error]) => `${field}: ${error}`)
- .join('\n');
- } else {
- details = errors.toString();
- }
-
- this.error(message, details);
- }
-};
-
-// Shorthand aliases for convenience
-window.showConfirm = window.modalHelpers.confirm.bind(window.modalHelpers);
-window.showSuccess = window.modalHelpers.success.bind(window.modalHelpers);
-window.showError = window.modalHelpers.error.bind(window.modalHelpers);
-window.showLoading = window.modalHelpers.showLoading.bind(window.modalHelpers);
-window.hideLoading = window.modalHelpers.hideLoading.bind(window.modalHelpers);
\ No newline at end of file
diff --git a/static/js/shared/modal-templates.js b/static/js/shared/modal-templates.js
deleted file mode 100644
index 355a8eeb..00000000
--- a/static/js/shared/modal-templates.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Universal Modal Templates
- * Shared across all sections: Admin, Vendor, and Shop
- */
-
-window.modalTemplates = {
-
- /**
- * Confirmation Modal
- */
- confirmModal: () => `
-
- `,
-
- /**
- * Success Modal
- */
- successModal: () => `
-
- `,
-
- /**
- * Error Modal
- */
- errorModal: () => `
-
- `,
-
- /**
- * Loading Overlay
- */
- loadingOverlay: () => `
-
- `
-};
\ No newline at end of file
diff --git a/static/js/shared/notification.js b/static/js/shared/notification.js
deleted file mode 100644
index 787cf2d7..00000000
--- a/static/js/shared/notification.js
+++ /dev/null
@@ -1 +0,0 @@
-// Notification handling
diff --git a/static/js/shared/search.js b/static/js/shared/search.js
deleted file mode 100644
index adc32660..00000000
--- a/static/js/shared/search.js
+++ /dev/null
@@ -1 +0,0 @@
-// Search functionality
diff --git a/static/js/shared/vendor-context.js b/static/js/shared/vendor-context.js
deleted file mode 100644
index 28e82f06..00000000
--- a/static/js/shared/vendor-context.js
+++ /dev/null
@@ -1 +0,0 @@
-// Vendor context detection and management
diff --git a/static/js/shop/account.js b/static/js/shop/account.js
deleted file mode 100644
index c573b782..00000000
--- a/static/js/shop/account.js
+++ /dev/null
@@ -1 +0,0 @@
-// Customer account
diff --git a/static/js/shop/cart.js b/static/js/shop/cart.js
deleted file mode 100644
index 9ab57ccb..00000000
--- a/static/js/shop/cart.js
+++ /dev/null
@@ -1 +0,0 @@
-// Shopping cart
diff --git a/static/js/shop/catalog.js b/static/js/shop/catalog.js
deleted file mode 100644
index b0d701ed..00000000
--- a/static/js/shop/catalog.js
+++ /dev/null
@@ -1 +0,0 @@
-// Product browsing
diff --git a/static/js/shop/checkout.js b/static/js/shop/checkout.js
deleted file mode 100644
index dfe60dd2..00000000
--- a/static/js/shop/checkout.js
+++ /dev/null
@@ -1 +0,0 @@
-// Checkout process
diff --git a/static/js/shop/search.js b/static/js/shop/search.js
deleted file mode 100644
index 7ec3d1e3..00000000
--- a/static/js/shop/search.js
+++ /dev/null
@@ -1 +0,0 @@
-// Product search
diff --git a/static/js/shop/shop-layout-templates.js b/static/js/shop/shop-layout-templates.js
deleted file mode 100644
index 680ff658..00000000
--- a/static/js/shop/shop-layout-templates.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * Shop Layout Templates
- * Header and Navigation specific to Customer-Facing Shop
- */
-
-window.shopLayoutTemplates = {
-
- /**
- * Shop Header
- */
- header: () => `
-
- `,
-
- /**
- * Shop Account Sidebar
- */
- accountSidebar: () => `
-
- `
-};
\ No newline at end of file
diff --git a/static/js/vendor/dashboard.js b/static/js/vendor/dashboard.js
deleted file mode 100644
index f93705b4..00000000
--- a/static/js/vendor/dashboard.js
+++ /dev/null
@@ -1,113 +0,0 @@
-// Vendor Dashboard Component
-function vendorDashboard() {
- return {
- currentUser: {},
- vendor: null,
- vendorRole: '',
- currentSection: 'dashboard',
- loading: false,
- stats: {
- products_count: 0,
- orders_count: 0,
- customers_count: 0,
- revenue: 0
- },
-
- init() {
- if (!this.checkAuth()) {
- return;
- }
- this.loadDashboard();
- },
-
- checkAuth() {
- const token = localStorage.getItem('vendor_token');
- const user = localStorage.getItem('vendor_user');
- const vendorContext = localStorage.getItem('vendor_context');
- const vendorRole = localStorage.getItem('vendor_role');
-
- if (!token || !user || !vendorContext) {
- // Get vendor code from URL
- const vendorCode = this.getVendorCodeFromUrl();
- const redirectUrl = vendorCode ?
- `/vendor/${vendorCode}/login` :
- '/static/vendor/login.html';
- window.location.href = redirectUrl;
- return false;
- }
-
- try {
- this.currentUser = JSON.parse(user);
- this.vendor = JSON.parse(vendorContext);
- this.vendorRole = vendorRole || 'Member';
- return true;
- } catch (e) {
- console.error('Error parsing stored data:', e);
- localStorage.removeItem('vendor_token');
- localStorage.removeItem('vendor_user');
- localStorage.removeItem('vendor_context');
- localStorage.removeItem('vendor_role');
- window.location.href = '/static/vendor/login.html';
- return false;
- }
- },
-
- getVendorCodeFromUrl() {
- // Try to get vendor code from URL path
- const pathParts = window.location.pathname.split('/').filter(p => p);
- const vendorIndex = pathParts.indexOf('vendor');
- if (vendorIndex !== -1 && pathParts[vendorIndex + 1]) {
- const code = pathParts[vendorIndex + 1];
- if (!['login', 'dashboard', 'admin', 'products', 'orders'].includes(code.toLowerCase())) {
- return code.toUpperCase();
- }
- }
-
- // Fallback to query parameter
- const urlParams = new URLSearchParams(window.location.search);
- return urlParams.get('vendor');
- },
-
- async handleLogout() {
- const confirmed = await Utils.confirm(
- 'Are you sure you want to logout?',
- 'Confirm Logout'
- );
-
- if (confirmed) {
- localStorage.removeItem('vendor_token');
- localStorage.removeItem('vendor_user');
- localStorage.removeItem('vendor_context');
- localStorage.removeItem('vendor_role');
-
- Utils.showToast('Logged out successfully', 'success', 2000);
-
- setTimeout(() => {
- window.location.href = `/vendor/${this.vendor.vendor_code}/login`;
- }, 500);
- }
- },
-
- async loadDashboard() {
- this.loading = true;
- try {
- // In future slices, load actual dashboard data
- // const data = await apiClient.get(`/vendor/dashboard/stats`);
- // this.stats = data;
-
- // For now, show placeholder data
- this.stats = {
- products_count: 0,
- orders_count: 0,
- customers_count: 0,
- revenue: 0
- };
- } catch (error) {
- console.error('Failed to load dashboard:', error);
- Utils.showToast('Failed to load dashboard data', 'error');
- } finally {
- this.loading = false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/static/js/vendor/login.js b/static/js/vendor/login.js
deleted file mode 100644
index edf64183..00000000
--- a/static/js/vendor/login.js
+++ /dev/null
@@ -1,170 +0,0 @@
-// Vendor Login Component
-function vendorLogin() {
- return {
- vendor: null,
- credentials: {
- username: '',
- password: ''
- },
- loading: false,
- checked: false,
- error: null,
- success: null,
- errors: {},
-
- init() {
- // Check if already logged in
- if (this.checkExistingAuth()) {
- return;
- }
-
- // Detect vendor from URL
- this.detectVendor();
- },
-
- checkExistingAuth() {
- const token = localStorage.getItem('vendor_token');
- const vendorContext = localStorage.getItem('vendor_context');
-
- if (token && vendorContext) {
- try {
- const vendor = JSON.parse(vendorContext);
- window.location.href = `/vendor/${vendor.vendor_code}/dashboard`;
- return true;
- } catch (e) {
- localStorage.removeItem('vendor_token');
- localStorage.removeItem('vendor_context');
- }
- }
- return false;
- },
-
- async detectVendor() {
- this.loading = true;
-
- try {
- const vendorCode = this.getVendorCodeFromUrl();
-
- if (!vendorCode) {
- this.error = 'Vendor code not found in URL. Please use the correct vendor login link.';
- this.checked = true;
- this.loading = false;
- return;
- }
-
- console.log('Detected vendor code:', vendorCode);
-
- // Fetch vendor information
- const response = await fetch(`/api/v1/public/vendors/by-code/${vendorCode}`);
-
- if (!response.ok) {
- throw new Error('Vendor not found');
- }
-
- this.vendor = await response.json();
- this.checked = true;
- console.log('Loaded vendor:', this.vendor);
-
- } catch (error) {
- console.error('Error detecting vendor:', error);
- this.error = 'Unable to load vendor information. The vendor may not exist or is inactive.';
- this.checked = true;
- } finally {
- this.loading = false;
- }
- },
-
- getVendorCodeFromUrl() {
- // Try multiple methods to get vendor code
-
- // Method 1: From URL path /vendor/VENDORCODE/login or /vendor/VENDORCODE/
- const pathParts = window.location.pathname.split('/').filter(p => p);
- const vendorIndex = pathParts.indexOf('vendor');
- if (vendorIndex !== -1 && pathParts[vendorIndex + 1]) {
- const code = pathParts[vendorIndex + 1];
- // Don't return if it's a generic route like 'login', 'dashboard', etc.
- if (!['login', 'dashboard', 'admin', 'products', 'orders'].includes(code.toLowerCase())) {
- return code.toUpperCase();
- }
- }
-
- // Method 2: From query parameter ?vendor=VENDORCODE
- const urlParams = new URLSearchParams(window.location.search);
- const queryVendor = urlParams.get('vendor');
- if (queryVendor) {
- return queryVendor.toUpperCase();
- }
-
- // Method 3: From subdomain (for production)
- const hostname = window.location.hostname;
- const parts = hostname.split('.');
- if (parts.length > 2 && parts[0] !== 'www') {
- // Assume subdomain is vendor code
- return parts[0].toUpperCase();
- }
-
- return null;
- },
-
- clearErrors() {
- this.error = null;
- this.errors = {};
- },
-
- validateForm() {
- this.clearErrors();
- let isValid = true;
-
- if (!this.credentials.username.trim()) {
- this.errors.username = 'Username is required';
- isValid = false;
- }
-
- if (!this.credentials.password) {
- this.errors.password = 'Password is required';
- isValid = false;
- }
-
- return isValid;
- },
-
- async handleLogin() {
- if (!this.validateForm()) {
- return;
- }
-
- this.loading = true;
- this.clearErrors();
-
- try {
- const response = await apiClient.post('/vendor/auth/login', {
- username: this.credentials.username.trim(),
- password: this.credentials.password,
- vendor_code: this.vendor.vendor_code
- });
-
- // Store authentication data
- localStorage.setItem('vendor_token', response.access_token);
- localStorage.setItem('vendor_user', JSON.stringify(response.user));
- localStorage.setItem('vendor_context', JSON.stringify(response.vendor));
- localStorage.setItem('vendor_role', response.vendor_role);
-
- // Show success message
- this.success = 'Login successful! Redirecting...';
- Utils.showToast('Login successful!', 'success', 2000);
-
- // Redirect after short delay
- setTimeout(() => {
- window.location.href = `/vendor/${this.vendor.vendor_code}/dashboard`;
- }, 1000);
-
- } catch (error) {
- console.error('Login error:', error);
- this.error = error.message || 'Login failed. Please check your credentials.';
- Utils.showToast(this.error, 'error');
- } finally {
- this.loading = false;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/static/js/vendor/marketplace.js b/static/js/vendor/marketplace.js
deleted file mode 100644
index 9b6ade64..00000000
--- a/static/js/vendor/marketplace.js
+++ /dev/null
@@ -1 +0,0 @@
-// Marketplace integration
diff --git a/static/js/vendor/media.js b/static/js/vendor/media.js
deleted file mode 100644
index 853f78a3..00000000
--- a/static/js/vendor/media.js
+++ /dev/null
@@ -1 +0,0 @@
-// Media management
diff --git a/static/js/vendor/orders.js b/static/js/vendor/orders.js
deleted file mode 100644
index 917f7f8a..00000000
--- a/static/js/vendor/orders.js
+++ /dev/null
@@ -1 +0,0 @@
-// Order management
diff --git a/static/js/vendor/payments.js b/static/js/vendor/payments.js
deleted file mode 100644
index 4c9efd9a..00000000
--- a/static/js/vendor/payments.js
+++ /dev/null
@@ -1 +0,0 @@
-// Payment configuration
diff --git a/static/js/vendor/products.js b/static/js/vendor/products.js
deleted file mode 100644
index c3f4a0b4..00000000
--- a/static/js/vendor/products.js
+++ /dev/null
@@ -1 +0,0 @@
-// Catalog management
diff --git a/static/js/vendor/vendor-layout-templates.js b/static/js/vendor/vendor-layout-templates.js
deleted file mode 100644
index 162c4d6e..00000000
--- a/static/js/vendor/vendor-layout-templates.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Vendor Layout Templates
- * Header and Sidebar specific to Vendor Dashboard
- */
-
-window.vendorLayoutTemplates = {
-
- /**
- * Vendor Header
- */
- header: () => `
-
- `,
-
- /**
- * Vendor Sidebar
- */
- sidebar: () => `
-
- `
-};
\ No newline at end of file
diff --git a/static/shared/js/icons.js b/static/shared/js/icons.js
index c8455bd6..402b8a5d 100644
--- a/static/shared/js/icons.js
+++ b/static/shared/js/icons.js
@@ -107,7 +107,13 @@ const Icons = {
'database': ``,
'light-bulb': ``,
'book-open': ``,
- 'play': ``
+ 'play': ``,
+
+ // Additional UI Icons
+ 'table': ``,
+ 'cursor-click': ``,
+ 'view-grid-add': ``,
+ 'code': ``
};
/**
diff --git a/static/shop/account/addresses.html b/static/shop/account/addresses.html
deleted file mode 100644
index 0ca25b1b..00000000
--- a/static/shop/account/addresses.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Address management
-
-
- <-- Address management -->
-
-
diff --git a/static/shop/account/login.html b/static/shop/account/login.html
deleted file mode 100644
index 150e8934..00000000
--- a/static/shop/account/login.html
+++ /dev/null
@@ -1,249 +0,0 @@
-
-
-
-
-
-
-
-
-
- Login - {{ vendor.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/shop/account/orders.html b/static/shop/account/orders.html
deleted file mode 100644
index 909a3bf9..00000000
--- a/static/shop/account/orders.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Order history
-
-
- <-- Order history -->
-
-
diff --git a/static/shop/account/profile.html b/static/shop/account/profile.html
deleted file mode 100644
index 96b6d750..00000000
--- a/static/shop/account/profile.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Customer profile
-
-
- <-- Customer profile -->
-
-
diff --git a/static/shop/account/register.html b/static/shop/account/register.html
deleted file mode 100644
index 56ff2d05..00000000
--- a/static/shop/account/register.html
+++ /dev/null
@@ -1,341 +0,0 @@
-
-
-
-
-
- Create Account - {{ vendor.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/static/shop/cart.html b/static/shop/cart.html
deleted file mode 100644
index cc14648a..00000000
--- a/static/shop/cart.html
+++ /dev/null
@@ -1,489 +0,0 @@
-
-
-
-
-
- Shopping Cart - {{ vendor.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Loading your cart...
-
-
-
-
-
🛒
-
Your cart is empty
-
Add some products to get started!
-
Browse Products
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Order Summary
-
-
- Subtotal ( items):
- €
-
-
-
- Shipping:
-
-
-
-
- Total:
- €
-
-
-
-
-
- Continue Shopping
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/shop/checkout.html b/static/shop/checkout.html
deleted file mode 100644
index 3270d419..00000000
--- a/static/shop/checkout.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Checkout process
-
-
- <-- Checkout process -->
-
-
diff --git a/static/shop/home.html b/static/shop/home.html
deleted file mode 100644
index 8e463635..00000000
--- a/static/shop/home.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Shop homepage
-
-
- <-- Shop homepage -->
-
-
diff --git a/static/shop/js/shop-layout.js b/static/shop/js/shop-layout.js
new file mode 100644
index 00000000..a16b5194
--- /dev/null
+++ b/static/shop/js/shop-layout.js
@@ -0,0 +1,228 @@
+// static/shop/js/shop-layout.js
+/**
+ * Shop Layout Component
+ * Provides base functionality for vendor shop pages
+ * Works with vendor-specific themes
+ */
+
+const shopLog = {
+ info: (...args) => console.info('🛒 [SHOP]', ...args),
+ warn: (...args) => console.warn('⚠️ [SHOP]', ...args),
+ error: (...args) => console.error('❌ [SHOP]', ...args),
+ debug: (...args) => console.log('🔍 [SHOP]', ...args)
+};
+
+/**
+ * Shop Layout Data
+ * Base Alpine.js component for shop pages
+ */
+function shopLayoutData() {
+ return {
+ // Theme state
+ dark: localStorage.getItem('shop-theme') === 'dark',
+
+ // UI state
+ mobileMenuOpen: false,
+ searchOpen: false,
+ cartCount: 0,
+
+ // Cart state
+ cart: [],
+
+ // Initialize
+ init() {
+ shopLog.info('Shop layout initializing...');
+
+ // Load cart from localStorage
+ this.loadCart();
+
+ // Listen for cart updates
+ window.addEventListener('cart-updated', () => {
+ this.loadCart();
+ });
+
+ shopLog.info('Shop layout initialized');
+ },
+
+ // Theme management
+ toggleTheme() {
+ this.dark = !this.dark;
+ localStorage.setItem('shop-theme', this.dark ? 'dark' : 'light');
+ shopLog.debug('Theme toggled:', this.dark ? 'dark' : 'light');
+ },
+
+ // Mobile menu
+ toggleMobileMenu() {
+ this.mobileMenuOpen = !this.mobileMenuOpen;
+ if (this.mobileMenuOpen) {
+ document.body.style.overflow = 'hidden';
+ } else {
+ document.body.style.overflow = '';
+ }
+ },
+
+ closeMobileMenu() {
+ this.mobileMenuOpen = false;
+ document.body.style.overflow = '';
+ },
+
+ // Search
+ openSearch() {
+ this.searchOpen = true;
+ shopLog.debug('Search opened');
+ // Focus search input after a short delay
+ setTimeout(() => {
+ const input = document.querySelector('#search-input');
+ if (input) input.focus();
+ }, 100);
+ },
+
+ closeSearch() {
+ this.searchOpen = false;
+ },
+
+ // Cart management
+ loadCart() {
+ try {
+ const cartData = localStorage.getItem('shop-cart');
+ if (cartData) {
+ this.cart = JSON.parse(cartData);
+ this.cartCount = this.cart.reduce((sum, item) => sum + item.quantity, 0);
+ }
+ } catch (error) {
+ shopLog.error('Failed to load cart:', error);
+ this.cart = [];
+ this.cartCount = 0;
+ }
+ },
+
+ addToCart(product, quantity = 1) {
+ shopLog.info('Adding to cart:', product.name, 'x', quantity);
+
+ // Find existing item
+ const existingIndex = this.cart.findIndex(item => item.id === product.id);
+
+ if (existingIndex !== -1) {
+ // Update quantity
+ this.cart[existingIndex].quantity += quantity;
+ } else {
+ // Add new item
+ this.cart.push({
+ id: product.id,
+ name: product.name,
+ price: product.price,
+ image: product.image,
+ quantity: quantity
+ });
+ }
+
+ // Save and update
+ this.saveCart();
+ this.showToast(`${product.name} added to cart`, 'success');
+ },
+
+ updateCartItem(productId, quantity) {
+ const index = this.cart.findIndex(item => item.id === productId);
+ if (index !== -1) {
+ if (quantity <= 0) {
+ this.cart.splice(index, 1);
+ } else {
+ this.cart[index].quantity = quantity;
+ }
+ this.saveCart();
+ }
+ },
+
+ removeFromCart(productId) {
+ this.cart = this.cart.filter(item => item.id !== productId);
+ this.saveCart();
+ this.showToast('Item removed from cart', 'info');
+ },
+
+ clearCart() {
+ this.cart = [];
+ this.saveCart();
+ this.showToast('Cart cleared', 'info');
+ },
+
+ saveCart() {
+ try {
+ localStorage.setItem('shop-cart', JSON.stringify(this.cart));
+ this.cartCount = this.cart.reduce((sum, item) => sum + item.quantity, 0);
+
+ // Dispatch custom event
+ window.dispatchEvent(new CustomEvent('cart-updated'));
+
+ shopLog.debug('Cart saved:', this.cart.length, 'items');
+ } catch (error) {
+ shopLog.error('Failed to save cart:', error);
+ }
+ },
+
+ // Get cart total
+ get cartTotal() {
+ return this.cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
+ },
+
+ // Toast notifications
+ showToast(message, type = 'info') {
+ const container = document.getElementById('toast-container');
+ if (!container) return;
+
+ const toast = document.createElement('div');
+ toast.className = `toast toast-${type} transform transition-all duration-300 mb-2`;
+
+ // Color based on type
+ const colors = {
+ success: 'bg-green-500',
+ error: 'bg-red-500',
+ warning: 'bg-yellow-500',
+ info: 'bg-blue-500'
+ };
+
+ toast.innerHTML = `
+
+ `;
+
+ container.appendChild(toast);
+
+ // Auto-remove after 3 seconds
+ setTimeout(() => {
+ toast.style.opacity = '0';
+ setTimeout(() => toast.remove(), 300);
+ }, 3000);
+ },
+
+ // Format currency
+ formatPrice(price) {
+ return new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ }).format(price);
+ },
+
+ // Format date
+ formatDate(dateString) {
+ if (!dateString) return '-';
+ const date = new Date(dateString);
+ return date.toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+ });
+ }
+ };
+}
+
+// Make available globally
+window.shopLayoutData = shopLayoutData;
+
+shopLog.info('Shop layout module loaded');
\ No newline at end of file
diff --git a/static/shop/product.html b/static/shop/product.html
deleted file mode 100644
index 77e5e639..00000000
--- a/static/shop/product.html
+++ /dev/null
@@ -1,771 +0,0 @@
-
-
-
-
-
- {{ product.name if product else 'Product' }} - {{ vendor.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Brand:
-
-
- Category:
-
-
- SKU:
-
-
-
-
-
-
- €
- €
- SALE
-
-
- €
-
-
-
-
-
-
- ✓ In Stock ( available)
-
-
- ✗ Out of Stock
-
-
-
-
-
-
-
-
-
Product Details
-
- -
- GTIN:
-
- -
- Condition:
-
- -
- Color:
-
- -
- Size:
-
- -
- Material:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Total: €
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/shop/products.html b/static/shop/products.html
deleted file mode 100644
index 99a44701..00000000
--- a/static/shop/products.html
+++ /dev/null
@@ -1,459 +0,0 @@
-
-
-
-
-
- Products - {{ vendor.name }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 🔍
-
-
-
-
-
-
-
-
-
-
-
-
-
Loading products...
-
-
-
-
-
📦
-
No products found
-
Try adjusting your filters
-
Check back soon for new products!
-
-
-
-
-
-
-
-
-
![]()
-
- Out of Stock
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/static/shop/search.html b/static/shop/search.html
deleted file mode 100644
index 3dfc5efa..00000000
--- a/static/shop/search.html
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- Search results page
-
-
- <-- Search results page -->
-
-