Files
timebank-cc-public/references/BRANDING_CUSTOMIZATION.md
Ronald Huynen 2547717edb Initial commit
2026-03-23 21:37:59 +01:00

28 KiB

Branding Customization Guide

Complete guide for creating and customizing branded instances of the Timebank platform with unique visual identity, configuration, content, and protected deployment.


Table of Contents

  1. Overview
  2. Configuration Protection System
  3. Theme Customization
  4. Logo Customization
  5. Platform Configuration
  6. Footer Customization
  7. Custom Content Pages
  8. Database Updates
  9. Complete Setup Workflow
  10. Deployment & Updates
  11. Troubleshooting
  12. Best Practices

Overview

The platform supports complete branding through four main customization layers:

  1. Theme System - Visual styling (colors, fonts, spacing)
  2. Logo System - Theme-specific branding assets
  3. Platform Configuration - Behavior, limits, translations, footer structure
  4. Content Seeding - Custom pages and navigation links

All customizations are protected from git overwrites during deployments using a config template system.


Configuration Protection System

How It Works

The Problem: When running deploy.sh, git pull would overwrite customized configuration files with defaults from the repository.

The Solution:

  • .example files are tracked in git (templates with defaults)
  • Actual config files are gitignored (safe from overwrites)
  • deploy.sh automatically creates configs from templates if they don't exist
  • Custom changes persist through all deployment updates

Protected Configuration Files

The following files are protected from git overwrites:

File Purpose Template
config/themes.php Theme configuration (colors, fonts, logos) config/themes.php.example
config/timebank-default.php Default platform configuration config/timebank-default.php.example
config/timebank_cc.php Platform-specific overrides Create as needed

Initial Migration

Run once per repository to enable the protection system:

# From repository root
./scripts/migrate-to-example-configs.sh

This will:

  1. Remove config files from git tracking (keeps your local files intact)
  2. Add .example template files to git
  3. Update .gitignore
  4. Create a commit with all changes
  5. Ready to push to repository

After migration:

git push origin main

Configuration Workflow

New Installation

git clone <repo>
cd timebank_cc_2
./deploy.sh

What happens:

  1. No config files exist yet
  2. deploy.sh creates them from .example templates
  3. Customize configs with your branding
  4. Customizations are now protected

Updating Existing Installation

./deploy.sh

What happens:

  1. Config check runs BEFORE git pull
  2. Your custom configs exist → Preserved
  3. Git pulls latest .example templates (updated defaults)
  4. Your custom configs remain unchanged
  5. Review .example files for new features to merge manually

Merging Updates from Templates

Option 1: Manual Review (Recommended)

# Compare your config with latest template
diff config/themes.php config/themes.php.example

# Review changes and merge relevant updates
nano config/themes.php

Option 2: Regenerate from Template

⚠️ Warning: This erases all customizations!

# Backup first
cp config/themes.php config/themes.php.backup

# Delete and regenerate
rm config/themes.php
./deploy.sh

# Re-apply customizations from backup

Theme Customization

Setting Up a Theme

Location: config/themes.php

Activation: Set TIMEBANK_THEME in .env

TIMEBANK_THEME=your_brand_name

Creating a New Theme

Add your theme definition to config/themes.php:

'your_brand_name' => [
    'name' => 'Your Brand Name',
    'description' => 'Description of your brand theme',

    // Logo Configuration
    'logos' => [
        'svg_inline' => 'logos.your_brand_name',
        'email_logo' => 'app-images/your_brand_name_mail_logo.png',
    ],

    // Color Palette
    'colors' => [
        // Brand Colors
        'brand' => '#FF5733',
        'secondary' => '#EBEDEE',
        'accent' => '#434343',

        // Primary Palette (9 shades)
        'primary' => [
            50 => '#fef2f2',
            100 => '#fee2e2',
            200 => '#fecaca',
            300 => '#fca5a5',
            400 => '#f87171',
            500 => '#ef4444',  // Main primary color
            600 => '#dc2626',
            700 => '#b91c1c',
            800 => '#991b1b',
            900 => '#7f1d1d',
        ],

        // Functional Colors
        'danger-dark' => '#b91c1c',
        'danger' => '#ef4444',
        'danger-light' => '#fecaca',
        'reaction' => '#eab308',
        'reaction-hover' => '#ca8a04',

        // UI Elements
        'background' => '#FFFFFF',
        'border' => '#CDCFD0',
        'surface' => '#F9FAFB',

        // Text Colors
        'text' => [
            'primary' => '#111827',
            'secondary' => '#6E6F70',
            'light' => '#9CA3AF',
            'surface' => '#F9FAFB',
            'background' => '#FFFFFF',
        ],

        // Logo Color (for SVG fill)
        'logo' => '#000000',
    ],

    // Typography
    'typography' => [
        'font_family_body' => 'Roboto, sans-serif',
        'font_family_heading' => 'Oswald, sans-serif',
        'font_size_base' => '16px',
        'line_height_base' => '1.7',
        'heading_transform' => 'uppercase',  // or 'none'
        'heading_sizes' => [
            'h1' => '30px',
            'h2' => '24px',
            'h3' => '20px',
            'h4' => '16px',
        ],
        'links' => [
            'text_decoration' => 'underline',
            'text_decoration_hover' => 'underline',
            'font_weight' => '600',
        ],
    ],
],

Using Theme Colors in Views

CSS Classes (Recommended):

<div class="bg-theme-brand text-white">
    <h1 class="text-theme-primary-600">Title</h1>
    <p class="text-theme-text-medium">Body text</p>
    <button class="border-theme-border bg-theme-primary-500">Click</button>
</div>

PHP Helper Functions:

// In Livewire components or controllers
$brandColor = theme_color('brand');
$primaryColor = theme_color('primary.500');
$fontFamily = theme_font('font_family_body');
$logoView = theme_logo('svg_inline');
$emailLogo = theme_logo('email_logo');

Important: Always use theme-aware classes/functions. Never hardcode colors like bg-blue-500 or text-gray-600.

Testing Themes

Switch themes by changing .env:

TIMEBANK_THEME=timebank_cc
TIMEBANK_THEME=uuro
TIMEBANK_THEME=vegetable
TIMEBANK_THEME=yellow

After changing theme:

php artisan config:clear
npm run build

Test all UI components across themes to ensure consistency.


Logo Customization

Logo System Overview

Each theme can have unique branding through two types of logos:

  1. SVG Logos - Inline SVG for website (navigation, auth pages)
  2. Email/PDF Logos - PNG format for emails and PDF reports

Logo File Locations

SVG Logos (Website):

  • Location: resources/views/logos/
  • Files:
    • timebank_cc.blade.php - Default theme
    • uuro.blade.php - Uuro theme
    • vegetable.blade.php - Vegetable theme
    • yellow.blade.php - Yellow theme
    • your_brand.blade.php - Your custom theme
  • Format: Blade template with inline SVG
  • Git Tracking: Yes (tracked as defaults)

Email/PDF Logos:

  • Location: storage/app/public/app-images/
  • Files:
    • timebank_cc_mail_logo.png
    • uuro_mail_logo.png
    • vegetable_mail_logo.png
    • yellow_mail_logo.png
    • your_brand_mail_logo.png
  • Format: PNG image
  • Git Tracking: No (gitignored, safe from overwrites)

Creating Custom Logos

1. SVG Logo (Website)

Create logo file:

cp resources/views/logos/timebank_cc.blade.php resources/views/logos/your_brand.blade.php

Edit the SVG:

{{-- your_brand.blade.php --}}
<svg width="160" height="112" viewBox="0 0 52.92 37.04" xmlns="http://www.w3.org/2000/svg"
     class="fill-theme-logo">
    <title>{{ config('app.name') . ' ' . __('logo') }}</title>

    <!-- Your custom SVG paths here -->
    <path d="..." />
</svg>

Important:

  • Keep class="fill-theme-logo" for theme-aware coloring
  • Include title tag for accessibility
  • Adjust viewBox and dimensions as needed

2. Email/PDF Logo (PNG)

Upload your logo:

# Upload to storage/app/public/app-images/
cp /path/to/your/logo.png storage/app/public/app-images/your_brand_mail_logo.png

Recommended specifications:

  • Format: PNG with transparency
  • Size: 300-400px width (maintains quality in emails)
  • Aspect ratio: Similar to your website logo

3. Configure Theme Logos

In config/themes.php:

'your_brand' => [
    'name' => 'Your Brand',
    'logos' => [
        'svg_inline' => 'logos.your_brand',          // Website logo
        'email_logo' => 'app-images/your_brand_mail_logo.png',  // Email/PDF logo
    ],
    // ... rest of theme config
],

Logo Helper Functions

// Get SVG view name
theme_logo('svg_inline')  // Returns: 'logos.your_brand'

// Get email logo path
theme_logo('email_logo')  // Returns: 'app-images/your_brand_mail_logo.png'

Logo Usage in Code

The logo system is automatically integrated:

  • Navigation menu - Uses application-mark.blade.php (compact logo)
  • Authentication pages - Uses authentication-card-logo.blade.php (full logo)
  • Email templates - Uses theme email logo
  • PDF reports - Uses theme email logo

All automatically switch based on TIMEBANK_THEME setting.

Logo Deployment Protection

SVG logos are tracked in git as theme-specific defaults Email logos are in storage/ (gitignored, safe from git pull) No conflicts when deploying updates Each installation maintains unique branding


Platform Configuration

Setting Up Platform Config

Location: config/ directory

Activation: Set TIMEBANK_CONFIG in .env

TIMEBANK_CONFIG=your_platform_name

Creating a New Platform Configuration

  1. Copy the default config:
cp config/timebank-default.php config/your-platform.php
  1. Customize settings in config/your-platform.php:
return [
    // Platform Identity
    'platform_name' => 'Your Platform Name',
    'currency_name' => 'TimeCredits',
    'currency_symbol' => 'TC',

    // Email Addresses
    'mail' => [
        'system_admin' => [
            'email' => 'admin@yourplatform.com',
            'name' => 'System Admin',
        ],
        'user_admin' => [
            'email' => 'users@yourplatform.com',
            'name' => 'User Admin',
        ],
        'content_admin' => [
            'email' => 'content@yourplatform.com',
            'name' => config('app.name'),
        ],
    ],

    // Account Limits (in minutes)
    'accounts' => [
        'user' => [
            'min_balance' => -300,  // -5 hours
            'max_balance' => 2400,  // 40 hours
        ],
        'organization' => [
            'min_balance' => -3000,  // -50 hours
            'max_balance' => 24000,  // 400 hours
        ],
    ],

    // Transaction Types & Permissions
    'transactions' => [
        'types' => [
            'worked_time' => true,
            'gift' => true,
            'donation' => true,
            'currency_creation' => true,
            'currency_removal' => true,
            'migration' => false,
        ],
        'permissions' => [
            'user_can_create_currency' => false,
            'organization_can_create_currency' => false,
            'bank_can_create_currency' => true,
        ],
    ],

    // Profile Visibility
    'profiles' => [
        'show_public_balances' => true,
        'allow_private_profiles' => true,
    ],

    // Search Configuration
    'search' => [
        'boost_factors' => [
            'name' => 3.0,
            'description' => 1.5,
            'tags' => 2.0,
        ],
    ],

    // Footer Configuration (see next section)
    'footer' => [
        // ...
    ],
];

Accessing Configuration Values

PHP Helper Function:

// Anywhere in the application
$platformName = timebank_config('platform_name');
$minBalance = timebank_config('accounts.user.min_balance');
$canCreateCurrency = timebank_config('transactions.permissions.bank_can_create_currency');

In Blade Views:

<h1>{{ timebank_config('platform_name') }}</h1>
<span>{{ timebank_config('currency_symbol') }}</span>

The footer is defined in your platform config file under the footer key:

'footer' => [
    'tagline' => 'Your time is currency',  // Translation key

    'sections' => [
        [
            'title' => 'Who we are',        // Translation key
            'order' => 1,                    // Display order (lower = left)
            'visible' => true,               // Show/hide entire section
            'links' => [
                [
                    'route' => 'static-whyjoin',     // Laravel route name
                    'title' => 'Why join',            // Translation key
                    'order' => 1,                     // Display order (lower = top)
                    'visible' => true,                // Show/hide link
                ],
                [
                    'route' => 'static-association',
                    'title' => 'Timebank Organization',
                    'order' => 2,
                    'visible' => true,
                ],
                // Custom URL example
                [
                    'url' => 'https://example.com',
                    'title' => 'External Resource',
                    'order' => 3,
                    'visible' => true,
                ],
                // Auth-required example
                [
                    'route' => 'static-messenger',
                    'title' => 'Chat messenger',
                    'order' => 4,
                    'visible' => true,
                    'auth_required' => true,  // Only show to logged-in users
                ],
            ],
        ],
        [
            'title' => 'Help',
            'order' => 2,
            'visible' => true,
            'links' => [
                // ... more links
            ],
        ],
    ],
],

1. Internal Route Links (most common):

[
    'route' => 'static-whyjoin',  // Must match route name in routes/web.php
    'title' => 'Why join',         // Translation key from lang files
    'order' => 1,
    'visible' => true,
]

2. External URL Links:

[
    'url' => 'https://external-site.com/page',
    'title' => 'External Resource',
    'order' => 2,
    'visible' => true,
]

3. Authenticated Links:

[
    'route' => 'dashboard',
    'title' => 'Dashboard',
    'order' => 3,
    'visible' => true,
    'auth_required' => true,  // Only visible when logged in
]

Reorder sections:

['title' => 'Help', 'order' => 1, ...],
['title' => 'Who we are', 'order' => 2, ...],
['title' => 'Policies', 'order' => 3, ...],

Hide specific links:

['route' => 'static-research', 'title' => 'Research', 'visible' => false],

Add email contact:

['url' => 'mailto:hello@yourplatform.com', 'title' => 'Email Us', 'order' => 5, 'visible' => true],

Add new section:

[
    'title' => 'Community',
    'order' => 4,
    'visible' => true,
    'links' => [
        ['url' => 'https://forum.example.com', 'title' => 'Forum', 'order' => 1, 'visible' => true],
        ['url' => 'https://blog.example.com', 'title' => 'Blog', 'order' => 2, 'visible' => true],
    ],
],

Custom Content Pages

Adding New Static Pages

To add new pages that appear in the footer or navigation, seed the database with categories and translations.

Step 1: Add Category Type

File: database/seeders/ExtendCategoriesSeeder.php

$categories = [
    // Existing categories...

    // Add your new category
    ['type' => 'SiteContents\\Static\\YourNewPage'],
];

Naming Convention:

  • Static pages: SiteContents\\Static\\PageName
  • Manage pages: SiteContents\\Manage\\PageName
  • Error pages: SiteContents\\Errors\\ErrorCode

Step 2: Add Translations

File: database/seeders/ExtendCategoryTranslationsSeeder.php

$translations = [
    // Existing translations...

    'SiteContents\\Static\\YourNewPage' => [
        'en' => [
            'name' => 'Your New Page',
            'slug' => 'your-new-page',
        ],
        'nl' => [
            'name' => 'Jouw Nieuwe Pagina',
            'slug' => 'jouw-nieuwe-pagina',
        ],
        'de' => [
            'name' => 'Deine Neue Seite',
            'slug' => 'deine-neue-seite',
        ],
        'es' => [
            'name' => 'Tu Nueva Página',
            'slug' => 'tu-nueva-pagina',
        ],
        'fr' => [
            'name' => 'Votre Nouvelle Page',
            'slug' => 'votre-nouvelle-page',
        ],
    ],
];

Step 3: Run Seeders

php artisan db:seed --class=ExtendCategoriesSeeder
php artisan db:seed --class=ExtendCategoryTranslationsSeeder

Step 4: Add Route

File: routes/web.php

Route::get('/your-new-page', [StaticController::class, 'yourNewPage'])
    ->name('static-yournewpage');

File: config/your-platform.php

'footer' => [
    'sections' => [
        [
            'title' => 'Who we are',
            'links' => [
                [
                    'route' => 'static-yournewpage',
                    'title' => 'Your New Page',
                    'order' => 10,
                    'visible' => true,
                ],
            ],
        ],
    ],
],

Database Updates

When to Use Database Updates

Use the DatabaseUpdate command when:

  • Renaming seeded categories across all installations
  • Updating category slugs or translations globally
  • Migrating data structures affecting seeded content
  • Making breaking changes to existing static pages

DO NOT use for:

  • Adding new categories (use seeders)
  • Platform-specific configs (use config files)
  • Theme changes (use themes.php)

Adding a Database Update

File: app/Console/Commands/DatabaseUpdate.php

private function updateYourFeature()
{
    $this->info('Updating your feature...');

    try {
        DB::beginTransaction();

        // Update category type
        $updated = DB::table('categories')
            ->where('type', 'SiteContents\\Old\\Name')
            ->update(['type' => 'SiteContents\\New\\Name']);

        if ($updated > 0) {
            $this->info("  ✓ Updated {$updated} category record(s)");
        }

        // Update translations
        $category = DB::table('categories')
            ->where('type', 'SiteContents\\New\\Name')
            ->first();

        if ($category) {
            DB::table('category_translations')
                ->where('category_id', $category->id)
                ->update([
                    'name' => 'New Name',
                    'slug' => 'new-slug',
                ]);
        }

        DB::commit();
        $this->info('  ✓ Update completed successfully');

    } catch (\Exception $e) {
        DB::rollBack();
        $this->error('  ✗ Failed to update: ' . $e->getMessage());
    }
}

Call in handle() method:

public function handle()
{
    $this->info('Starting database updates...');
    $this->updateYourFeature();
    $this->info('Database updates completed!');
    return 0;
}

Run updates:

php artisan database:update

Complete Setup Workflow

Initial Branded Instance Setup

# 1. Clone repository
git clone <repository-url>
cd timebank_cc_2

# 2. Run first deployment (creates configs from templates)
./deploy.sh

# 3. Configure environment variables
# Edit .env:
TIMEBANK_THEME=mybrand
TIMEBANK_CONFIG=mybrand

# 4. Create theme in config/themes.php
# Add 'mybrand' theme definition with colors, fonts, logos

# 5. Create platform config
cp config/timebank-default.php config/mybrand.php
# Edit config/mybrand.php with your settings

# 6. Create theme logos
# SVG logo:
cp resources/views/logos/timebank_cc.blade.php resources/views/logos/mybrand.blade.php
# Edit mybrand.blade.php with your logo

# Email logo:
cp your-logo.png storage/app/public/app-images/mybrand_mail_logo.png

# 7. Add custom content pages (if needed)
# Edit database/seeders/ExtendCategoriesSeeder.php
# Edit database/seeders/ExtendCategoryTranslationsSeeder.php

# 8. Seed custom content
php artisan db:seed --class=ExtendCategoriesSeeder
php artisan db:seed --class=ExtendCategoryTranslationsSeeder

# 9. Apply database updates
php artisan database:update

# 10. Clear caches and build assets
php artisan config:clear
npm run build

# 11. Test
php artisan serve

Deployment & Updates

Protected Files During Deployment

When you run ./deploy.sh, these files are protected from git overwrites:

Protected (gitignored):

  • config/themes.php - Your custom theme configuration
  • config/timebank-default.php - Your platform configuration
  • config/mybrand.php - Your brand-specific configuration
  • storage/app/public/app-images/*.png - Your email/PDF logos

Updated from git (templates):

  • config/themes.php.example - Latest theme defaults
  • config/timebank-default.php.example - Latest platform defaults
  • resources/views/logos/*.blade.php - SVG logo defaults

Deployment Process

./deploy.sh

What happens:

  1. Config Check (NEW):

    ===========================================================
       CHECKING CONFIGURATION FILES
    ===========================================================
    
    ✓ config/themes.php exists (custom installation config)
    ✓ config/timebank-default.php exists (custom installation config)
    
  2. Git Pull:

    • Pulls latest code
    • Updates .example templates
    • Your custom configs untouched
  3. Dependencies:

    • composer install
    • npm install
  4. Database:

    • Migrations
    • Database updates
    • Seeders
  5. Build Assets:

    • npm run build
    • Theme-specific compilation

After Deployment

Review new features:

# Check for new theme options
diff config/themes.php config/themes.php.example

# Check for new platform config options
diff config/timebank-default.php config/timebank-default.php.example

Merge beneficial updates manually into your custom configs.

Emergency Config Recovery

If configs were accidentally overwritten:

# Restore from git (if committed before migration)
git checkout HEAD~1 config/themes.php

# Or regenerate from backup
cp config/themes.php.backup config/themes.php

Troubleshooting

Theme not applying

  • Verify TIMEBANK_THEME in .env matches theme name in config/themes.php
  • Run php artisan config:clear
  • Run npm run build
  • Check browser console for CSS errors

Platform config not loading

  • Verify TIMEBANK_CONFIG in .env matches filename (without .php)
  • Ensure config file exists in config/ directory
  • Run php artisan config:clear

Logos not displaying

  • SVG logos: Verify logo file exists in resources/views/logos/
  • Email logos: Verify PNG exists in storage/app/public/app-images/
  • Check theme config logos section points to correct files
  • Run php artisan config:clear
  • Check visible is set to true in footer config
  • Verify route name exists in routes/web.php
  • Check translation keys exist in language files
  • Clear cache: php artisan config:clear

Custom page not found

  • Verify category seeded: check categories table
  • Verify translations seeded: check category_translations table
  • Verify route exists and matches route in footer config
  • Check category type matches exactly (including backslashes)

Config files overwritten by git

Symptom: Customizations disappeared after git pull

Cause: Migration to .example system not completed

Solution:

# Run migration script
./scripts/migrate-to-example-configs.sh

# Push changes
git push origin main

Database updates not applying

  • Check database connection
  • Verify update method called in handle()
  • Check database permissions
  • Look for transaction rollback messages

Best Practices

Configuration Management

  1. Always use .example files as templates for new installations
  2. Document your customizations in comments within config files
  3. Review .example files after each deployment for new features
  4. Backup configs before major changes
  5. Never commit actual config files (only .example versions)

Theme Development

  1. Test across all themes after making UI changes
  2. Use theme-aware classes exclusively (bg-theme-brand not bg-blue-500)
  3. Define complete color palettes (all 9 shades for primary)
  4. Test logo visibility on light and dark backgrounds
  5. Verify email logos render correctly in email clients

Platform Configuration

  1. Keep configs focused on behavior, not styling
  2. Version control custom configs locally (gitignored from repo)
  3. Document custom pages in config file comments
  4. Follow naming conventions for category types consistently
  5. Provide all 5 language translations for new content

Deployment

  1. Run ./deploy.sh regularly to stay updated
  2. Review .example diffs after deployment
  3. Test in staging before production deployment
  4. Clear caches after configuration changes
  5. Monitor deployment logs for config file status

Content Management

  1. Use DatabaseUpdate for breaking changes to seeded data
  2. Test footer configuration in all languages
  3. Clear caches after seeding new categories
  4. Verify routes before adding to footer config
  5. Keep slugs URL-friendly and consistent

Quick Reference

Environment Variables

TIMEBANK_THEME=your_brand_name
TIMEBANK_CONFIG=your_platform_name

Helper Functions

// Theme
theme_color('brand')
theme_color('primary.500')
theme_font('font_family_body')
theme_logo('svg_inline')
theme_logo('email_logo')

// Config
timebank_config('platform_name')
timebank_config('accounts.user.min_balance')
timebank_config('footer.sections')

Artisan Commands

# Configuration
php artisan config:clear

# Database
php artisan db:seed --class=ExtendCategoriesSeeder
php artisan db:seed --class=ExtendCategoryTranslationsSeeder
php artisan database:update

# Assets
npm run build

# Deployment
./deploy.sh
./scripts/migrate-to-example-configs.sh

File Locations

Themes:          config/themes.php (protected)
                 config/themes.php.example (tracked)
Configs:         config/{platform}.php (protected)
                 config/{platform}.php.example (tracked)
SVG Logos:       resources/views/logos/{theme}.blade.php
Email Logos:     storage/app/public/app-images/{theme}_mail_logo.png (gitignored)
Seeders:         database/seeders/ExtendCategoriesSeeder.php
                 database/seeders/ExtendCategoryTranslationsSeeder.php
DB Updates:      app/Console/Commands/DatabaseUpdate.php
Translations:    lang/{locale}/messages.php
Routes:          routes/web.php

Git Tracking

# Tracked in git (defaults/templates)
git ls-files config/*.example
git ls-files resources/views/logos/

# Gitignored (custom/protected)
git check-ignore config/themes.php
git check-ignore storage/app/public/app-images/*.png

Additional Resources

  • Theme System Details: references/THEME_IMPLEMENTATION.md
  • Logo Customization: resources/views/logos/README.md
  • Migration Script: scripts/migrate-to-example-configs.sh
  • Main Documentation: CLAUDE.md

This guide covers all aspects of creating and maintaining a branded Timebank instance with full protection from deployment overwrites.