Update project dependencies and configuration

- Added Filament and Tailwind CSS dependencies in composer.json.
- Updated AGENTS.md to include new package versions.
- Modified boost.json to include tailwindcss-development skill.
- Updated DatabaseSeeder to create an admin user with a password.
- Changed the root route to use HomeController instead of a closure.
- Adjusted permissions for .gitignore in storage directory.
This commit is contained in:
Mekan1206
2026-06-04 21:30:06 +05:00
parent 608876864b
commit b13d61b342
128 changed files with 7221 additions and 223 deletions

View File

@@ -0,0 +1,119 @@
---
name: tailwindcss-development
description: "Always invoke when the user's message includes 'tailwind' in any form. Also invoke for: building responsive grid layouts (multi-column card grids, product grids), flex/grid page structures (dashboards with sidebars, fixed topbars, mobile-toggle navs), styling UI components (cards, tables, navbars, pricing sections, forms, inputs, badges), adding dark mode variants, fixing spacing or typography, and Tailwind v3/v4 work. The core use case: writing or fixing Tailwind utility classes in HTML templates (Blade, JSX, Vue). Skip for backend PHP logic, database queries, API routes, JavaScript with no HTML/CSS component, CSS file audits, build tool configuration, and vanilla CSS."
license: MIT
metadata:
author: laravel
---
# Tailwind CSS Development
## Documentation
Use `search-docs` for detailed Tailwind CSS v4 patterns and documentation.
## Basic Usage
- Use Tailwind CSS classes to style HTML. Check and follow existing Tailwind conventions in the project before introducing new patterns.
- Offer to extract repeated patterns into components that match the project's conventions (e.g., Blade, JSX, Vue).
- Consider class placement, order, priority, and defaults. Remove redundant classes, add classes to parent or child elements carefully to reduce repetition, and group elements logically.
## Tailwind CSS v4 Specifics
- Always use Tailwind CSS v4 and avoid deprecated utilities.
- `corePlugins` is not supported in Tailwind v4.
### CSS-First Configuration
In Tailwind v4, configuration is CSS-first using the `@theme` directive — no separate `tailwind.config.js` file is needed:
<!-- CSS-First Config -->
```css
@theme {
--color-brand: oklch(0.72 0.11 178);
}
```
### Import Syntax
In Tailwind v4, import Tailwind with a regular CSS `@import` statement instead of the `@tailwind` directives used in v3:
<!-- v4 Import Syntax -->
```diff
- @tailwind base;
- @tailwind components;
- @tailwind utilities;
+ @import "tailwindcss";
```
### Replaced Utilities
Tailwind v4 removed deprecated utilities. Use the replacements shown below. Opacity values remain numeric.
| Deprecated | Replacement |
|------------|-------------|
| bg-opacity-* | bg-black/* |
| text-opacity-* | text-black/* |
| border-opacity-* | border-black/* |
| divide-opacity-* | divide-black/* |
| ring-opacity-* | ring-black/* |
| placeholder-opacity-* | placeholder-black/* |
| flex-shrink-* | shrink-* |
| flex-grow-* | grow-* |
| overflow-ellipsis | text-ellipsis |
| decoration-slice | box-decoration-slice |
| decoration-clone | box-decoration-clone |
## Spacing
Use `gap` utilities instead of margins for spacing between siblings:
<!-- Gap Utilities -->
```html
<div class="flex gap-8">
<div>Item 1</div>
<div>Item 2</div>
</div>
```
## Dark Mode
If existing pages and components support dark mode, new pages and components must support it the same way, typically using the `dark:` variant:
<!-- Dark Mode -->
```html
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
Content adapts to color scheme
</div>
```
## Common Patterns
### Flexbox Layout
<!-- Flexbox Layout -->
```html
<div class="flex items-center justify-between gap-4">
<div>Left content</div>
<div>Right content</div>
</div>
```
### Grid Layout
<!-- Grid Layout -->
```html
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>
```
## Common Pitfalls
- Using deprecated v3 utilities (bg-opacity-*, flex-shrink-*, etc.)
- Using `@tailwind` directives instead of `@import "tailwindcss"`
- Trying to use `tailwind.config.js` instead of CSS `@theme` directive
- Using margins for spacing between siblings instead of gap utilities
- Forgetting to add dark mode variants when the project uses dark mode

View File

@@ -10,14 +10,17 @@ The Laravel Boost guidelines are specifically curated by Laravel maintainers for
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.3
- filament/filament (FILAMENT) - v5
- laravel/framework (LARAVEL) - v13
- laravel/prompts (PROMPTS) - v0
- livewire/livewire (LIVEWIRE) - v4
- laravel/boost (BOOST) - v2
- laravel/mcp (MCP) - v0
- laravel/pail (PAIL) - v1
- laravel/pint (PINT) - v1
- pestphp/pest (PEST) - v4
- phpunit/phpunit (PHPUNIT) - v12
- tailwindcss (TAILWINDCSS) - v4
## Skills Activation

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Filament\Pages;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Schemas\Schema;
use Filament\Pages\SettingsPage;
use App\Settings\GeneralSettings as Settings;
class GeneralSettings extends SettingsPage
{
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-cog-6-tooth';
protected static string $settings = Settings::class;
public function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('marquee_text')
->required(),
TextInput::make('about_title')
->required(),
Textarea::make('about_text')
->required(),
FileUpload::make('about_image')
->image()
->visibility('public')
->directory('settings'),
Textarea::make('footer_address')
->required(),
TextInput::make('footer_phone')
->required(),
TextInput::make('footer_copyright')
->required(),
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\CarouselSlides;
use App\Filament\Resources\CarouselSlides\Pages\CreateCarouselSlide;
use App\Filament\Resources\CarouselSlides\Pages\EditCarouselSlide;
use App\Filament\Resources\CarouselSlides\Pages\ListCarouselSlides;
use App\Filament\Resources\CarouselSlides\Schemas\CarouselSlideForm;
use App\Filament\Resources\CarouselSlides\Tables\CarouselSlidesTable;
use App\Models\CarouselSlide;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class CarouselSlideResource extends Resource
{
protected static ?string $model = CarouselSlide::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CarouselSlideForm::configure($schema);
}
public static function table(Table $table): Table
{
return CarouselSlidesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListCarouselSlides::route('/'),
'create' => CreateCarouselSlide::route('/create'),
'edit' => EditCarouselSlide::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\CarouselSlides\Pages;
use App\Filament\Resources\CarouselSlides\CarouselSlideResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCarouselSlide extends CreateRecord
{
protected static string $resource = CarouselSlideResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CarouselSlides\Pages;
use App\Filament\Resources\CarouselSlides\CarouselSlideResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCarouselSlide extends EditRecord
{
protected static string $resource = CarouselSlideResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\CarouselSlides\Pages;
use App\Filament\Resources\CarouselSlides\CarouselSlideResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCarouselSlides extends ListRecords
{
protected static string $resource = CarouselSlideResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Filament\Resources\CarouselSlides\Schemas;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class CarouselSlideForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
FileUpload::make('image')
->image()
->visibility('public')
->required(),
TextInput::make('title'),
TextInput::make('subtitle'),
TextInput::make('order')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->default(true)
->required(),
]);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\CarouselSlides\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CarouselSlidesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image'),
TextColumn::make('title')
->searchable(),
TextColumn::make('subtitle')
->searchable(),
TextColumn::make('order')
->numeric()
->sortable(),
IconColumn::make('is_active')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Categories;
use App\Filament\Resources\Categories\Pages\CreateCategory;
use App\Filament\Resources\Categories\Pages\EditCategory;
use App\Filament\Resources\Categories\Pages\ListCategories;
use App\Filament\Resources\Categories\Schemas\CategoryForm;
use App\Filament\Resources\Categories\Tables\CategoriesTable;
use App\Models\Category;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class CategoryResource extends Resource
{
protected static ?string $model = Category::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CategoryForm::configure($schema);
}
public static function table(Table $table): Table
{
return CategoriesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListCategories::route('/'),
'create' => CreateCategory::route('/create'),
'edit' => EditCategory::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCategory extends CreateRecord
{
protected static string $resource = CategoryResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCategory extends EditRecord
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Categories\Pages;
use App\Filament\Resources\Categories\CategoryResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCategories extends ListRecords
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\Categories\Schemas;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class CategoryForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('icon'),
TextInput::make('order')
->required()
->numeric()
->default(0),
]);
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Filament\Resources\Categories\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CategoriesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('icon')
->searchable(),
TextColumn::make('order')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Collections;
use App\Filament\Resources\Collections\Pages\CreateCollection;
use App\Filament\Resources\Collections\Pages\EditCollection;
use App\Filament\Resources\Collections\Pages\ListCollections;
use App\Filament\Resources\Collections\Schemas\CollectionForm;
use App\Filament\Resources\Collections\Tables\CollectionsTable;
use App\Models\Collection;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class CollectionResource extends Resource
{
protected static ?string $model = Collection::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return CollectionForm::configure($schema);
}
public static function table(Table $table): Table
{
return CollectionsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListCollections::route('/'),
'create' => CreateCollection::route('/create'),
'edit' => EditCollection::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Collections\Pages;
use App\Filament\Resources\Collections\CollectionResource;
use Filament\Resources\Pages\CreateRecord;
class CreateCollection extends CreateRecord
{
protected static string $resource = CollectionResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Collections\Pages;
use App\Filament\Resources\Collections\CollectionResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditCollection extends EditRecord
{
protected static string $resource = CollectionResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Collections\Pages;
use App\Filament\Resources\Collections\CollectionResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListCollections extends ListRecords
{
protected static string $resource = CollectionResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Filament\Resources\Collections\Schemas;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class CollectionForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('title')
->required(),
TextInput::make('subtitle'),
FileUpload::make('image')
->image()
->visibility('public'),
TextInput::make('order')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->required(),
]);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\Collections\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CollectionsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('title')
->searchable(),
TextColumn::make('subtitle')
->searchable(),
ImageColumn::make('image'),
TextColumn::make('order')
->numeric()
->sortable(),
IconColumn::make('is_active')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Products\Pages;
use App\Filament\Resources\Products\ProductResource;
use Filament\Resources\Pages\CreateRecord;
class CreateProduct extends CreateRecord
{
protected static string $resource = ProductResource::class;
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Products\Pages;
use App\Filament\Resources\Products\ProductResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditProduct extends EditRecord
{
protected static string $resource = ProductResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Products\Pages;
use App\Filament\Resources\Products\ProductResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListProducts extends ListRecords
{
protected static string $resource = ProductResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Products;
use App\Filament\Resources\Products\Pages\CreateProduct;
use App\Filament\Resources\Products\Pages\EditProduct;
use App\Filament\Resources\Products\Pages\ListProducts;
use App\Filament\Resources\Products\Schemas\ProductForm;
use App\Filament\Resources\Products\Tables\ProductsTable;
use App\Models\Product;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class ProductResource extends Resource
{
protected static ?string $model = Product::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return ProductForm::configure($schema);
}
public static function table(Table $table): Table
{
return ProductsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListProducts::route('/'),
'create' => CreateProduct::route('/create'),
'edit' => EditProduct::route('/{record}/edit'),
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Filament\Resources\Products\Schemas;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class ProductForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('category_id')
->relationship('category', 'name')
->required(),
TextInput::make('name')
->required(),
Textarea::make('description')
->columnSpanFull(),
TextInput::make('price')
->required()
->numeric()
->prefix('$'),
FileUpload::make('image')
->image()
->visibility('public'),
Toggle::make('is_active')
->required(),
]);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Filament\Resources\Products\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class ProductsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('category.name')
->searchable(),
TextColumn::make('name')
->searchable(),
TextColumn::make('price')
->money()
->sortable(),
ImageColumn::make('image'),
IconColumn::make('is_active')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use App\Models\CarouselSlide;
use App\Models\Category;
use App\Models\Collection;
use App\Models\Product;
use App\Settings\GeneralSettings;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function __invoke(GeneralSettings $settings)
{
$slides = CarouselSlide::where('is_active', true)->orderBy('order')->get();
$collections = Collection::where('is_active', true)->orderBy('order')->get();
$categories = Category::orderBy('order')->get();
$products = Product::with('category')->where('is_active', true)->get();
return view('home', compact('slides', 'collections', 'categories', 'products', 'settings'));
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class CarouselSlide extends Model
{
protected $fillable = ['image', 'title', 'subtitle', 'order', 'is_active'];
protected static function booted(): void
{
static::deleting(function (CarouselSlide $slide) {
if ($slide->image) {
Storage::disk('public')->delete($slide->image);
}
});
}
}

16
app/Models/Category.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Category extends Model
{
protected $fillable = ['name', 'icon', 'order'];
public function products(): HasMany
{
return $this->hasMany(Product::class);
}
}

20
app/Models/Collection.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class Collection extends Model
{
protected $fillable = ['title', 'subtitle', 'image', 'order', 'is_active'];
protected static function booted(): void
{
static::deleting(function (Collection $collection) {
if ($collection->image) {
Storage::disk('public')->delete($collection->image);
}
});
}
}

26
app/Models/Product.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\Storage;
class Product extends Model
{
protected $fillable = ['category_id', 'name', 'description', 'price', 'image', 'is_active'];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
protected static function booted(): void
{
static::deleting(function (Product $product) {
if ($product->image) {
Storage::disk('public')->delete($product->image);
}
});
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Providers\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->login()
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
->widgets([
AccountWidget::class,
FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
PreventRequestForgery::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class GeneralSettings extends Settings
{
public string $marquee_text;
public string $about_title;
public string $about_text;
public string $about_image;
public string $footer_address;
public string $footer_phone;
public string $footer_copyright;
public static function group(): string
{
return 'general';
}
}

View File

@@ -10,6 +10,7 @@
"sail": false,
"skills": [
"laravel-best-practices",
"pest-testing"
"pest-testing",
"tailwindcss-development"
]
}

View File

@@ -1,7 +1,6 @@
<?php
use App\Providers\AppServiceProvider;
return [
AppServiceProvider::class,
App\Providers\AppServiceProvider::class,
App\Providers\Filament\AdminPanelProvider::class,
];

View File

@@ -3,15 +3,15 @@
"name": "laravel/laravel",
"type": "project",
"description": "The skeleton application for the Laravel framework.",
"keywords": [
"laravel",
"framework"
],
"keywords": ["laravel", "framework"],
"license": "MIT",
"require": {
"php": "^8.3",
"filament/filament": "^5.6",
"filament/spatie-laravel-settings-plugin": "*",
"laravel/framework": "^13.8",
"laravel/tinker": "^3.0"
"laravel/tinker": "^3.0",
"spatie/laravel-settings": "^3.9"
},
"require-dev": {
"fakerphp/faker": "^1.23",
@@ -55,7 +55,8 @@
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
"@php artisan package:discover --ansi",
"@php artisan filament:upgrade"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force",
@@ -89,4 +90,4 @@
},
"minimum-stability": "stable",
"prefer-stable": true
}
}

2728
composer.lock generated

File diff suppressed because it is too large Load Diff

137
config/filament.php Normal file
View File

@@ -0,0 +1,137 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Broadcasting
|--------------------------------------------------------------------------
|
| By uncommenting the Laravel Echo configuration, you may connect Filament
| to any Pusher-compatible websockets server.
|
| This will allow your users to receive real-time notifications.
|
*/
'broadcasting' => [
// 'echo' => [
// 'broadcaster' => 'pusher',
// 'key' => env('VITE_PUSHER_APP_KEY'),
// 'cluster' => env('VITE_PUSHER_APP_CLUSTER'),
// 'wsHost' => env('VITE_PUSHER_HOST'),
// 'wsPort' => env('VITE_PUSHER_PORT'),
// 'wssPort' => env('VITE_PUSHER_PORT'),
// 'authEndpoint' => '/broadcasting/auth',
// 'disableStats' => true,
// 'encrypted' => true,
// 'forceTLS' => env('VITE_PUSHER_SCHEME', 'https') === 'https',
// ],
],
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| This is the storage disk Filament will use to store files. You may use
| any of the disks defined in the `config/filesystems.php`.
|
*/
'default_filesystem_disk' => 'public',
/*
|--------------------------------------------------------------------------
| Temporary File URL Expiry
|--------------------------------------------------------------------------
|
| When Filament generates temporary URLs for previewing private files
| (file uploads, image columns, image entries, rich editor attachments,
| etc.), this value controls how many minutes those URLs remain valid.
|
| The generated URL's expiry is rounded up to the end of the hour it
| falls in, so the effective lifetime will be between this value and
| this value plus up to 60 minutes.
|
*/
'temporary_file_url_expiry_minutes' => 30,
/*
|--------------------------------------------------------------------------
| Assets Path
|--------------------------------------------------------------------------
|
| This is the directory where Filament's assets will be published to. It
| is relative to the `public` directory of your Laravel application.
|
| After changing the path, you should run `php artisan filament:assets`.
|
*/
'assets_path' => null,
/*
|--------------------------------------------------------------------------
| Cache Path
|--------------------------------------------------------------------------
|
| This is the directory that Filament will use to store cache files that
| are used to optimize the registration of components.
|
| After changing the path, you should run `php artisan filament:cache-components`.
|
*/
'cache_path' => base_path('bootstrap/cache/filament'),
/*
|--------------------------------------------------------------------------
| Livewire Loading Delay
|--------------------------------------------------------------------------
|
| This sets the delay before loading indicators appear.
|
| Setting this to 'none' makes indicators appear immediately, which can be
| desirable for high-latency connections. Setting it to 'default' applies
| Livewire's standard 200ms delay.
|
*/
'livewire_loading_delay' => 'default',
/*
|--------------------------------------------------------------------------
| File Generation
|--------------------------------------------------------------------------
|
| Artisan commands that generate files can be configured here by setting
| configuration flags that will impact their location or content.
|
| Often, this is useful to preserve file generation behavior from a
| previous version of Filament, to ensure consistency between older and
| newer generated files. These flags are often documented in the upgrade
| guide for the version of Filament you are upgrading to.
|
*/
'file_generation' => [
'flags' => [],
],
/*
|--------------------------------------------------------------------------
| System Route Prefix
|--------------------------------------------------------------------------
|
| This is the prefix used for the system routes that Filament registers,
| such as the routes for downloading exports and failed import rows.
|
*/
'system_route_prefix' => 'filament',
];

View File

@@ -0,0 +1,24 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create(config('settings.repositories.database.table') ?? 'settings', function (Blueprint $table): void {
$table->id();
$table->string('group');
$table->string('name');
$table->boolean('locked')->default(false);
$table->json('payload');
$table->timestamps();
$table->unique(['group', 'name']);
});
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('carousel_slides', function (Blueprint $table) {
$table->id();
$table->string('image');
$table->string('title')->nullable();
$table->string('subtitle')->nullable();
$table->integer('order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('carousel_slides');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('icon')->nullable();
$table->integer('order')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('collections', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('subtitle')->nullable();
$table->string('image')->nullable();
$table->integer('order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('collections');
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->foreignId('category_id')->constrained()->onDelete('cascade');
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 8, 2);
$table->string('image')->nullable();
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};

View File

@@ -5,6 +5,7 @@ namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
@@ -18,8 +19,9 @@ class DatabaseSeeder extends Seeder
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
'name' => 'Admin',
'email' => 'admin@example.com',
'password' => Hash::make('password'),
]);
}
}

View File

@@ -0,0 +1,17 @@
<?php
use Spatie\LaravelSettings\Migrations\SettingsMigration;
return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('general.marquee_text', 'Her gün täze bişirilen · Kiçi partýalarda taýýarlanylýar · Hünärmen iýmitçilik harytlary');
$this->migrator->add('general.about_title', 'Sabyr sungaty');
$this->migrator->add('general.about_text', 'Hoşal-da hakyky lýuksy wagtda görmek mümkin diýip hasaplaýarys. Peçimizden çykýan her kruassan üç gün dowam edýän jik-jik laminaasiýa prosesinden geçýär. Her tart gabygy dynýar, her krem sabyr bilen doldurylýar. Täzelikçi fransuz usullaryna esaslanýan, ýöne ýerli teýrwarlaryň ýyllygyndan ilham alýan patisseriamyz — öň biziňden öň gelen hünärmenlere hormatdyr.');
$this->migrator->add('general.about_image', '');
$this->migrator->add('general.footer_address', "Magtymguly şaýoly\nAşgabat, Türkmenistan");
$this->migrator->add('general.footer_phone', '+993 61 92 92 48');
$this->migrator->add('general.footer_copyright', '© 2026 Hoşal Patisserie. Hünärmençe döredilen.');
}
};

1614
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

316
public/assets/css/fonts.css Normal file
View File

@@ -0,0 +1,316 @@
/* cyrillic-ext */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../fonts/b4c084fa7b3b.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../fonts/292a2d96126e.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../fonts/4a49d9e68a9b.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../fonts/742139e4aed3.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Libre Franklin';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url(../fonts/eb92ff4bee5b.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/1164e5847032.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/84d684bf317e.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/51cb09f9398f.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/8092b1a96c6d.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/3c9a4dfed618.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/1164e5847032.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/84d684bf317e.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/51cb09f9398f.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/8092b1a96c6d.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
font-display: swap;
src: url(../fonts/3c9a4dfed618.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 600;
font-display: swap;
src: url(../fonts/711017585461.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 600;
font-display: swap;
src: url(../fonts/f690fa552832.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 600;
font-display: swap;
src: url(../fonts/a9bc00d9dd0f.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 600;
font-display: swap;
src: url(../fonts/ef5ca8ac661a.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url(../fonts/711017585461.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url(../fonts/f690fa552832.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url(../fonts/a9bc00d9dd0f.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url(../fonts/ef5ca8ac661a.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../fonts/73961b9b0d7b.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../fonts/49e0be96266a.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../fonts/f556cda9daa8.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(../fonts/9deeae77196a.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../fonts/73961b9b0d7b.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../fonts/49e0be96266a.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../fonts/f556cda9daa8.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(../fonts/9deeae77196a.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* fallback */
.material-symbols-outlined {
font-family: 'Material Symbols Outlined';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}
@font-face {
font-family: 'Material Symbols Outlined';
font-style: normal;
font-weight: 100 700;
font-display: swap;
src: url('../fonts/material-symbols.woff2') format('woff2');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

83
public/assets/js/tailwind.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-cyrillic-ext-wght-normal-IYF56FF6.woff2") format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-cyrillic-wght-normal-JEOLYBOO.woff2") format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-greek-ext-wght-normal-EOVOK2B5.woff2") format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-greek-wght-normal-IRE366VL.woff2") format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-vietnamese-wght-normal-CE5GGD3W.woff2") format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-latin-ext-wght-normal-HA22NDSG.woff2") format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url("./inter-latin-wght-normal-NRMW37G5.woff2") format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

View File

@@ -0,0 +1 @@
(()=>{var n=({livewireId:e})=>({actionNestingIndex:null,init(){window.addEventListener("sync-action-modals",t=>{t.detail.id===e&&this.syncActionModals(t.detail.newActionNestingIndex,t.detail.shouldOverlayParentActions??!1)})},syncActionModals(t,i=!1){if(this.actionNestingIndex===t){this.actionNestingIndex!==null&&this.$nextTick(()=>this.openModal());return}let s=this.actionNestingIndex!==null&&t!==null&&t>this.actionNestingIndex;if(this.actionNestingIndex!==null&&!(i&&s)&&this.closeModal(),this.actionNestingIndex=t,this.actionNestingIndex!==null){if(!this.$el.querySelector(`#${this.generateModalId(t)}`)){this.$nextTick(()=>this.openModal());return}this.openModal()}},generateModalId(t){return`fi-${e}-action-`+t},openModal(){let t=this.generateModalId(this.actionNestingIndex);document.dispatchEvent(new CustomEvent("open-modal",{bubbles:!0,composed:!0,detail:{id:t}}))},closeModal(){let t=this.generateModalId(this.actionNestingIndex);document.dispatchEvent(new CustomEvent("close-modal-quietly",{bubbles:!0,composed:!0,detail:{id:t}}))}});document.addEventListener("alpine:init",()=>{window.Alpine.data("filamentActionModals",n)});})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
function c({livewireId:s}){return{areAllCheckboxesChecked:!1,checkboxListOptions:[],search:"",unsubscribeLivewireHook:null,visibleCheckboxListOptions:[],init(){this.checkboxListOptions=Array.from(this.$root.querySelectorAll(".fi-fo-checkbox-list-option")),this.updateVisibleCheckboxListOptions(),this.$nextTick(()=>{this.checkIfAllCheckboxesAreChecked()}),this.unsubscribeLivewireHook=Livewire.interceptMessage(({message:e,onSuccess:t})=>{t(()=>{this.$nextTick(()=>{e.component.id===s&&(this.checkboxListOptions=Array.from(this.$root.querySelectorAll(".fi-fo-checkbox-list-option")),this.updateVisibleCheckboxListOptions(),this.checkIfAllCheckboxesAreChecked())})})}),this.$watch("search",()=>{this.updateVisibleCheckboxListOptions(),this.checkIfAllCheckboxesAreChecked()})},checkIfAllCheckboxesAreChecked(){this.areAllCheckboxesChecked=this.visibleCheckboxListOptions.length===this.visibleCheckboxListOptions.filter(e=>e.querySelector("input[type=checkbox]:checked, input[type=checkbox]:disabled")).length},toggleAllCheckboxes(){this.checkIfAllCheckboxesAreChecked();let e=!this.areAllCheckboxesChecked;this.visibleCheckboxListOptions.forEach(t=>{let i=t.querySelector("input[type=checkbox]");i.disabled||i.checked!==e&&(i.checked=e,i.dispatchEvent(new Event("change")))}),this.areAllCheckboxesChecked=e},updateVisibleCheckboxListOptions(){this.visibleCheckboxListOptions=this.checkboxListOptions.filter(e=>["",null,void 0].includes(this.search)||e.querySelector(".fi-fo-checkbox-list-option-label")?.innerText.toLowerCase().includes(this.search.toLowerCase())?!0:e.querySelector(".fi-fo-checkbox-list-option-description")?.innerText.toLowerCase().includes(this.search.toLowerCase()))},destroy(){this.unsubscribeLivewireHook?.()}}}export{c as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More