First commit
This commit is contained in:
commit
7cf3558ba7
12933 changed files with 1180047 additions and 0 deletions
563
packages/flux-cms/README.md
Normal file
563
packages/flux-cms/README.md
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
# Flux CMS - Laravel Package Suite
|
||||
|
||||
🚀 **Modern, component-first CMS for Laravel with multi-domain support**
|
||||
|
||||
[](https://packagist.org/packages/flux-cms/core)
|
||||
[](LICENSE.md)
|
||||
[](https://packagist.org/packages/flux-cms/core)
|
||||
|
||||
## Overview
|
||||
|
||||
Flux CMS is a powerful, modern Content Management System built specifically for Laravel applications. It features a revolutionary "Code-as-Schema" approach where content structure is defined directly in PHP components, offering unprecedented flexibility and developer experience.
|
||||
|
||||
### 🎯 Key Features
|
||||
|
||||
- **🧩 Component-First Architecture** - Build pages from reusable Livewire components
|
||||
- **📝 Code-as-Schema** - Define fields in PHP, not in databases
|
||||
- **🌍 Multi-Domain Support** - Manage multiple websites from one installation
|
||||
- **🗣️ Full Multilingual** - Everything is translatable with fallbacks
|
||||
- **📦 Versioning** - Automatic content versioning and rollback
|
||||
- **🎨 Media Management** - Integrated media library with automatic conversions
|
||||
- **⚡ Performance** - Optimized queries and smart caching
|
||||
- **🔒 Secure** - Built-in security best practices
|
||||
|
||||
## Package Architecture
|
||||
|
||||
Flux CMS is split into modular packages for maximum flexibility:
|
||||
|
||||
### Core Packages
|
||||
|
||||
| Package | Description | Installation |
|
||||
|---------|-------------|--------------|
|
||||
| **flux-cms/core** | Core models, services, and field types | `composer require flux-cms/core` |
|
||||
| **flux-cms/components** | Livewire backend and frontend components | `composer require flux-cms/components` |
|
||||
| **flux-cms/starter-components** | Ready-to-use starter components | `composer require flux-cms/starter-components` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Installation
|
||||
|
||||
```bash
|
||||
# Install core package
|
||||
composer require flux-cms/core
|
||||
|
||||
# Install components (optional but recommended)
|
||||
composer require flux-cms/components flux-cms/starter-components
|
||||
|
||||
# Install and setup
|
||||
php artisan flux-cms:install
|
||||
```
|
||||
|
||||
### 2. Basic Configuration
|
||||
|
||||
```php
|
||||
// config/flux-cms.php
|
||||
return [
|
||||
'locales' => [
|
||||
'de' => 'Deutsch',
|
||||
'en' => 'English',
|
||||
],
|
||||
'component_paths' => [
|
||||
'App\\Livewire\\Components',
|
||||
'FluxCms\\StarterComponents\\Components',
|
||||
],
|
||||
'domains' => [
|
||||
'enabled' => true,
|
||||
'config_source' => 'domains', // Use existing config/domains.php
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
### 3. Create Your First Component
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Components;
|
||||
|
||||
use Livewire\Component;
|
||||
use FluxCms\Core\FieldTypes\TextField;
|
||||
use FluxCms\Core\FieldTypes\WysiwygField;
|
||||
use FluxCms\Core\FieldTypes\MediaField;
|
||||
|
||||
class FeatureSection extends Component
|
||||
{
|
||||
public array $content = [];
|
||||
|
||||
public function mount(array $content = [])
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public static function getCmsName(): string
|
||||
{
|
||||
return 'Feature Section';
|
||||
}
|
||||
|
||||
public static function getCmsDescription(): string
|
||||
{
|
||||
return 'Showcase features with icons and descriptions';
|
||||
}
|
||||
|
||||
public static function getCmsCategory(): string
|
||||
{
|
||||
return 'Content';
|
||||
}
|
||||
|
||||
public static function getCmsFields(): array
|
||||
{
|
||||
return [
|
||||
TextField::make('headline', 'Headline')
|
||||
->translatable()
|
||||
->required()
|
||||
->maxLength(100),
|
||||
|
||||
WysiwygField::make('description', 'Description')
|
||||
->translatable()
|
||||
->toolbar(['bold', 'italic', 'link']),
|
||||
|
||||
MediaField::make('icon', 'Icon')
|
||||
->images()
|
||||
->helpText('SVG or PNG icon'),
|
||||
];
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('components.feature-section');
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
protected function getHeadline(?string $locale = null): string
|
||||
{
|
||||
$locale = $locale ?? app()->getLocale();
|
||||
return $this->content['headline'][$locale] ?? '';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Create the Blade Template
|
||||
|
||||
```blade
|
||||
{{-- resources/views/components/feature-section.blade.php --}}
|
||||
<section class="feature-section py-12">
|
||||
<div class="container mx-auto px-4">
|
||||
@if($this->getHeadline())
|
||||
<h2 class="text-3xl font-bold text-center mb-8">
|
||||
{{ $this->getHeadline() }}
|
||||
</h2>
|
||||
@endif
|
||||
|
||||
@if($this->getDescription())
|
||||
<div class="prose prose-lg mx-auto text-center">
|
||||
{!! $this->getDescription() !!}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Multi-Domain Setup
|
||||
|
||||
```php
|
||||
// Automatic domain detection from existing config/domains.php
|
||||
$page = Page::forDomain('b2in')->bySlug('/about', 'en')->first();
|
||||
|
||||
// Create domain-specific content
|
||||
$page = Page::create([
|
||||
'domain_key' => 'b2in',
|
||||
'title' => ['de' => 'Über uns', 'en' => 'About us'],
|
||||
'is_published' => true,
|
||||
]);
|
||||
|
||||
$page->slugs()->create(['locale' => 'de', 'slug' => '/ueber-uns']);
|
||||
$page->slugs()->create(['locale' => 'en', 'slug' => '/about']);
|
||||
```
|
||||
|
||||
### Component Registry
|
||||
|
||||
```php
|
||||
// Get all available components
|
||||
$registry = app(ComponentRegistry::class);
|
||||
$components = $registry->getAvailableComponents();
|
||||
|
||||
// Search components
|
||||
$results = $registry->searchComponents('hero');
|
||||
|
||||
// Get by category
|
||||
$layoutComponents = $registry->getComponentsByCategory()['Layout'];
|
||||
|
||||
// Validate component content
|
||||
$errors = $registry->validateComponentContent(HeroSection::class, $content);
|
||||
```
|
||||
|
||||
### Custom Field Types
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\FieldTypes;
|
||||
|
||||
use FluxCms\Core\FieldTypes\BaseField;
|
||||
|
||||
class ColorField extends BaseField
|
||||
{
|
||||
public function getType(): string
|
||||
{
|
||||
return 'color';
|
||||
}
|
||||
|
||||
public function getValidationRules(): array
|
||||
{
|
||||
$rules = ['string', 'regex:/^#[0-9A-Fa-f]{6}$/'];
|
||||
|
||||
if ($this->required) {
|
||||
$rules[] = 'required';
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->getType(),
|
||||
'key' => $this->key,
|
||||
'label' => $this->label,
|
||||
'translatable' => $this->translatable,
|
||||
'required' => $this->required,
|
||||
'default' => $this->default,
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Versioning
|
||||
|
||||
```php
|
||||
// Create version before major changes
|
||||
$page->createVersion('Redesign homepage layout', auth()->id());
|
||||
|
||||
// Restore previous version
|
||||
$version = $page->versions()->first();
|
||||
$version->restore();
|
||||
|
||||
// Compare versions
|
||||
$differences = $version->getDifferences();
|
||||
```
|
||||
|
||||
## Field Types
|
||||
|
||||
Flux CMS includes powerful field types out of the box:
|
||||
|
||||
### Text Fields
|
||||
```php
|
||||
TextField::make('title', 'Title')
|
||||
->translatable()
|
||||
->required()
|
||||
->maxLength(100)
|
||||
->placeholder('Enter title...');
|
||||
|
||||
TextField::make('email', 'Email')
|
||||
->email()
|
||||
->required();
|
||||
|
||||
TextField::make('website', 'Website')
|
||||
->url();
|
||||
```
|
||||
|
||||
### Content Fields
|
||||
```php
|
||||
WysiwygField::make('content', 'Content')
|
||||
->translatable()
|
||||
->toolbar(['bold', 'italic', 'link', 'bulletList'])
|
||||
->allowImages(true)
|
||||
->minHeight(300);
|
||||
```
|
||||
|
||||
### Media Fields
|
||||
```php
|
||||
MediaField::make('image', 'Image')
|
||||
->images()
|
||||
->required();
|
||||
|
||||
MediaField::make('gallery', 'Gallery')
|
||||
->images()
|
||||
->multiple(true, 10);
|
||||
|
||||
MediaField::make('document', 'Document')
|
||||
->documents()
|
||||
->maxFileSize(5120); // 5MB
|
||||
```
|
||||
|
||||
### Selection Fields
|
||||
```php
|
||||
SelectField::make('layout', 'Layout')
|
||||
->options([
|
||||
'left' => 'Image Left',
|
||||
'right' => 'Image Right',
|
||||
'center' => 'Centered'
|
||||
])
|
||||
->default('left')
|
||||
->searchable();
|
||||
```
|
||||
|
||||
### Other Fields
|
||||
```php
|
||||
NumberField::make('count', 'Count')
|
||||
->min(1)
|
||||
->max(100)
|
||||
->default(5);
|
||||
|
||||
BooleanField::make('featured', 'Featured')
|
||||
->default(false)
|
||||
->labels('Yes', 'No');
|
||||
```
|
||||
|
||||
## Frontend Integration
|
||||
|
||||
### Page Controller
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use FluxCms\Core\Models\Page;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function show(Request $request, string $slug = '/')
|
||||
{
|
||||
$domainKey = $this->getCurrentDomainKey($request);
|
||||
$locale = app()->getLocale();
|
||||
|
||||
$page = Page::forDomain($domainKey)
|
||||
->bySlugWithFallback($slug)
|
||||
->published()
|
||||
->with(['components'])
|
||||
->firstOrFail();
|
||||
|
||||
$components = $page->components()->get();
|
||||
|
||||
return view('pages.show', compact('page', 'components'));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Page Template
|
||||
|
||||
```blade
|
||||
{{-- resources/views/pages/show.blade.php --}}
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', $page->getSeoTitle())
|
||||
@section('description', $page->getSeoDescription())
|
||||
|
||||
@section('content')
|
||||
@foreach($components as $component)
|
||||
@if($component->canRender())
|
||||
@livewire($component->component_class, [
|
||||
'content' => $component->getTranslations('content')
|
||||
], key('component-' . $component->id))
|
||||
@endif
|
||||
@endforeach
|
||||
@endsection
|
||||
```
|
||||
|
||||
## Backend Integration
|
||||
|
||||
### Admin Routes
|
||||
|
||||
```php
|
||||
// routes/admin.php
|
||||
Route::middleware(['web', 'auth'])->prefix('admin/cms')->name('admin.cms.')->group(function () {
|
||||
Route::get('/', [Admin\DashboardController::class, 'index'])->name('index');
|
||||
Route::resource('pages', Admin\PageController::class)->except(['show']);
|
||||
// ... other admin routes
|
||||
});
|
||||
```
|
||||
|
||||
### Admin Controller
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use FluxCms\Core\Models\Page;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PageController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$pages = Page::with(['components'])
|
||||
->orderBy('updated_at', 'desc')
|
||||
->paginate(20);
|
||||
|
||||
return view('admin.cms.pages.index', compact('pages'));
|
||||
}
|
||||
|
||||
public function edit(Page $page)
|
||||
{
|
||||
return view('admin.cms.pages.edit', compact('page'));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Edit Page Template
|
||||
|
||||
```blade
|
||||
{{-- resources/views/admin/cms/edit.blade.php --}}
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('content')
|
||||
@livewire('flux-cms::page-editor', ['page' => $page])
|
||||
@endsection
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Available Locales
|
||||
|
||||
```php
|
||||
// config/flux-cms.php
|
||||
'locales' => [
|
||||
'de' => 'Deutsch',
|
||||
'en' => 'English',
|
||||
'fr' => 'Français',
|
||||
'es' => 'Español',
|
||||
],
|
||||
```
|
||||
|
||||
### Component Paths
|
||||
|
||||
```php
|
||||
'component_paths' => [
|
||||
'App\\Livewire\\Components',
|
||||
'App\\CmsComponents',
|
||||
'FluxCms\\StarterComponents\\Components',
|
||||
],
|
||||
```
|
||||
|
||||
### Media Configuration
|
||||
|
||||
```php
|
||||
'media' => [
|
||||
'disk' => 'public',
|
||||
'max_file_size' => 10240, // 10MB
|
||||
'conversions' => [
|
||||
'thumb' => ['width' => 300, 'height' => 300],
|
||||
'medium' => ['width' => 800, 'height' => 600],
|
||||
'large' => ['width' => 1200, 'height' => 900],
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Install Flux CMS
|
||||
php artisan flux-cms:install
|
||||
|
||||
# Create a new component (in app/Livewire/Web/Components)
|
||||
php artisan flux-cms:make-component MyNewComponent
|
||||
|
||||
# Clear component registry cache
|
||||
php artisan flux-cms:clear-cache
|
||||
|
||||
# Publish package assets
|
||||
php artisan vendor:publish --tag=flux-cms
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run tests from the root of your project
|
||||
./vendor/bin/pest
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
- **XSS Protection**: All user content is sanitized
|
||||
- **CSRF Protection**: All forms include CSRF tokens
|
||||
- **File Upload Security**: MIME type validation and file scanning
|
||||
- **Permission System**: Integration with Spatie Laravel Permission
|
||||
|
||||
## Performance
|
||||
|
||||
- **Component Registry Caching**: Components are cached for fast lookup
|
||||
- **Eager Loading**: Optimized database queries
|
||||
- **Asset Optimization**: Automatic image conversions
|
||||
- **Query Caching**: Smart caching for frequently accessed data
|
||||
|
||||
## Upgrade Guide
|
||||
|
||||
### From Dev Version to Package
|
||||
|
||||
1. Install packages:
|
||||
```bash
|
||||
composer require flux-cms/core flux-cms/components flux-cms/starter-components
|
||||
```
|
||||
|
||||
2. Migrate existing components:
|
||||
```bash
|
||||
# Copy your existing components to app/Livewire/Components/
|
||||
# Update namespaces and field imports
|
||||
```
|
||||
|
||||
3. Update configuration:
|
||||
```bash
|
||||
php artisan vendor:publish --tag=flux-cms-config
|
||||
```
|
||||
|
||||
4. Run migrations:
|
||||
```bash
|
||||
php artisan migrate
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
||||
|
||||
### Development Setup
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/flux-cms/flux-cms.git
|
||||
|
||||
# Install dependencies
|
||||
composer install
|
||||
|
||||
# Run tests
|
||||
composer test
|
||||
|
||||
# Code style
|
||||
composer format
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Flux CMS is open-sourced software licensed under the [MIT license](LICENSE.md).
|
||||
|
||||
## Support
|
||||
|
||||
- 📖 **Documentation**: [https://flux-cms.com/docs](https://flux-cms.com/docs)
|
||||
- 💬 **Discussions**: [GitHub Discussions](https://github.com/flux-cms/flux-cms/discussions)
|
||||
- 🐛 **Issues**: [GitHub Issues](https://github.com/flux-cms/flux-cms/issues)
|
||||
- 💌 **Email**: support@flux-cms.com
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- Built with [Laravel](https://laravel.com)
|
||||
- Powered by [Livewire](https://laravel-livewire.com)
|
||||
- Uses [Spatie packages](https://spatie.be/open-source)
|
||||
- UI with [Flux UI](https://fluxui.dev)
|
||||
|
||||
---
|
||||
|
||||
Made with ❤️ by the Flux CMS team
|
||||
Loading…
Add table
Add a link
Reference in a new issue