diff --git a/CLAUDE.md b/CLAUDE.md index 9b33ae5..b8b1cb2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -93,31 +93,29 @@ When making changes to database models, always create Alembic migrations: # Activate environment first source env/bin/activate -# Create a new migration +# Create a new migration (manual) alembic -c data/development.ini revision -m "description of change" -# Edit the generated migration file in make_post_sell/scripts/alembic/versions/ -# Add your upgrade() and downgrade() logic +# OR: Create autogenerated migration (compares DB with models) +alembic -c data/development.ini revision --autogenerate -m "description of change" -# Apply the migration -alembic -c data/development.ini upgrade head +# Edit the generated migration file in make_post_sell/scripts/alembic/versions/ ``` -### Migration Commands +### Running Migrations ```bash -# Check current database revision +# Apply all pending migrations +alembic -c data/development.ini upgrade head + +# Check current migration status alembic -c data/development.ini current # View migration history alembic -c data/development.ini history - -# Upgrade to latest -alembic -c data/development.ini upgrade head - -# Auto-generate migration from model changes (review before applying!) -alembic -c data/development.ini revision --autogenerate -m "auto-generated changes" ``` +**IMPORTANT**: Always backup the database before running migrations! + ### Important Migration Notes **SQLite Column Defaults**: When adding NOT NULL columns with defaults to existing tables in SQLite, use `server_default` with raw SQL values: diff --git a/THEME_AUDIT.md b/THEME_AUDIT.md new file mode 100644 index 0000000..b0d8ce7 --- /dev/null +++ b/THEME_AUDIT.md @@ -0,0 +1,329 @@ +# CSS Theme Audit Report + +## Executive Summary + +This audit documents all DOM elements, CSS classes, and inline styles across the Make Post Sell application templates to prepare for theme implementation. The application uses a mobile-first CSS Grid layout with semantic class naming. + +## CSS Architecture Overview + +- **Layout System**: CSS Grid (exclusively, no Flexbox) +- **Mobile-First**: Responsive design starting from mobile +- **Main CSS File**: `make_post_sell/static/css/common.css` (1,072 lines) +- **Template Engine**: Jinja2 (.j2 files) +- **Total Templates**: 42 templates across 48 files + +## 1. INLINE STYLES AUDIT + +### High Priority - Need CSS Classes + +**shop_settings.j2** (16 instances) +- `style="color: #666;"` - Status messages (lines 176, 271, 314, 329, 392) +- `style="color: green;"` - Success indicators (lines 308, 366) +- `style="color: #d44;"` - Error indicators (lines 312, 370) +- `style="display: inline;"` - Inline labels (lines 136, 266) +- `style="width: 32px;"` - Favicon preview (line 434) + +**crypto_checkout.j2** (25 instances) +- Complex grid layouts: `style="display: grid; grid-template-columns: auto 1fr; gap: 20px;"` (line 23) +- Button layouts: `style="display: grid; grid-template-columns: 1fr 1fr 1fr;"` (line 38) +- Status boxes: `style="background: #f8f9fa; border: 1px solid #dee2e6;"` (line 48) +- Warning/info boxes: `style="background: #d1fae5; border: 1px solid #10b981;"` (line 539) + +**cart_checkout.j2** (18 instances) +- Payment method buttons with crypto icons +- Status indicators and warning boxes +- Grid layouts for pending payment display + +**cart.j2** (16 instances) +- Float layouts: `style="float: right;"` (line 34) +- Form styling: `style="display: inline;"` (lines 113, 121) +- Shop names: `style="font-size: 1.5em;"` (line 90) + +### Medium Priority + +**snippets/comments.j2** (6 instances) +- Comment indentation: `style="margin-left: {{ comment.depth * 20 }}px;"` +- Form hiding: `style="display: none;"` + +**product.j2**, **content.j2** (2 instances each) +- Subtitle styling: `style="font-size: 0.6em; font-weight: normal;"` + +**Other templates** (30+ instances across remaining files) +- Various display, color, and layout inline styles + +## 2. CSS CLASSES ANALYSIS + +### Well-Designed Semantic Classes (Keep) + +**Layout Classes** +- `.one-column` (24 uses) - Single column layout, max-width 600px +- `.two-column` (4 uses) - Two column responsive layout +- `.one-column-thin` (1 use) - Narrower single column, max-width 400px +- `.well`, `.well2` (9 uses) - Content containers with background + +**Component Classes** +- `.mps-button` family - Comprehensive button system +- `.serp` family - Search results display +- `.cart-*` family - Cart-specific components +- `.product-*` family - Product display components +- `.comment-*` family - Comment system components + +**State Classes** +- `.hidden-control` - Toggle visibility +- `.opacity-60` - Transparency +- `.discounted` - Price styling +- `.highlight` - Text highlighting + +### Button System Analysis + +**Primary Buttons** (semantic and consistent) +```css +.mps-button - Base button class +.mps-button-blue - #98b6fa (info/secondary) +.mps-button-green - #a3c765 (success/primary) +.mps-button-red - #bc2131 (danger) +.mps-button-small - Smaller variant for desktop +``` + +**Specialized Buttons** (good semantic naming) +```css +.cart-checkout-button +.cart-save-button +.cart-activate-button +.cart-delete-button +.product-download-button +.product-edit-button +.shop-new-button +.payment-toggle-button +``` + +### Areas Needing Attention + +**Inconsistent Classes** +- Multiple button size combinations (`.mps-button-small mps-button-green`) +- Mixed semantic levels (`.product-edit-button mps-button mps-button-small`) + +**Missing Classes** (have inline styles instead) +- Status indicators (success, warning, error) +- Crypto payment layouts +- Form spacing +- Icon sizing + +## 3. COLOR PALETTE ANALYSIS + +### Current Theme Colors +```css +/* Primary Brand Colors */ +#5871ad - Primary blue (navbar, buttons) +#82A8FF - Gradient end +#98b6fa - Secondary blue (info buttons) + +/* Action Colors */ +#a3c765 - Success green (primary actions) +#bc2131 - Danger red (destructive actions) +#CC6958 - Delete red (cart delete) + +/* Status Colors */ +#28a745 - Success green (confirmations) +#ffc107 - Warning yellow +#dc3545 - Error red +#6c757d - Muted gray + +/* Background Colors */ +#F9F9FA - Light gray (navbar, wells) +#f2f2f2 - Even table rows +#ffffff - Odd table rows, content background + +/* Text Colors */ +#5f6368 - Link color +#666666 - Muted text +#721c24 - Error text +#856404 - Warning text +#0c5460 - Info text +#155724 - Success text +``` + +## 4. LAYOUT SYSTEM ANALYSIS + +### CSS Grid Implementation +- Mobile-first responsive design +- Breakpoints: 800px (tablet), 960px (desktop), 1200px (large) +- Grid areas for complex layouts (product pages) +- Auto-fit columns for responsive grids + +### Layout Classes Usage +``` +one-column: 24 instances - Most common layout +shop-settings well: 9 instances - Settings pages +two-column: 4 instances - Product/content pages +well: 7 instances - Content containers +``` + +## 5. THEME TARGETS FOR IMPLEMENTATION + +### Essential CSS Variables Needed + +```css +:root { + /* Brand Colors */ + --color-primary: #5871ad; + --color-primary-light: #82A8FF; + --color-secondary: #98b6fa; + + /* Action Colors */ + --color-success: #a3c765; + --color-danger: #bc2131; + --color-warning: #ffc107; + --color-info: #0c5460; + + /* Status Colors */ + --color-status-success: #28a745; + --color-status-error: #dc3545; + --color-status-warning: #856404; + --color-status-muted: #6c757d; + + /* Background Colors */ + --bg-navbar: #F9F9FA; + --bg-content: #ffffff; + --bg-well: #F9F9FA; + --bg-table-even: #f2f2f2; + + /* Text Colors */ + --text-link: #5f6368; + --text-muted: #666666; + --text-body: #333333; + + /* Spacing */ + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 14px; + --spacing-lg: 20px; + --spacing-xl: 40px; +} +``` + +### New Classes Needed (Replace Inline Styles) + +```css +/* Status Indicators */ +.status-success { color: var(--color-status-success); } +.status-error { color: var(--color-status-error); } +.status-warning { color: var(--color-status-warning); } +.status-muted { color: var(--color-status-muted); } + +/* Crypto Payment Layouts */ +.crypto-payment-grid { + display: grid; + grid-template-columns: auto 1fr; + gap: 20px; + margin: 16px 0; + align-items: start; +} + +.crypto-button-grid { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 8px; + margin: 8px 0; +} + +/* Info Boxes */ +.info-box { + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 4px; + padding: 15px; + margin: 10px 0; +} + +.success-box { + background: #d1fae5; + border: 1px solid #10b981; + border-radius: 4px; + padding: 15px; + margin: 20px 0; +} + +.warning-box { + background: #fef3c7; + border: 1px solid #f59e0b; + border-radius: 4px; + padding: 15px; + margin: 20px 0; +} + +/* Form Elements */ +.inline-label { display: inline; } +.form-row { margin-bottom: var(--spacing-md); } + +/* Icon Sizes */ +.icon-sm { width: 32px; height: 32px; } +.icon-md { width: 48px; height: 48px; } +.icon-lg { width: 150px; height: 150px; } + +/* Typography */ +.text-large { font-size: 1.5em; } +.text-small { font-size: 0.6em; font-weight: normal; } +.text-monospace { font-family: monospace; } + +/* Layout Utilities */ +.float-right { float: right; } +.text-right { text-align: right; } +.margin-top-none { margin-top: 0; } +.margin-bottom-none { margin-bottom: 0; } +``` + +## 6. RECOMMENDATIONS + +### High Priority +1. **Replace all inline styles** with semantic CSS classes +2. **Implement CSS custom properties** for theme colors +3. **Create component-specific classes** for crypto payments, status indicators +4. **Establish consistent spacing system** using CSS variables + +### Medium Priority +1. **Consolidate button variants** to reduce complexity +2. **Create utility classes** for common patterns (float, text-align, etc.) +3. **Implement theme switching mechanism** using CSS custom properties +4. **Add dark mode support** with color scheme media queries + +### Low Priority +1. **Optimize CSS delivery** by splitting into component files +2. **Add CSS Grid fallbacks** for older browsers if needed +3. **Implement print styles** for invoices and receipts + +## 7. THEME IMPLEMENTATION STRATEGY + +### Phase 1: Foundation +- Convert all inline styles to CSS classes +- Implement CSS custom properties system +- Create component-specific classes + +### Phase 2: Theming +- Build theme switching system +- Create default light/dark themes +- Add theme preview functionality + +### Phase 3: Customization +- Allow color customization per shop +- Implement theme marketplace/sharing +- Add advanced theming options + +## Files Modified in This Audit +- `make_post_sell/static/css/common.css` (analyzed) +- All 48 template files in `make_post_sell/templates/` (analyzed) + +## Theme Target Summary + +The application is well-structured for theming with: +- ✅ Semantic CSS class naming +- ✅ CSS Grid layout system +- ✅ Mobile-first responsive design +- ✅ Consistent button system +- ❌ Too many inline styles (83 instances) +- ❌ Missing CSS custom properties +- ❌ No theme switching mechanism + +**Total Elements Requiring Attention**: 83 inline styles across 21 template files +**Estimated Effort**: Medium (2-3 weeks for complete theme system) +**Theme Readiness**: 65% (needs cleanup before theming) \ No newline at end of file diff --git a/make_post_sell/models/shop.py b/make_post_sell/models/shop.py index 5c4b060..b3ae57f 100644 --- a/make_post_sell/models/shop.py +++ b/make_post_sell/models/shop.py @@ -103,6 +103,9 @@ class Shop(RBase, Base): BigInteger, nullable=False, default=3600 ) # Default 60 minutes + # Default theme for shop visitors (0=dark, 1=light) + default_theme = Column(BigInteger, nullable=False, default=1) # Default light mode + # many to many uses association_proxy. users = association_proxy("shop_users", "user", creator=lambda u: UserShop(user=u)) diff --git a/make_post_sell/scripts/alembic/versions/b090f873502e_add_default_theme_to_shop.py b/make_post_sell/scripts/alembic/versions/b090f873502e_add_default_theme_to_shop.py new file mode 100644 index 0000000..7dc3daa --- /dev/null +++ b/make_post_sell/scripts/alembic/versions/b090f873502e_add_default_theme_to_shop.py @@ -0,0 +1,32 @@ +"""add default_theme to shop + +Revision ID: b090f873502e +Revises: 16b9fd6d0f70 +Create Date: 2025-10-04 14:11:13.516680 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "b090f873502e" +down_revision = "16b9fd6d0f70" +branch_labels = None +depends_on = None + +from make_post_sell.models.meta import UUIDType + + +def upgrade(): + # Add default_theme column to mps_shop table with default 1 (light mode) + op.add_column( + "mps_shop", + sa.Column("default_theme", sa.BigInteger(), nullable=False, server_default="1"), + ) + + +def downgrade(): + # Remove default_theme column from mps_shop table + op.drop_column("mps_shop", "default_theme") diff --git a/make_post_sell/static/css/common.css b/make_post_sell/static/css/common.css index 97c5fd0..179533b 100644 --- a/make_post_sell/static/css/common.css +++ b/make_post_sell/static/css/common.css @@ -272,6 +272,7 @@ img.product-main { border: none; border-radius: 4px; color: white; + background-color: #D4D0C8; display: inline-block; font-size: 14px; font-weight: bold; @@ -285,21 +286,92 @@ img.product-main { cursor: pointer; } +[data-theme="dark"] .mps-button { + background-color: #2d3748; + background-image: url("/static/img/trans-blue.png"); + color: var(--blue-color); + border: 2px solid var(--blue-color); +} + +[data-theme="dark"] .mps-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-blue2.png"); + color: #ffffff; + border: 2px solid var(--blue-color); +} + a.mps-button-blue, button.mps-button-blue { background-color: #98b6fa; } +[data-theme="dark"] a.mps-button-blue, +[data-theme="dark"] button.mps-button-blue, +[data-theme="dark"] input.mps-button-blue { + background-color: #2d3748; + background-image: url("/static/img/trans-blue.png"); + color: var(--blue-color); + border: 2px solid var(--blue-color); +} + +[data-theme="dark"] a.mps-button-blue:hover, +[data-theme="dark"] button.mps-button-blue:hover, +[data-theme="dark"] input.mps-button-blue:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-blue2.png"); + color: #ffffff; + border: 2px solid var(--blue-color); +} + a.mps-button-green, button.mps-button-green { background-color: #a3c765; } + +[data-theme="dark"] a.mps-button-green, +[data-theme="dark"] button.mps-button-green, +[data-theme="dark"] input.mps-button-green { + background-color: #2d3748; + background-image: url("/static/img/trans-green.png"); + color: var(--green-color); + border: 2px solid var(--green-color); +} + +[data-theme="dark"] a.mps-button-green:hover, +[data-theme="dark"] button.mps-button-green:hover, +[data-theme="dark"] input.mps-button-green:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-green2.png"); + color: #ffffff; + border: 2px solid var(--green-color); +} + a.mps-button-red, -button.mps-button-red { +button.mps-button-red, +input.mps-button-red { background-color: #bc2131; opacity: 0.8; } +[data-theme="dark"] a.mps-button-red, +[data-theme="dark"] button.mps-button-red, +[data-theme="dark"] input.mps-button-red { + background-color: #2d3748; + background-image: url("/static/img/trans-red.png"); + color: var(--red-color); + border: 2px solid var(--red-color); + opacity: 1.0; +} + +[data-theme="dark"] a.mps-button-red:hover, +[data-theme="dark"] button.mps-button-red:hover, +[data-theme="dark"] input.mps-button-red:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-red2.png"); + color: #ffffff; + border: 2px solid var(--red-color); +} + .mps-cancel-button, .mps-comment-form-button { display: inline-block; @@ -374,6 +446,67 @@ a.product-edit-button { background-color: #98b6fa; } +[data-theme="dark"] a.mps-button.product-edit-button { + background-color: #2d3748; + background-image: url("/static/img/trans-blue.png"); + color: #7ab9ff; + border: 2px solid #7ab9ff; +} + +[data-theme="dark"] a.mps-button.product-edit-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-blue2.png"); + color: #ffffff; + border: 2px solid #7ab9ff; +} + +[data-theme="dark"] a.mps-button.shop-new-button { + background-color: #2d3748; + background-image: url("/static/img/trans-green.png"); + color: var(--green-color); + border: 2px solid var(--green-color); +} + +[data-theme="dark"] a.mps-button.shop-new-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-green2.png"); + color: #ffffff; + border: 2px solid var(--green-color); +} + +/* Product download and preview buttons - make them green in dark mode */ +[data-theme="dark"] a.product-download-button, +[data-theme="dark"] button.product-download-button { + background-color: #2d3748; + background-image: url("/static/img/trans-green.png"); + color: var(--green-color); + border: 2px solid var(--green-color); +} + +[data-theme="dark"] a.product-download-button:hover, +[data-theme="dark"] button.product-download-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-green2.png"); + color: #ffffff; + border: 2px solid var(--green-color); +} + +[data-theme="dark"] a.product-preview-button, +[data-theme="dark"] button.product-preview-button { + background-color: #2d3748; + background-image: url("/static/img/trans-green.png"); + color: var(--green-color); + border: 2px solid var(--green-color); +} + +[data-theme="dark"] a.product-preview-button:hover, +[data-theme="dark"] button.product-preview-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-green2.png"); + color: #ffffff; + border: 2px solid var(--green-color); +} + a.product-preview-button { background-color: #98b6fa; } @@ -436,6 +569,20 @@ button.cart-remove-link:hover { text-decoration: underline; } +/* Links should use the theme link color */ +[data-theme="dark"] a { + color: var(--link-color); +} + +[data-theme="dark"] button.cart-remove-link { + color: var(--blue-color); +} + +[data-theme="dark"] button.cart-remove-link:hover { + color: var(--blue-color); + text-decoration: underline; +} + /* “Add To Cart”, “Download”, “Preview” buttons */ button.product-download-button, button.product-preview-button { @@ -455,6 +602,21 @@ button.cart-checkout-button { button.cart-save-button { background-color: #98b6fa; } + +/* Dark mode cart buttons */ +[data-theme="dark"] button.cart-checkout-button { + background-color: #2d3748; + background-image: url("/static/img/trans-green.png"); + color: var(--green-color); + border: 2px solid var(--green-color); +} + +[data-theme="dark"] button.cart-checkout-button:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-green2.png"); + color: #ffffff; + border: 2px solid var(--green-color); +} button.cart-activate-button { background-color: #5871ad; } @@ -519,6 +681,20 @@ div.serp-item:hover { filter: brightness(88%); } +[data-theme="dark"] div.serp-item:hover { + background-color: #2d3748; + background-image: url("/static/img/trans-blue2.png"); + border: 2px solid #7ab9ff; + color: #ffffff; + -webkit-filter: none; + -moz-filter: none; + filter: none; +} + +[data-theme="dark"] div.serp-item:hover a { + color: #ffffff; +} + img.serp-thumbnail { border-radius: 4px; } @@ -1041,9 +1217,9 @@ div.message-ribbon { } .alert-info, .alert-notice { - color: #0c5460; - background-color: #98b6fa; - border-color: #bee5eb; + color: var(--text-primary); + background-color: color-mix(in srgb, var(--info-color) 20%, var(--bg-primary) 80%); + border-color: var(--info-color); } .alert-success { @@ -1143,8 +1319,9 @@ div.message-ribbon { } .status-box { - background: #f8f9fa; - border: 1px solid #dee2e6; + background: var(--bg-secondary); + border: 1px solid var(--border-color); + color: var(--text-primary); border-radius: 4px; padding: 15px; margin: 10px 0; @@ -1167,16 +1344,18 @@ div.message-ribbon { } .success-notice { - background: #d1fae5; - border: 1px solid #10b981; + background: color-mix(in srgb, var(--success-color) 15%, var(--bg-primary) 85%); + border: 1px solid var(--success-color); + color: var(--text-primary); border-radius: 4px; padding: 15px; margin: 20px 0; } .warning-notice { - background: #fef3c7; - border: 1px solid #f59e0b; + background: color-mix(in srgb, var(--warning-color) 15%, var(--bg-primary) 85%); + border: 1px solid var(--warning-color); + color: var(--text-primary); border-radius: 4px; padding: 15px; margin: 20px 0; @@ -1184,7 +1363,8 @@ div.message-ribbon { .monospace-address { font-family: monospace; - background: #f0f0f0; + background: var(--bg-secondary); + color: var(--text-primary); padding: 8px; border-radius: 3px; word-break: break-all; @@ -1204,6 +1384,15 @@ div.message-ribbon { cursor: not-allowed; } +[data-theme="dark"] .disabled-crypto-button { + background-color: #1a1a1a !important; + background-image: none !important; + color: #666666 !important; + border: 2px solid #444444 !important; + cursor: not-allowed; + opacity: 0.6; +} + .crypto-button-icon { width: 32px; height: 32px; @@ -1228,8 +1417,9 @@ div.message-ribbon { } .warning-banner-alt { - background: #fff3cd; - border: 1px solid #ffc107; + background: color-mix(in srgb, var(--info-color) 15%, var(--bg-primary) 85%); + border: 1px solid var(--info-color); + color: var(--text-primary); border-radius: 4px; padding: 15px; margin: 20px 0; @@ -1249,24 +1439,29 @@ div.message-ribbon { } .pending-quote-item { - background: #f8f9fa; - border: 1px solid #dee2e6; + background: transparent; + border: none; + color: var(--text-primary); border-radius: 3px; padding: 10px; margin: 8px 0; } -.pending-quote-grid { - display: grid; - grid-template-columns: 1fr auto; - align-items: start; +.pending-quote-single { + text-align: center; } -.pending-quote-status { - color: #666; - margin-left: 10px; +.pending-quote-cancel { + text-align: center; + margin-top: 10px; } +.full-width-button { + width: 100%; + display: block; +} + + .view-quote-button { background: #17a2b8; font-size: 12px; @@ -1542,3 +1737,206 @@ div.message-ribbon { font-size: 0.9em; font-family: monospace; } + +/* Dark Mode Theme System */ +:root { + /* Light mode colors (default) */ + --bg-primary: #ffffff; + --bg-secondary: #f8f9fa; + --bg-tertiary: #e9ecef; + --text-primary: #333333; + --text-secondary: #6c757d; + --text-muted: #666666; + --border-color: #dee2e6; + --border-light: #e9ecef; + --link-color: #5f6368; + --blue-color: #98b6fa; + --green-color: #a3c765; + --red-color: #bc2131; + --success-color: #28a745; + --warning-color: #ffc107; + --error-color: #dc3545; + --info-color: #17a2b8; + + /* Form elements */ + --input-bg: #ffffff; + --input-border: #cccccc; + --input-text: #333333; + + /* Navigation */ + --nav-bg: #f9f9fa; + --nav-text: #333333; + + /* Cards and containers */ + --card-bg: #f8f9fa; + --well-bg: #f9f9fa; + + /* Status notices */ + --notice-warning-bg: #fff3cd; + --notice-warning-border: #ffeaa7; + --notice-error-bg: #f8d7da; + --notice-error-border: #f5c6cb; + --notice-info-bg: #d1ecf1; + --notice-info-border: #bee5eb; +} + +[data-theme="dark"] { + /* Dark mode colors - zealotrush.com inspired gaming theme */ + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --bg-tertiary: #21262d; + --text-primary: #ffffff; + --text-secondary: #cccccc; + --text-muted: #999999; + --border-color: #7ab9ff; + --border-light: #5599dd; + --link-color: #7ab9ff; + --blue-color: #7ab9ff; + --green-color: #08e700; + --red-color: #F34C31; + --success-color: #08e700; + --warning-color: #f34c31; + --error-color: #f34c31; + --info-color: #7ab9ff; + + /* Form elements */ + --input-bg: #161b22; + --input-border: #7ab9ff; + --input-text: #ffffff; + + /* Navigation */ + --nav-bg: #0d1117; + --nav-text: #ffffff; + + /* Cards and containers */ + --card-bg: #2d2d2d; + --well-bg: #2d2d2d; + + /* Status notices */ + --notice-warning-bg: #3e2723; + --notice-warning-border: #5d4037; + --notice-error-bg: #3f1a1a; + --notice-error-border: #5c2626; + --notice-info-bg: #1a365d; + --notice-info-border: #2c5282; +} + +/* Apply theme variables to existing elements */ +body { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +section.content { + background-color: var(--bg-primary); + color: var(--text-primary); +} + +section.nav { + background-color: var(--nav-bg); + color: var(--nav-text); +} + +a { + color: var(--link-color); +} + +input[type="text"], +input[type="tel"], +input[type="password"], +input[type="number"], +input[type="date"], +textarea { + background-color: var(--input-bg); + border-color: var(--input-border); + color: var(--input-text); +} + +.well, .well2 { + background-color: var(--well-bg); + color: var(--text-primary); +} + +[data-theme="dark"] .well, +[data-theme="dark"] .well2 { + background-color: #2d3748; + background-image: url("/static/img/trans-blue.png"); + border: 2px solid #7ab9ff; + box-shadow: 0 0 10px rgba(122, 185, 255, 0.3); + color: var(--text-primary); +} + +/* Dark mode specific overrides for existing classes */ +[data-theme="dark"] table tr:nth-child(even) { + background-color: #2d2d2d; +} + +[data-theme="dark"] table tr:nth-child(odd) { + background-color: #333333; +} + +[data-theme="dark"] .crypto-payment-card { + background: var(--card-bg); + border-color: var(--border-color); + color: var(--text-primary); +} + +[data-theme="dark"] .status-warning-notice { + background: var(--notice-warning-bg); + border-color: var(--notice-warning-border); + color: var(--text-primary); +} + +[data-theme="dark"] .status-error-notice { + background: var(--notice-error-bg); + border-color: var(--notice-error-border); + color: var(--text-primary); +} + +[data-theme="dark"] .status-info-notice { + background: var(--notice-info-bg); + border-color: var(--notice-info-border); + color: var(--text-primary); +} + +[data-theme="dark"] .crypto-help-section { + background: var(--bg-tertiary); + color: var(--text-primary); +} + +[data-theme="dark"] .invoice-payment-box { + background-color: #1a365d; + border-color: #2c5282; + color: var(--text-primary); +} + +/* Crypto wallet success indicators */ +.success-indicator { + color: var(--success-color); + font-weight: bold; +} + +[data-theme="dark"] .success-indicator { + color: var(--green-color); + font-weight: bold; +} + +/* Theme toggle button */ +.theme-toggle { + background: none; + border: 1px solid var(--border-color); + color: var(--text-primary); + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + transition: background-color 0.2s ease; +} + +.theme-toggle:hover { + background-color: var(--bg-secondary); +} + +.theme-toggle-icon { + margin-right: 5px; +} diff --git a/make_post_sell/static/img/trans-blue.png b/make_post_sell/static/img/trans-blue.png new file mode 100644 index 0000000..cd0b39b Binary files /dev/null and b/make_post_sell/static/img/trans-blue.png differ diff --git a/make_post_sell/static/img/trans-blue2.png b/make_post_sell/static/img/trans-blue2.png new file mode 100644 index 0000000..ef7c0fc Binary files /dev/null and b/make_post_sell/static/img/trans-blue2.png differ diff --git a/make_post_sell/static/img/trans-green.png b/make_post_sell/static/img/trans-green.png new file mode 100644 index 0000000..1332b16 Binary files /dev/null and b/make_post_sell/static/img/trans-green.png differ diff --git a/make_post_sell/static/img/trans-green2.png b/make_post_sell/static/img/trans-green2.png new file mode 100644 index 0000000..cd5aa69 Binary files /dev/null and b/make_post_sell/static/img/trans-green2.png differ diff --git a/make_post_sell/static/img/trans-red.png b/make_post_sell/static/img/trans-red.png new file mode 100644 index 0000000..4bc43a2 Binary files /dev/null and b/make_post_sell/static/img/trans-red.png differ diff --git a/make_post_sell/static/img/trans-red2.png b/make_post_sell/static/img/trans-red2.png new file mode 100644 index 0000000..fb0fae0 Binary files /dev/null and b/make_post_sell/static/img/trans-red2.png differ diff --git a/make_post_sell/templates/actions_new.j2 b/make_post_sell/templates/actions_new.j2 index 2e396e2..ff8712c 100644 --- a/make_post_sell/templates/actions_new.j2 +++ b/make_post_sell/templates/actions_new.j2 @@ -10,28 +10,28 @@

- + New Content + + New Content {% if request.user in request.shop.owners %}

- + New Coupon + + New Coupon {% endif %}

- + New Product + + New Product {% if request.user in request.shop.owners %}

- + New Shop Location + + New Shop Location {% endif %} {% if request.is_saas_domain %}

- + New Shop + + New Shop {% endif %} {% else %} @@ -39,7 +39,7 @@ {% if request.is_saas_domain %}

Create your first shop to get started!


- + Create Your First Shop + + Create Your First Shop {% else %}

No shop configured for this domain.

{% endif %} diff --git a/make_post_sell/templates/actions_view.j2 b/make_post_sell/templates/actions_view.j2 index ede4a82..d3ea6cd 100644 --- a/make_post_sell/templates/actions_view.j2 +++ b/make_post_sell/templates/actions_view.j2 @@ -10,38 +10,38 @@

-   View Shop +   View Shop

-   View Products +   View Products {% if request.user in request.shop.owners %}

-   View Coupons +   View Coupons

- 👤   Shop Users + 👤   Shop Users

- 💰   Shop Sales + 💰   Shop Sales

- ⚙   Shop Settings + ⚙   Shop Settings {% endif %}

- 🏠   Shop Locations + 🏠   Shop Locations {% if request.is_saas_domain %}

- ⛶   Switch Shop + ⛶   Switch Shop {% endif %} {% endif %} diff --git a/make_post_sell/templates/base.j2 b/make_post_sell/templates/base.j2 index 61c92b6..3116dd1 100644 --- a/make_post_sell/templates/base.j2 +++ b/make_post_sell/templates/base.j2 @@ -7,11 +7,53 @@ {%- endif %} - +{% set user_theme_id = request.user.theme_id if request.user and request.user.authenticated else none %} +{% set shop_default_theme = request.shop.default_theme if request.shop else 1 %} +{% if user_theme_id is not none %} + {% set theme_preference = 'light' if (user_theme_id == 1) else 'dark' %} +{% else %} + {% set theme_preference = 'light' if (shop_default_theme == 1) else 'dark' %} +{% endif %} + + + + {% include 'snippets/analytics.j2' %} diff --git a/make_post_sell/templates/cart.j2 b/make_post_sell/templates/cart.j2 index 8b6e784..3922409 100644 --- a/make_post_sell/templates/cart.j2 +++ b/make_post_sell/templates/cart.j2 @@ -9,9 +9,14 @@ {% block content -%} +{% if cart.is_empty %} +
+
+{% else %}
+{% endif %} {% for coupon in cart.coupons %}
@@ -64,15 +69,16 @@

This cart is empty.

Nothing to see here. + {% if request.user and request.user.authenticated and request.user.carts.count() > 1 %}

View Saved Carts

or +
+
{% endif %} -
-
Let's go shopping!
@@ -185,6 +191,7 @@
+ {% if not cart.is_empty %}
{% if cart.is_discounted %} @@ -275,6 +282,7 @@
+ {% endif %}
diff --git a/make_post_sell/templates/cart_checkout.j2 b/make_post_sell/templates/cart_checkout.j2 index f486448..104d989 100644 --- a/make_post_sell/templates/cart_checkout.j2 +++ b/make_post_sell/templates/cart_checkout.j2 @@ -42,8 +42,7 @@
{% if cart.requires_payment %} - Are you sure you want to confirm checkout & pay
- ${{ '{:,.2f}'.format(cart.total) }}? + Are you sure you want to confirm checkout & pay ${{ '{:,.2f}'.format(cart.total) }}? {% else %} Are you sure you want to confirm checkout? {% endif %} @@ -61,7 +60,7 @@ {% if monero_enabled and xmr_processor_enabled and cart.requires_payment and cart.shop_product_dict|length == 1 %}
{% if pending_crypto_quotes %} - + {% else %}
{% include "snippets/csrf.j2" %} @@ -80,7 +79,7 @@ {% if dogecoin_enabled and doge_processor_enabled and cart.requires_payment and cart.shop_product_dict|length == 1 %}
{% if pending_crypto_quotes %} - + {% else %} {% include "snippets/csrf.j2" %} @@ -124,27 +123,18 @@ {# Show pending crypto quotes if user has any #} {% if pending_crypto_quotes %}
-

📋 {{ pending_crypto_quotes|length }} Pending Crypto Quote{{ 's' if pending_crypto_quotes|length != 1 else '' }}

-

You have {{ pending_crypto_quotes|length }} pending crypto payment{{ 's' if pending_crypto_quotes|length != 1 else '' }}:

+

📋 Pending {{ pending_crypto_quotes[0].coin_type }} Payment

{% for quote in pending_crypto_quotes %}
-
-
- {{ quote.coin_type }} - - {{ quote.status.title() }} - {% if quote.current_confirmations > 0 %} - ({{ quote.confirmation_status }}) - {% endif %} - -
- -
Amount: {{ '%.8f' % (quote.expected_amount / (1000000000000 if quote.coin_type == 'XMR' else 100000000)) }} {{ quote.coin_type }}
+ +
+ +
{% endfor %}
@@ -169,8 +159,11 @@ function cancelQuote(paymentId) { .then(response => response.json()) .then(data => { if (data.success) { - alert('Payment quote cancelled successfully'); - window.location.reload(); + if (data.cart_url) { + window.location.href = data.cart_url; + } else { + window.location.reload(); + } } else { alert('Failed to cancel quote: ' + (data.message || 'Unknown error')); } diff --git a/make_post_sell/templates/shop_settings.j2 b/make_post_sell/templates/shop_settings.j2 index 3d0cf63..a4f84c2 100644 --- a/make_post_sell/templates/shop_settings.j2 +++ b/make_post_sell/templates/shop_settings.j2 @@ -163,9 +163,6 @@ />
-
- -
{% if request.shop.stripe_enabled %} @@ -173,9 +170,12 @@ {% else %} - Enter your API keys to re-enable Stripe payments {% endif %} + + +
+

@@ -504,6 +504,16 @@

+ + + Choose the default theme that new visitors see. Users can override this in their profile settings. + +
+
+
diff --git a/make_post_sell/templates/user_crypto_settings.j2 b/make_post_sell/templates/user_crypto_settings.j2 index 9d97544..d273e6c 100644 --- a/make_post_sell/templates/user_crypto_settings.j2 +++ b/make_post_sell/templates/user_crypto_settings.j2 @@ -28,32 +28,16 @@ placeholder = "Your {{ coin }} address for automatic refunds" /> -
- - - -

- {% if addresses.get(coin) %} - - {% else %} - - {% endif %} +

-
+ {% if not loop.last %}
{% endif %} {% endfor %} {% else %}

No cryptocurrencies are currently enabled on this platform.

diff --git a/make_post_sell/templates/user_settings.j2 b/make_post_sell/templates/user_settings.j2 index 3300ddb..83ad9d9 100644 --- a/make_post_sell/templates/user_settings.j2 +++ b/make_post_sell/templates/user_settings.j2 @@ -35,19 +35,8 @@ placeholder = "Full Name" required /> - +
+
@@ -56,6 +45,53 @@
+ +
+ +
+
+

Theme Preference

+ +
+ + +
+ + + +
+ + +
+

diff --git a/make_post_sell/views/shop.py b/make_post_sell/views/shop.py index 1241be2..adfb547 100644 --- a/make_post_sell/views/shop.py +++ b/make_post_sell/views/shop.py @@ -382,6 +382,9 @@ def shop_settings(request): ribbon_color_1 = request.params.get("ribbon_color_1", shop.ribbon_color_1).strip() ribbon_color_2 = request.params.get("ribbon_color_2", shop.ribbon_color_2).strip() + # Theme settings + default_theme = request.params.get("default_theme", shop.default_theme) + google_analytics_id = request.params.get( "google_analytics_id", shop.google_analytics_id ) @@ -551,6 +554,16 @@ def shop_settings(request): ) request.session.flash(msg) + # Handle default theme setting + if default_theme and int(default_theme) != shop.default_theme: + shop.default_theme = int(default_theme) + theme_name = "Dark Mode" if int(default_theme) == 0 else "Light Mode" + msg = ( + f"Shop default theme set to {theme_name}.", + "success", + ) + request.session.flash(msg) + # Handle stripe settings form if form_section == "stripe-settings": # Handle disable action @@ -877,6 +890,7 @@ def shop_settings(request): "ribbon_text_color": shop.ribbon_text_color or "", "ribbon_color_1": shop.ribbon_color_1 or "", "ribbon_color_2": shop.ribbon_color_2 or "", + "default_theme": shop.default_theme, "google_analytics_id": shop.google_analytics_id or "", "plausible_domain_name": shop.plausible_domain_name or "", "stripe_public_api_key": shop.stripe_public_api_key or "", diff --git a/make_post_sell/views/user.py b/make_post_sell/views/user.py index c17d6f2..3bd4662 100644 --- a/make_post_sell/views/user.py +++ b/make_post_sell/views/user.py @@ -50,6 +50,7 @@ def user_settings(request): name = request.params.get("name", user.name).strip() full_name = request.params.get("full_name", user.full_name or "").strip() + theme_id = request.params.get("theme_id", user.theme_id) if name and name != user.name: if not is_user_name_valid(name): @@ -74,9 +75,17 @@ def user_settings(request): msg = ("You set your private full name.", "success") request.session.flash(msg) + # Handle theme preference changes + if theme_id and int(theme_id) != user.theme_id: + user.theme_id = int(theme_id) + theme_name = "Dark Mode" if int(theme_id) == 0 else "Light Mode" + msg = (f"Theme preference set to {theme_name}.", "success") + request.session.flash(msg) + return { "name": name, "full_name": full_name, + "theme_id": user.theme_id, }