Files
metabuilder/docs/guides/SASS_EXAMPLES.md
2025-12-25 11:56:14 +00:00

14 KiB

SASS Usage Examples

This document provides practical examples of how to use the SASS system in MetaBuilder.

Table of Contents

  1. Using Pre-built Classes
  2. Using Variables & Mixins
  3. Creating Custom Components
  4. Responsive Design
  5. Theme Switching
  6. Advanced Techniques

Using Pre-built Classes

Buttons

<!-- Primary button (large) -->
<button class="btn btn-primary btn-lg">Submit</button>

<!-- Secondary button (medium) -->
<button class="btn btn-secondary btn-md">Cancel</button>

<!-- Danger button (small) -->
<button class="btn btn-danger btn-sm">Delete</button>

<!-- Success button (block/full width) -->
<button class="btn btn-success btn-block">Confirm</button>

<!-- Icon button (circular) -->
<button class="btn btn-primary btn-icon">
  <svg>...</svg>
</button>

Cards

<div class="card">
  <div class="card-header">
    <h2>Card Title</h2>
  </div>
  
  <div class="card-body">
    <p>Card content goes here.</p>
  </div>
  
  <div class="card-footer">
    <button class="btn btn-primary">Action</button>
  </div>
</div>

<!-- Elevated card -->
<div class="card card-elevated">
  Content with shadow
</div>

<!-- Compact card -->
<div class="card card-compact">
  <p>Smaller padding</p>
</div>

Forms

<form>
  <div class="form-group">
    <label class="form-label">Email Address</label>
    <input type="email" placeholder="user@example.com" />
    <span class="form-help">We'll never share your email.</span>
  </div>
  
  <div class="form-group">
    <label class="form-label">Password</label>
    <input type="password" />
    <span class="form-error">Password is required.</span>
  </div>
  
  <div class="form-group">
    <label class="form-label">Confirm Password</label>
    <input type="password" />
    <span class="form-success">Passwords match!</span>
  </div>
  
  <button class="btn btn-primary btn-block">Sign In</button>
</form>

Badges

<!-- Default badge -->
<span class="badge">New</span>

<!-- Color variants -->
<span class="badge badge-primary">Featured</span>
<span class="badge badge-success">Active</span>
<span class="badge badge-warning">Pending</span>
<span class="badge badge-danger">Offline</span>
<span class="badge badge-info">Info</span>

Alerts

<!-- Info alert -->
<div class="alert alert-info">
  <strong class="alert-title">Heads up!</strong>
  <p class="alert-message">This is an informational message.</p>
</div>

<!-- Success alert -->
<div class="alert alert-success">
  <strong>Success!</strong> Your changes have been saved.
</div>

<!-- Warning alert -->
<div class="alert alert-warning">
  <strong>Warning:</strong> Please review your input.
</div>

<!-- Danger alert -->
<div class="alert alert-danger">
  <strong>Error!</strong> Something went wrong. Please try again.
</div>

Spacing Utilities

<!-- Margin utilities -->
<div class="mt-4 mb-8">Margin top 1rem, margin bottom 2rem</div>

<!-- Padding utilities -->
<div class="p-6">Padding 1.5rem all sides</div>

<!-- Responsive spacing -->
<div class="p-4 md:p-6 lg:p-8">
  Padding 1rem (mobile), 1.5rem (tablet), 2rem (desktop)
</div>

<!-- Margin horizontal (left/right) -->
<div class="mx-auto">Centered horizontally</div>

Text Utilities

<!-- Text colors -->
<p class="text-primary">Primary color text</p>
<p class="text-success">Success message</p>
<p class="text-danger">Error message</p>
<p class="text-muted">Muted text</p>

<!-- Text alignment -->
<p class="text-left">Left aligned</p>
<p class="text-center">Centered</p>
<p class="text-right">Right aligned</p>

<!-- Text transformation -->
<p class="text-uppercase">UPPERCASE</p>
<p class="text-lowercase">lowercase</p>
<p class="text-capitalize">Capitalized</p>

<!-- Text truncate -->
<p class="text-truncate">
  This very long text will be cut off with an ellipsis...
</p>

Grid & Flex Layout

<!-- Simple grid (3 columns) -->
<div class="grid grid-cols-3 gap-4">
  <div class="card">Column 1</div>
  <div class="card">Column 2</div>
  <div class="card">Column 3</div>
</div>

<!-- Flex with space-between -->
<div class="flex flex-between">
  <div>Left item</div>
  <div>Right item</div>
</div>

<!-- Flex centered -->
<div class="flex flex-center">
  <span>Centered content</span>
</div>

<!-- Flex column -->
<div class="flex flex-column gap-4">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</div>

Responsive Display

<!-- Hidden on small screens, visible on medium+ -->
<div class="md:block hidden">
  Desktop navigation
</div>

<!-- Visible on small screens, hidden on large+ -->
<div class="lg:hidden">
  Mobile menu
</div>

<!-- Responsive grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  <div class="card">Item</div>
  <!-- Repeats... -->
</div>

<!-- Responsive text size -->
<h1 class="text-2xl md:text-3xl lg:text-4xl">
  Responsive heading
</h1>

Using Variables & Mixins

In React Components with CSS Modules

// MyComponent.module.scss
@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.container {
  padding: $space-6;
  background-color: $bg-primary;
  border-radius: $radius-lg;
  @include elevation(2);
}

.title {
  @include heading-3;
  color: $color-primary;
  margin-bottom: $space-4;
}

.description {
  @include text-body;
  color: $fg-secondary;
  line-height: $line-height-relaxed;
}

.buttonGroup {
  @include flex-between;
  gap: $space-4;
  margin-top: $space-6;
}

.button {
  @include btn-primary;
  
  &:hover {
    @include elevation(3);
  }
}
// MyComponent.tsx
import styles from './MyComponent.module.scss'

export function MyComponent() {
  return (
    <div className={styles.container}>
      <h3 className={styles.title}>Card Title</h3>
      <p className={styles.description}>Card description</p>
      <div className={styles.buttonGroup}>
        <button className={styles.button}>Action</button>
      </div>
    </div>
  )
}

Standalone SCSS File

// styles/dashboard.scss
@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.dashboard {
  @include grid(4);
  gap: $space-6;
  padding: $space-8;
  background-color: $bg-secondary;
  min-height: 100vh;
}

.dashboardCard {
  @include card;
  padding: $space-6;
  
  &:hover {
    @include elevation(3);
  }
  
  @include breakpoint-md {
    @include grid(2);
  }
  
  @include breakpoint-sm {
    @include grid(1);
  }
}

.cardTitle {
  @include heading-4;
  color: $color-primary;
  margin-bottom: $space-4;
}

.cardValue {
  @include text-xl;
  font-weight: $font-weight-bold;
  color: $fg-primary;
  margin-bottom: $space-2;
}

.cardMetric {
  @include text-sm;
  color: $fg-secondary;
}

Creating Custom Components

Form Input Component

// styles/components/_form-input.scss
@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.formInput {
  @include input-base;
  
  &-wrapper {
    margin-bottom: $space-6;
  }
  
  &-label {
    display: block;
    margin-bottom: $space-2;
    font-weight: $font-weight-medium;
    color: $fg-primary;
  }
  
  &-helper {
    display: block;
    margin-top: $space-1;
    font-size: $font-size-xs;
    color: $fg-tertiary;
  }
  
  &.error {
    border-color: $color-error;
    
    .formInput-helper {
      color: $color-error;
    }
  }
  
  &.success {
    border-color: $color-success;
    
    .formInput-helper {
      color: $color-success;
    }
  }
}

Data Table Component

// styles/components/_data-table.scss
@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.dataTable {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: $space-6;
  
  &-header {
    background-color: $color-neutral-100;
    
    th {
      padding: $space-4;
      text-align: left;
      font-weight: $font-weight-semibold;
      color: $fg-primary;
      border-bottom: 2px solid $color-neutral-300;
    }
  }
  
  &-body {
    tr {
      transition: background-color $transition-base;
      
      &:hover {
        background-color: $color-neutral-50;
      }
      
      &:nth-child(even) {
        background-color: $color-neutral-50;
      }
    }
    
    td {
      padding: $space-4;
      border-bottom: 1px solid $color-neutral-200;
      color: $fg-primary;
    }
  }
}

Modal Overlay Component

// styles/components/_modal.scss
@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.modalBackdrop {
  @include position-absolute(0, 0, 0, 0);
  background-color: color.change(#000000, $alpha: 0.5);
  z-index: $z-modal-backdrop;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal {
  background-color: $bg-primary;
  border-radius: $radius-lg;
  box-shadow: $shadow-2xl;
  z-index: $z-modal;
  padding: $space-8;
  max-width: 500px;
  width: 90%;
  
  @include breakpoint-md {
    width: 100%;
  }
  
  &-header {
    margin-bottom: $space-6;
    border-bottom: 1px solid $color-neutral-200;
    padding-bottom: $space-4;
    
    h2 {
      margin: 0;
      @include heading-2;
    }
  }
  
  &-body {
    margin-bottom: $space-6;
  }
  
  &-footer {
    @include flex-between;
    gap: $space-4;
    border-top: 1px solid $color-neutral-200;
    padding-top: $space-4;
  }
}

Responsive Design

Mobile-First Approach

@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

.responsiveLayout {
  // Mobile-first: default to 1 column
  @include grid(1);
  gap: $space-4;
  padding: $space-4;
  
  // Tablet: 2 columns
  @include breakpoint-md {
    @include grid(2);
    gap: $space-6;
    padding: $space-6;
  }
  
  // Desktop: 3 columns
  @include breakpoint-lg {
    @include grid(3);
    gap: $space-8;
    padding: $space-8;
  }
  
  // Large desktop: 4 columns
  @include breakpoint-xl {
    @include grid(4);
  }
}

.responsiveText {
  // Mobile: small font
  font-size: $font-size-base;
  padding: $space-4;
  
  // Tablet: medium font
  @include breakpoint-md {
    font-size: $font-size-lg;
    padding: $space-6;
  }
  
  // Desktop: large font
  @include breakpoint-lg {
    font-size: $font-size-xl;
    padding: $space-8;
  }
}

.responsiveImage {
  max-width: 100%;
  height: auto;
  
  @include breakpoint-md {
    border-radius: $radius-lg;
    @include elevation(2);
  }
  
  @include breakpoint-lg {
    border-radius: $radius-2xl;
    @include elevation(3);
  }
}

Theme Switching

In JavaScript

// Switch to dark theme
document.documentElement.setAttribute('data-theme', 'dark')

// Switch to light theme
document.documentElement.removeAttribute('data-theme')
// or
document.documentElement.setAttribute('data-theme', 'light')

// Get current theme
const currentTheme = document.documentElement.getAttribute('data-theme')

// Check system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
if (prefersDark) {
  document.documentElement.setAttribute('data-theme', 'dark')
}

In React

import { useEffect, useState } from 'react'

export function ThemeToggle() {
  const [theme, setTheme] = useState<'light' | 'dark'>('light')
  
  useEffect(() => {
    const root = document.documentElement
    if (theme === 'dark') {
      root.setAttribute('data-theme', 'dark')
    } else {
      root.removeAttribute('data-theme')
    }
  }, [theme])
  
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      {theme === 'light' ? '🌙 Dark' : '☀️ Light'}
    </button>
  )
}

Using CSS Variables

.themeAwareElement {
  background-color: var(--bg-primary);
  color: var(--fg-primary);
  font-family: var(--font-family-body);
  transition: background-color var(--transition-base);
}

.themeAwareBorder {
  border-color: var(--color-neutral-300);
}

[data-theme='dark'] .themeAwareBorder {
  border-color: var(--color-neutral-700);
}

Advanced Techniques

Extending Mixins

@use '@/styles/variables' as *;
@use '@/styles/mixins' as *;

// Custom button with additional styling
@mixin btn-custom {
  @include btn-primary;
  border-radius: $radius-full;
  padding: $space-3 $space-6;
  font-weight: $font-weight-semibold;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.customButton {
  @include btn-custom;
}

Creating Color Variants

@use '@/styles/variables' as *;

@mixin card-variant($bg-color, $border-color) {
  background-color: $bg-color;
  border: 2px solid $border-color;
  padding: $space-6;
  border-radius: $radius-lg;
}

.card-success {
  @include card-variant(
    oklch(0.93 0.12 149.47),  // Light green
    $color-success
  );
}

.card-warning {
  @include card-variant(
    oklch(0.95 0.15 70.08),   // Light yellow
    $color-warning
  );
}

.card-error {
  @include card-variant(
    oklch(0.92 0.2 25.39),    // Light red
    $color-error
  );
}

Dynamic Spacing Loop

@use '@/styles/variables' as *;

// Create responsive spacing utilities
.spacing {
  @for $i from 1 through 6 {
    $value: $space-4 * $i;
    
    &-#{$i} {
      padding: $value;
    }
    
    @include breakpoint-md {
      &-md-#{$i} {
        padding: $value * 1.5;
      }
    }
    
    @include breakpoint-lg {
      &-lg-#{$i} {
        padding: $value * 2;
      }
    }
  }
}

Conditional Color Adjustments

@use 'sass:color' as *;
@use '@/styles/variables' as *;

.accentElement {
  background-color: $color-primary;
  
  @media (prefers-contrast: more) {
    // Increase contrast for high contrast mode
    background-color: change-color($color-primary, $lightness: 40%);
    color: #ffffff;
  }
}

Best Practices

✓ Always use variables instead of hardcoded values
✓ Use mixins for frequently used patterns
✓ Keep components responsive with breakpoint mixins
✓ Test color accessibility
✓ Use CSS variables for runtime theme switching
✓ Document custom mixins and variables
✓ Keep nesting 3 levels deep maximum
✓ Use meaningful class names


See SASS_CONFIGURATION.md for comprehensive reference.