# Apex Admins — Component Library

**Version:** 1.0  
**Date:** 2026-06-27  
**Location:** `resources/views/components/`

---

## Layout Components

| Component | Path | Props |
|-----------|------|-------|
| `x-layout.app` | `layouts/app.blade.php` | title, seo, schema |
| `x-layout.admin` | `admin/layouts/app.blade.php` | title, breadcrumbs |
| `x-header` | `components/header.blade.php` | menu, settings, sticky |
| `x-footer` | `components/footer.blade.php` | menu, settings |
| `x-mobile-nav` | `components/mobile-nav.blade.php` | menu, open (Alpine) |
| `x-breadcrumbs` | `components/breadcrumbs.blade.php` | items[] |
| `x-sticky-cta` | `components/sticky-cta.blade.php` | text, url, enabled |
| `x-floating-contact` | `components/floating-contact.blade.php` | phone, email, enabled |

---

## Marketing Sections (Page Builder)

Each section accepts `$data` array from page `sections` JSON.

| Component | Path | Key Props |
|-----------|------|-----------|
| `x-sections.hero` | `sections/hero.blade.php` | headline, subheadline, cta_primary, cta_secondary, image_id, badge |
| `x-sections.trusted-logos` | `sections/trusted-logos.blade.php` | logos[] (media_id) |
| `x-sections.why-us` | `sections/why-us.blade.php` | title, items[]{icon, title, description} |
| `x-sections.staff-grid` | `sections/staff-grid.blade.php` | title, services[] or limit |
| `x-sections.ai-services` | `sections/ai-services.blade.php` | title, services[] |
| `x-sections.featured-talent` | `sections/featured-talent.blade.php` | title, roles[] |
| `x-sections.industries-grid` | `sections/industries-grid.blade.php` | title, industries[] |
| `x-sections.case-studies-carousel` | `sections/case-studies-carousel.blade.php` | title, case_studies[] |
| `x-sections.process-steps` | `sections/process-steps.blade.php` | title, steps[]{number, title, description} |
| `x-sections.testimonials` | `sections/testimonials.blade.php` | title, testimonials[] |
| `x-sections.faq` | `sections/faq.blade.php` | title, items[]{question, answer} |
| `x-sections.final-cta` | `sections/final-cta.blade.php` | title, description, cta_text, cta_url |
| `x-sections.stats-counter` | `sections/stats-counter.blade.php` | stats[]{value, suffix, label} |
| `x-sections.comparison-table` | `sections/comparison-table.blade.php` | columns[], rows[] |
| `x-sections.lead-magnet` | `sections/lead-magnet.blade.php` | title, form_slug, image_id |
| `x-sections.rich-text` | `sections/rich-text.blade.php` | content (HTML) |
| `x-sections.two-column` | `sections/two-column.blade.php` | left, right, reverse |
| `x-sections.video-embed` | `sections/video-embed.blade.php` | url, title, poster_id |

### Section Renderer

```blade
@foreach($page->sections as $section)
    <x-dynamic-component :component="'sections.'.$section['type']" :data="$section['data']" />
@endforeach
```

---

## UI Primitives

| Component | Path | Props |
|-----------|------|-------|
| `x-ui.button` | `ui/button.blade.php` | variant, href, type, size |
| `x-ui.card` | `ui/card.blade.php` | class, hover |
| `x-ui.badge` | `ui/badge.blade.php` | variant |
| `x-ui.input` | `ui/input.blade.php` | name, label, error, type |
| `x-ui.select` | `ui/select.blade.php` | name, label, options |
| `x-ui.textarea` | `ui/textarea.blade.php` | name, label, rows |
| `x-ui.modal` | `ui/modal.blade.php` | name (Alpine), title |
| `x-ui.accordion` | `ui/accordion.blade.php` | items[] |
| `x-ui.tabs` | `ui/tabs.blade.php` | tabs[] |
| `x-ui.progress-bar` | `ui/progress-bar.blade.php` | value, max |
| `x-ui.toast` | `ui/toast.blade.php` | — (Alpine store) |
| `x-ui.skeleton` | `ui/skeleton.blade.php` | class |

### Button Variants
`primary`, `secondary`, `ghost`, `dark`, `danger`  
Sizes: `sm`, `md`, `lg`

---

## Form Components

| Component | Path | Props |
|-----------|------|-------|
| `x-forms.multistep` | `forms/multistep.blade.php` | form, steps |
| `x-forms.field` | `forms/field.blade.php` | field definition |
| `x-forms.honeypot` | `forms/honeypot.blade.php` | — |
| `x-forms.file-upload` | `forms/file-upload.blade.php` | name, accept |
| `x-forms.calendly-embed` | `forms/calendly-embed.blade.php` | url |

---

## SEO Components

| Component | Path | Props |
|-----------|------|-------|
| `x-seo.meta` | `seo/meta.blade.php` | seo object |
| `x-seo.json-ld` | `seo/json-ld.blade.php` | schema[] |
| `x-seo.og-tags` | `seo/og-tags.blade.php` | seo object |
| `x-admin.seo-panel` | `admin/seo-panel.blade.php` | auditable |

---

## Media Components

| Component | Path | Props |
|-----------|------|-------|
| `x-media.image` | `media/image.blade.php` | media, sizes, lazy, class |
| `x-media.picture` | `media/picture.blade.php` | media, alt, sizes (WebP/AVIF) |

---

## Animation Wrappers

| Component | Path | Props |
|-----------|------|-------|
| `x-animate.counter` | `animate/counter.blade.php` | value, duration, suffix |
| `x-animate.scroll-reveal` | `animate/scroll-reveal.blade.php` | children, delay |
| `x-animate.swiper-carousel` | `animate/swiper-carousel.blade.php` | slides, options |

### JS Initialization (`resources/js/app.js`)
```js
import Alpine from 'alpinejs';
import { initGsap } from './gsap';
import { initSwipers } from './swiper';
import { initAnalytics } from './analytics';

document.addEventListener('DOMContentLoaded', () => {
    initGsap();
    initSwipers();
    initAnalytics();
});
Alpine.start();
```

---

## Admin Components

| Component | Path |
|-----------|------|
| `x-admin.layout` | `admin/layouts/app.blade.php` |
| `x-admin.sidebar` | `admin/sidebar.blade.php` |
| `x-admin.media-picker` | `admin/media-picker.blade.php` |
| `x-admin.section-builder` | `admin/section-builder.blade.php` |
| `x-admin.seo-fields` | `admin/seo-fields.blade.php` |

---

## Naming Conventions

- Public components: kebab-case folders, dot notation in Blade
- Props: camelCase in PHP, kebab-case in Blade attributes
- All components accept `class` merge via `$attributes->merge()`
