migrate template

This commit is contained in:
Mekan1206
2026-06-06 12:56:15 +05:00
parent e57fdfc2ad
commit 24b8539e98
135 changed files with 7586 additions and 237 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,111 @@
<?php
namespace App\Filament\Pages;
use App\Models\SiteSetting;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Schemas\Components\Form;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
class SiteSettingsPage extends Page
{
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCog6Tooth;
protected static ?string $navigationLabel = 'Sahypa sazlamalary';
protected static \UnitEnum|string|null $navigationGroup = null;
protected static ?int $navigationSort = 10;
protected string $view = 'filament.pages.site-settings-page';
/** @var array<string, mixed>|null */
public ?array $data = [];
public function mount(): void
{
$this->data = SiteSetting::pluck('value', 'key')->toArray();
$this->form->fill($this->data);
}
public function form(Schema $schema): Schema
{
return $schema
->statePath('data')
->components([
Form::make()
->schema([
Tabs::make()
->tabs([
Tabs\Tab::make('Kesimçiniň hekaýasy')
->schema([
TextInput::make('butchers_tale_title')
->label('Bölüm başlygy')
->required(),
Textarea::make('butchers_tale_body')
->label('Tekst')
->rows(5)
->columnSpanFull(),
FileUpload::make('butchers_tale_image')
->label('Surat (gollar)')
->image()
->disk('public')
->directory('settings')
->columnSpanFull(),
]),
Tabs\Tab::make('Footer')
->schema([
TextInput::make('footer_brand_name')
->label('Brend ady')
->required(),
TextInput::make('footer_copyright')
->label('Awtorlyk hukugy ýazgysy')
->required()
->columnSpanFull(),
TextInput::make('footer_address')
->label('Salgy'),
TextInput::make('footer_email')
->label('E-poçta')
->email(),
TextInput::make('footer_phone')
->label('Telefon')
->tel(),
]),
])
->columnSpanFull(),
])
->columnSpanFull(),
]);
}
public function save(): void
{
$state = $this->form->getState();
foreach ($state as $key => $value) {
SiteSetting::updateOrCreate(['key' => $key], ['value' => $value]);
}
Notification::make()
->title('Sazlamalar saklanyldy.')
->success()
->send();
}
protected function getHeaderActions(): array
{
return [
Action::make('save')
->label('Saklamak')
->action('save'),
];
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace App\Filament\Resources\Categories;
use App\Filament\Resources\Categories\Pages\ManageCategories;
use App\Models\Category;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class CategoryResource extends Resource
{
protected static ?string $model = Category::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedSquares2x2;
protected static ?string $navigationLabel = 'Kategoriýalar';
protected static string|\UnitEnum|null $navigationGroup = 'Harytlar';
protected static ?int $navigationSort = 1;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label('Ady')
->required()
->live(onBlur: true),
TextInput::make('slug')
->label('Slug')
->required()
->unique(ignoreRecord: true),
TextInput::make('icon')
->label('Material Symbol ikony')
->required()
->default('category')
->placeholder('set_meal'),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->label('Işjeň')
->default(true),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->label('Ady')
->searchable(),
TextColumn::make('slug')
->label('Slug')
->searchable(),
TextColumn::make('icon')
->label('Ikony'),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
IconColumn::make('is_active')
->label('Işjeň')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageCategories::route('/'),
];
}
}

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\ManageRecords;
class ManageCategories extends ManageRecords
{
protected static string $resource = CategoryResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,88 @@
<?php
namespace App\Filament\Resources\FooterNavLinks;
use App\Filament\Resources\FooterNavLinks\Pages\ManageFooterNavLinks;
use App\Models\FooterNavLink;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class FooterNavLinkResource extends Resource
{
protected static ?string $model = FooterNavLink::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedLink;
protected static ?string $navigationLabel = 'Footer baglanyşyklary';
protected static string|\UnitEnum|null $navigationGroup = 'Sahypa mazmunu';
protected static ?int $navigationSort = 4;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('label')
->label('Ýazgy')
->required(),
TextInput::make('url')
->label('URL')
->required()
->url(),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('label')
->label('Ýazgy')
->searchable(),
TextColumn::make('url')
->label('URL')
->searchable(),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageFooterNavLinks::route('/'),
];
}
}

View File

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

View File

@@ -0,0 +1,115 @@
<?php
namespace App\Filament\Resources\HeroSlides;
use App\Filament\Resources\HeroSlides\Pages\ManageHeroSlides;
use App\Models\HeroSlide;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class HeroSlideResource extends Resource
{
protected static ?string $model = HeroSlide::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedPhoto;
protected static ?string $navigationLabel = 'Hero Slaýdlary';
protected static string|\UnitEnum|null $navigationGroup = 'Sahypa mazmunu';
protected static ?int $navigationSort = 1;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('headline')
->label('Sözbaşy')
->required()
->columnSpanFull(),
Textarea::make('subheadline')
->label('Ikinji sözbaşy')
->rows(2)
->columnSpanFull(),
TextInput::make('cta_label')
->label('Düwme ýazgysy'),
TextInput::make('cta_url')
->label('Düwme URL')
->url(),
FileUpload::make('image')
->label('Surat')
->image()
->disk('public')
->directory('hero-slides')
->columnSpanFull(),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->label('Işjeň')
->default(true),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image')
->label('Surat')
->square(),
TextColumn::make('headline')
->label('Sözbaşy')
->searchable()
->limit(40),
TextColumn::make('cta_label')
->label('Düwme')
->searchable(),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
IconColumn::make('is_active')
->label('Işjeň')
->boolean(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageHeroSlides::route('/'),
];
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\HeroSlides\Pages;
use App\Filament\Resources\HeroSlides\HeroSlideResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ManageRecords;
class ManageHeroSlides extends ManageRecords
{
protected static string $resource = HeroSlideResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::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\ManageRecords;
class ManageProducts extends ManageRecords
{
protected static string $resource = ProductResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@@ -0,0 +1,172 @@
<?php
namespace App\Filament\Resources\Products;
use App\Filament\Resources\Products\Pages\ManageProducts;
use App\Models\Product;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
class ProductResource extends Resource
{
protected static ?string $model = Product::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedShoppingBag;
protected static ?string $navigationLabel = 'Harytlar';
protected static string|\UnitEnum|null $navigationGroup = 'Harytlar';
protected static ?int $navigationSort = 2;
public static function form(Schema $schema): Schema
{
return $schema
->components([
Select::make('category_id')
->label('Kategoriýa')
->relationship('category', 'name')
->required()
->searchable()
->preload(),
TextInput::make('name')
->label('Ady')
->required(),
TextInput::make('slug')
->label('Slug')
->required()
->unique(ignoreRecord: true),
TextInput::make('price')
->label('Bahasy')
->required()
->numeric()
->prefix('TMT'),
TextInput::make('price_unit')
->label('Baha birligi')
->required()
->default('kg')
->placeholder('kg, sany, gram'),
Select::make('availability_status')
->label('Elýeterliligi')
->required()
->options([
'available' => 'Elýeterli',
'out_of_season' => 'Möwsümden daşary',
'low_stock' => 'Az galdy',
])
->default('available'),
Textarea::make('description')
->label('Beýany')
->rows(3)
->columnSpanFull(),
FileUpload::make('image')
->label('Surat')
->image()
->disk('public')
->directory('products')
->columnSpanFull(),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->label('Işjeň')
->default(true),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image')
->label('Surat')
->square(),
TextColumn::make('name')
->label('Ady')
->searchable(),
TextColumn::make('category.name')
->label('Kategoriýa')
->badge()
->sortable(),
TextColumn::make('price')
->label('Bahasy')
->formatStateUsing(fn ($state) => number_format($state, 2).' TMT')
->sortable(),
TextColumn::make('price_unit')
->label('Birlik'),
TextColumn::make('availability_status')
->label('Elýeterliligi')
->badge()
->color(fn (string $state): string => match ($state) {
'available' => 'success',
'out_of_season' => 'warning',
'low_stock' => 'danger',
default => 'gray',
})
->formatStateUsing(fn (string $state): string => match ($state) {
'available' => 'Elýeterli',
'out_of_season' => 'Möwsümden daşary',
'low_stock' => 'Az galdy',
default => $state,
}),
IconColumn::make('is_active')
->label('Işjeň')
->boolean(),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([
SelectFilter::make('category')
->relationship('category', 'name')
->label('Kategoriýa'),
SelectFilter::make('availability_status')
->options([
'available' => 'Elýeterli',
'out_of_season' => 'Möwsümden daşary',
'low_stock' => 'Az galdy',
])
->label('Elýeterliligi'),
])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageProducts::route('/'),
];
}
}

View File

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

View File

@@ -0,0 +1,120 @@
<?php
namespace App\Filament\Resources\SignatureItems;
use App\Filament\Resources\SignatureItems\Pages\ManageSignatureItems;
use App\Models\SignatureItem;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\ImageColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class SignatureItemResource extends Resource
{
protected static ?string $model = SignatureItem::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedStar;
protected static ?string $navigationLabel = 'Aýratynlyklar';
protected static string|\UnitEnum|null $navigationGroup = 'Sahypa mazmunu';
protected static ?int $navigationSort = 2;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->label('Ady')
->required(),
TextInput::make('price')
->label('Bahasy')
->required()
->numeric()
->prefix('TMT'),
TextInput::make('price_unit')
->label('Baha birligi')
->required()
->default('kg'),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
Toggle::make('is_active')
->label('Işjeň')
->default(true),
Textarea::make('description')
->label('Beýany')
->rows(3)
->columnSpanFull(),
FileUpload::make('image')
->label('Surat')
->image()
->disk('public')
->directory('signature-items')
->columnSpanFull(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
ImageColumn::make('image')
->label('Surat')
->square(),
TextColumn::make('name')
->label('Ady')
->searchable(),
TextColumn::make('price')
->label('Bahasy')
->formatStateUsing(fn ($state) => number_format($state, 2).' TMT / ')
->sortable(),
TextColumn::make('price_unit')
->label('Birlik'),
IconColumn::make('is_active')
->label('Işjeň')
->boolean(),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageSignatureItems::route('/'),
];
}
}

View File

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

View File

@@ -0,0 +1,95 @@
<?php
namespace App\Filament\Resources\SocialLinks;
use App\Filament\Resources\SocialLinks\Pages\ManageSocialLinks;
use App\Models\SocialLink;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class SocialLinkResource extends Resource
{
protected static ?string $model = SocialLink::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedShare;
protected static ?string $navigationLabel = 'Sosial mediýa';
protected static string|\UnitEnum|null $navigationGroup = 'Sahypa mazmunu';
protected static ?int $navigationSort = 5;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('platform')
->label('Platforma')
->required()
->placeholder('Instagram'),
TextInput::make('url')
->label('URL')
->required(),
TextInput::make('icon')
->label('Material Symbol ikony')
->required()
->default('link')
->placeholder('photo_camera'),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('platform')
->label('Platforma')
->searchable(),
TextColumn::make('icon')
->label('Ikony'),
TextColumn::make('url')
->label('URL')
->searchable(),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageSocialLinks::route('/'),
];
}
}

View File

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

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Filament\Resources\TimelineEntries;
use App\Filament\Resources\TimelineEntries\Pages\ManageTimelineEntries;
use App\Models\TimelineEntry;
use BackedEnum;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class TimelineEntryResource extends Resource
{
protected static ?string $model = TimelineEntry::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedClock;
protected static ?string $navigationLabel = 'Taryh';
protected static string|\UnitEnum|null $navigationGroup = 'Sahypa mazmunu';
protected static ?int $navigationSort = 3;
public static function form(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('year')
->label('Ýyly')
->required()
->numeric()
->minValue(1900)
->maxValue(2100),
TextInput::make('title')
->label('Başlyk')
->required(),
TextInput::make('icon')
->label('Material Symbol ikony')
->required()
->default('history')
->placeholder('storefront'),
TextInput::make('sort_order')
->label('Tertip')
->required()
->numeric()
->default(0),
Textarea::make('body')
->label('Tekst')
->required()
->rows(3)
->columnSpanFull(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
TextColumn::make('year')
->label('Ýyly')
->sortable(),
TextColumn::make('title')
->label('Başlyk')
->searchable(),
TextColumn::make('icon')
->label('Ikony'),
TextColumn::make('sort_order')
->label('Tertip')
->numeric()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('sort_order')
->filters([])
->recordActions([
EditAction::make(),
DeleteAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => ManageTimelineEntries::route('/'),
];
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\FooterNavLink;
use App\Models\HeroSlide;
use App\Models\SignatureItem;
use App\Models\SiteSetting;
use App\Models\SocialLink;
use App\Models\TimelineEntry;
use Illuminate\Contracts\View\View;
class HomeController extends Controller
{
public function index(): View
{
$heroSlides = HeroSlide::where('is_active', true)
->orderBy('sort_order')
->get();
$categories = Category::where('is_active', true)
->orderBy('sort_order')
->with([
'products' => fn ($query) => $query
->where('is_active', true)
->orderBy('sort_order'),
])
->get();
$signatureItems = SignatureItem::where('is_active', true)
->orderBy('sort_order')
->get();
$timelineEntries = TimelineEntry::orderBy('sort_order')->get();
$footerNavLinks = FooterNavLink::orderBy('sort_order')->get();
$socialLinks = SocialLink::orderBy('sort_order')->get();
$settings = SiteSetting::pluck('value', 'key');
return view('welcome', compact(
'heroSlides',
'categories',
'signatureItems',
'timelineEntries',
'footerNavLinks',
'socialLinks',
'settings',
));
}
}

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

@@ -0,0 +1,50 @@
<?php
namespace App\Models;
use Database\Factories\CategoryFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;
class Category extends Model
{
/** @use HasFactory<CategoryFactory> */
use HasFactory;
protected $fillable = [
'name',
'slug',
'icon',
'sort_order',
'is_active',
];
protected function casts(): array
{
return [
'is_active' => 'boolean',
'sort_order' => 'integer',
];
}
protected static function booted(): void
{
static::saving(function (Category $category): void {
if (empty($category->slug)) {
$category->slug = Str::slug($category->name);
}
});
}
public function products(): HasMany
{
return $this->hasMany(Product::class);
}
public function scopeActive($query): void
{
$query->where('is_active', true);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Database\Factories\FooterNavLinkFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class FooterNavLink extends Model
{
/** @use HasFactory<FooterNavLinkFactory> */
use HasFactory;
protected $fillable = [
'label',
'url',
'sort_order',
];
protected function casts(): array
{
return [
'sort_order' => 'integer',
];
}
}

36
app/Models/HeroSlide.php Normal file
View File

@@ -0,0 +1,36 @@
<?php
namespace App\Models;
use Database\Factories\HeroSlideFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class HeroSlide extends Model
{
/** @use HasFactory<HeroSlideFactory> */
use HasFactory;
protected $fillable = [
'headline',
'subheadline',
'cta_label',
'cta_url',
'image',
'sort_order',
'is_active',
];
protected function casts(): array
{
return [
'is_active' => 'boolean',
'sort_order' => 'integer',
];
}
public function scopeActive($query): void
{
$query->where('is_active', true);
}
}

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

@@ -0,0 +1,61 @@
<?php
namespace App\Models;
use Database\Factories\ProductFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
class Product extends Model
{
/** @use HasFactory<ProductFactory> */
use HasFactory;
protected $fillable = [
'category_id',
'name',
'slug',
'price',
'price_unit',
'description',
'image',
'availability_status',
'is_active',
'sort_order',
];
protected function casts(): array
{
return [
'price' => 'decimal:2',
'is_active' => 'boolean',
'sort_order' => 'integer',
];
}
protected static function booted(): void
{
static::saving(function (Product $product): void {
if (empty($product->slug)) {
$product->slug = Str::slug($product->name);
}
});
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function scopeActive($query): void
{
$query->where('is_active', true);
}
public function isAvailable(): bool
{
return $this->availability_status === 'available';
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Models;
use Database\Factories\SignatureItemFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SignatureItem extends Model
{
/** @use HasFactory<SignatureItemFactory> */
use HasFactory;
protected $fillable = [
'name',
'price',
'price_unit',
'description',
'image',
'sort_order',
'is_active',
];
protected function casts(): array
{
return [
'price' => 'decimal:2',
'is_active' => 'boolean',
'sort_order' => 'integer',
];
}
public function scopeActive($query): void
{
$query->where('is_active', true);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use Database\Factories\SiteSettingFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
class SiteSetting extends Model
{
/** @use HasFactory<SiteSettingFactory> */
use HasFactory;
protected $primaryKey = 'key';
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'key',
'value',
];
/**
* Get a setting value by key.
*/
public static function get(string $key, ?string $default = null): ?string
{
return static::find($key)?->value ?? $default;
}
/**
* Set a setting value by key.
*/
public static function set(string $key, ?string $value): void
{
static::updateOrCreate(['key' => $key], ['value' => $value]);
}
/**
* Get all settings as a key-value collection.
*/
public static function allAsCollection(): Collection
{
return static::pluck('value', 'key');
}
}

27
app/Models/SocialLink.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Database\Factories\SocialLinkFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SocialLink extends Model
{
/** @use HasFactory<SocialLinkFactory> */
use HasFactory;
protected $fillable = [
'platform',
'url',
'icon',
'sort_order',
];
protected function casts(): array
{
return [
'sort_order' => 'integer',
];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Models;
use Database\Factories\TimelineEntryFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TimelineEntry extends Model
{
/** @use HasFactory<TimelineEntryFactory> */
use HasFactory;
protected $fillable = [
'year',
'title',
'body',
'icon',
'sort_order',
];
protected function casts(): array
{
return [
'year' => 'integer',
'sort_order' => 'integer',
];
}
}

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

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

View File

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

View File

@@ -3,13 +3,11 @@
"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.0",
"laravel/framework": "^13.8",
"laravel/tinker": "^3.0"
},
@@ -55,7 +53,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",

2126
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
<?php
namespace Database\Factories;
use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends Factory<Category>
*/
class CategoryFactory extends Factory
{
public function definition(): array
{
$name = fake()->unique()->word();
return [
'name' => $name,
'slug' => Str::slug($name),
'icon' => 'category',
'sort_order' => fake()->numberBetween(0, 10),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(['is_active' => false]);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Database\Factories;
use App\Models\FooterNavLink;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<FooterNavLink>
*/
class FooterNavLinkFactory extends Factory
{
public function definition(): array
{
return [
'label' => fake()->word(),
'url' => '#',
'sort_order' => fake()->numberBetween(0, 10),
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Database\Factories;
use App\Models\HeroSlide;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<HeroSlide>
*/
class HeroSlideFactory extends Factory
{
public function definition(): array
{
return [
'headline' => fake()->sentence(3),
'subheadline' => fake()->sentence(8),
'cta_label' => fake()->words(3, true),
'cta_url' => '#',
'image' => null,
'sort_order' => fake()->numberBetween(0, 10),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(['is_active' => false]);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Database\Factories;
use App\Models\Category;
use App\Models\Product;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends Factory<Product>
*/
class ProductFactory extends Factory
{
public function definition(): array
{
$name = fake()->words(3, true);
return [
'category_id' => Category::factory(),
'name' => $name,
'slug' => Str::slug($name),
'price' => fake()->randomFloat(2, 10, 500),
'price_unit' => fake()->randomElement(['kg', 'sany', 'gram']),
'description' => fake()->sentence(12),
'image' => null,
'availability_status' => 'available',
'is_active' => true,
'sort_order' => fake()->numberBetween(0, 10),
];
}
public function unavailable(): static
{
return $this->state(['availability_status' => 'out_of_season']);
}
public function inactive(): static
{
return $this->state(['is_active' => false]);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Database\Factories;
use App\Models\SignatureItem;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<SignatureItem>
*/
class SignatureItemFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->words(3, true),
'price' => fake()->randomFloat(2, 50, 1000),
'price_unit' => 'kg',
'description' => fake()->sentence(12),
'image' => null,
'sort_order' => fake()->numberBetween(0, 10),
'is_active' => true,
];
}
public function inactive(): static
{
return $this->state(['is_active' => false]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Database\Factories;
use App\Models\SiteSetting;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<SiteSetting>
*/
class SiteSettingFactory extends Factory
{
public function definition(): array
{
return [
'key' => fake()->unique()->slug(),
'value' => fake()->sentence(),
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Database\Factories;
use App\Models\SocialLink;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<SocialLink>
*/
class SocialLinkFactory extends Factory
{
public function definition(): array
{
return [
'platform' => fake()->randomElement(['Instagram', 'Facebook', 'Email', 'Telegram']),
'url' => fake()->url(),
'icon' => 'link',
'sort_order' => fake()->numberBetween(0, 10),
];
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use App\Models\TimelineEntry;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<TimelineEntry>
*/
class TimelineEntryFactory extends Factory
{
public function definition(): array
{
return [
'year' => fake()->year(),
'title' => fake()->sentence(3),
'body' => fake()->paragraph(),
'icon' => 'history',
'sort_order' => fake()->numberBetween(0, 10),
];
}
}

View File

@@ -0,0 +1,34 @@
<?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('hero_slides', function (Blueprint $table) {
$table->id();
$table->string('headline');
$table->string('subheadline')->nullable();
$table->string('cta_label')->nullable();
$table->string('cta_url')->nullable();
$table->string('image')->nullable();
$table->unsignedSmallInteger('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('hero_slides');
}
};

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('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->string('icon')->default('category');
$table->unsignedSmallInteger('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('categories');
}
};

View File

@@ -0,0 +1,37 @@
<?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()->cascadeOnDelete();
$table->string('name');
$table->string('slug')->unique();
$table->decimal('price', 10, 2);
$table->string('price_unit')->default('kg');
$table->text('description')->nullable();
$table->string('image')->nullable();
$table->string('availability_status')->default('available');
$table->boolean('is_active')->default(true);
$table->unsignedSmallInteger('sort_order')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};

View File

@@ -0,0 +1,34 @@
<?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('signature_items', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 10, 2);
$table->string('price_unit')->default('kg');
$table->text('description')->nullable();
$table->string('image')->nullable();
$table->unsignedSmallInteger('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('signature_items');
}
};

View File

@@ -0,0 +1,28 @@
<?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('site_settings', function (Blueprint $table) {
$table->string('key')->primary();
$table->text('value')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('site_settings');
}
};

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('timeline_entries', function (Blueprint $table) {
$table->id();
$table->unsignedSmallInteger('year');
$table->string('title');
$table->text('body');
$table->string('icon')->default('history');
$table->unsignedSmallInteger('sort_order')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('timeline_entries');
}
};

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('footer_nav_links', function (Blueprint $table) {
$table->id();
$table->string('label');
$table->string('url');
$table->unsignedSmallInteger('sort_order')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('footer_nav_links');
}
};

View File

@@ -0,0 +1,31 @@
<?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('social_links', function (Blueprint $table) {
$table->id();
$table->string('platform');
$table->string('url');
$table->string('icon')->default('link');
$table->unsignedSmallInteger('sort_order')->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('social_links');
}
};

View File

@@ -0,0 +1,24 @@
<?php
namespace Database\Seeders;
use App\Models\Category;
use Illuminate\Database\Seeder;
class CategorySeeder extends Seeder
{
public function run(): void
{
$categories = [
['name' => 'Sygyr eti', 'slug' => 'sygyr-eti', 'icon' => 'set_meal', 'sort_order' => 1],
['name' => 'Goýun eti', 'slug' => 'goyun-eti', 'icon' => 'cruelty_free', 'sort_order' => 2],
['name' => 'Goş', 'slug' => 'gos', 'icon' => 'kebab_dining', 'sort_order' => 3],
['name' => 'Guş eti', 'slug' => 'gus-eti', 'icon' => 'egg', 'sort_order' => 4],
['name' => 'Kolbasalar', 'slug' => 'kolbasalar', 'icon' => 'local_pizza', 'sort_order' => 5],
];
foreach ($categories as $category) {
Category::create(array_merge($category, ['is_active' => true]));
}
}
}

View File

@@ -3,23 +3,26 @@
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
use WithoutModelEvents;
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
'name' => 'Admin',
'email' => 'admin@daragt.tm',
]);
$this->call([
SiteSettingSeeder::class,
CategorySeeder::class,
ProductSeeder::class,
SignatureItemSeeder::class,
TimelineEntrySeeder::class,
FooterNavLinkSeeder::class,
SocialLinkSeeder::class,
HeroSlideSeeder::class,
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Database\Seeders;
use App\Models\FooterNavLink;
use Illuminate\Database\Seeder;
class FooterNavLinkSeeder extends Seeder
{
public function run(): void
{
$links = [
['label' => 'Çykgyş', 'url' => '#', 'sort_order' => 1],
['label' => 'Eltip bermek', 'url' => '#', 'sort_order' => 2],
['label' => 'Gizlinlik', 'url' => '#', 'sort_order' => 3],
['label' => 'Şertler', 'url' => '#', 'sort_order' => 4],
];
foreach ($links as $link) {
FooterNavLink::create($link);
}
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Database\Seeders;
use App\Models\HeroSlide;
use Illuminate\Database\Seeder;
class HeroSlideSeeder extends Seeder
{
public function run(): void
{
$slides = [
[
'headline' => "Usta\ntarapyndan\ntaýýarlanan bölekler.",
'subheadline' => 'Miras et, el bilen saýlanan we bilimiň stoly üçin usta taýýarlygy.',
'cta_label' => 'Häzir satyn al',
'cta_url' => '#explore',
'image' => null,
'sort_order' => 1,
'is_active' => true,
],
[
'headline' => "Kämilleşdirilmek\nüçin\ngowaldyrylan.",
'subheadline' => 'Wagtyň synagdan geçen gowaldyryş usullary — ýokary ýumşaklyk we tagam çuňlugy.',
'cta_label' => 'Gowaldyrylan etleri gözden geçiriň',
'cta_url' => '#explore',
'image' => null,
'sort_order' => 2,
'is_active' => true,
],
[
'headline' => "Usta\nkolbasalary.",
'subheadline' => 'Her gün el bilen baglanýar — adaty reseptler, premium bölekler we aýratyn tagam garyndylary.',
'cta_label' => 'Saýlawy görmek',
'cta_url' => '#explore',
'image' => null,
'sort_order' => 3,
'is_active' => true,
],
];
foreach ($slides as $slide) {
HeroSlide::create($slide);
}
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Database\Seeders;
use App\Models\Category;
use App\Models\Product;
use Illuminate\Database\Seeder;
use Illuminate\Support\Str;
class ProductSeeder extends Seeder
{
public function run(): void
{
$productsByCategory = [
'sygyr-eti' => [
['name' => 'Ribeye Bifteği', 'price' => 320, 'price_unit' => 'kg', 'description' => 'Ýag damarlary bilen doly marbleli premium ribeye bifteği.', 'availability_status' => 'available', 'sort_order' => 1],
['name' => 'Filé Minyon', 'price' => 480, 'price_unit' => 'kg', 'description' => 'Iň ýumşak we inçe süýümli et, aşpezleriň söýgülisi.', 'availability_status' => 'available', 'sort_order' => 2],
['name' => 'T-Bone Bifteği', 'price' => 290, 'price_unit' => 'kg', 'description' => 'Iki sany bifteği bir kesimde — strip we filé.', 'availability_status' => 'available', 'sort_order' => 3],
['name' => 'Çarşamba Bifteği', 'price' => 220, 'price_unit' => 'kg', 'description' => 'Güýçli tagamy bilen meşhur ýönekeý biftek.', 'availability_status' => 'available', 'sort_order' => 4],
],
'goyun-eti' => [
['name' => 'Goýun Çapraz Bölegi', 'price' => 180, 'price_unit' => 'kg', 'description' => 'Slow-cook üçin amatly, süýji tagamly goýun eti.', 'availability_status' => 'available', 'sort_order' => 1],
['name' => 'Goýun Gyrmak', 'price' => 240, 'price_unit' => 'kg', 'description' => 'El bilen gyrdylan inçe goýun eti.', 'availability_status' => 'available', 'sort_order' => 2],
['name' => 'Goýun Kelleçe', 'price' => 160, 'price_unit' => 'kg', 'description' => 'Bahasynyň deregine tagamly we ýumşak et.', 'availability_status' => 'out_of_season', 'sort_order' => 3],
],
'gos' => [
['name' => 'Goş Karbonat', 'price' => 200, 'price_unit' => 'kg', 'description' => 'Galyň dilen premium goş filési.', 'availability_status' => 'available', 'sort_order' => 1],
['name' => 'Goş Garnide', 'price' => 170, 'price_unit' => 'kg', 'description' => 'Ýumşak ot kaburga bölekleri.', 'availability_status' => 'available', 'sort_order' => 2],
['name' => 'Goş Gyrmak', 'price' => 140, 'price_unit' => 'kg', 'description' => 'El bilen taýýarlanan taze goş gyrmak.', 'availability_status' => 'available', 'sort_order' => 3],
],
'gus-eti' => [
['name' => 'Towuk Döşi', 'price' => 110, 'price_unit' => 'kg', 'description' => 'Süýümli we ýagsyz towuk döşi.', 'availability_status' => 'available', 'sort_order' => 1],
['name' => 'Hindi Buty', 'price' => 130, 'price_unit' => 'kg', 'description' => 'Tagamly hindi buty, süýji et.', 'availability_status' => 'available', 'sort_order' => 2],
['name' => 'Ördek Döşi', 'price' => 260, 'price_unit' => 'kg', 'description' => 'Baý tagamly premium ördek döşi.', 'availability_status' => 'available', 'sort_order' => 3],
],
'kolbasalar' => [
['name' => 'Gyzgyn Merguez', 'price' => 190, 'price_unit' => 'kg', 'description' => 'Demirgazyk Afrika resepti, harissa we zira bilen.', 'availability_status' => 'available', 'sort_order' => 1],
['name' => 'Düzgün Sosis', 'price' => 150, 'price_unit' => 'kg', 'description' => 'Adaty resept bilen el bilen taýýarlanan sosis.', 'availability_status' => 'available', 'sort_order' => 2],
['name' => 'Brätworst', 'price' => 170, 'price_unit' => 'kg', 'description' => 'Nemes stili premium doňuz sosisi.', 'availability_status' => 'available', 'sort_order' => 3],
],
];
foreach ($productsByCategory as $categorySlug => $products) {
$category = Category::where('slug', $categorySlug)->first();
if (! $category) {
continue;
}
foreach ($products as $productData) {
Product::create(array_merge($productData, [
'category_id' => $category->id,
'slug' => Str::slug($productData['name']),
'image' => null,
'is_active' => true,
]));
}
}
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Database\Seeders;
use App\Models\SignatureItem;
use Illuminate\Database\Seeder;
class SignatureItemSeeder extends Seeder
{
public function run(): void
{
$items = [
[
'name' => 'Gowaldyrylan Tomahawk',
'price' => 890,
'price_unit' => 'kg',
'description' => '45 gün gowaldyrylan ribeye, baý we nahar tagamly. Paýlaşmak üçin amatly.',
'image' => null,
'sort_order' => 1,
'is_active' => true,
],
[
'name' => 'Öýde duzlanan we tüsse edilen goş',
'price' => 420,
'price_unit' => 'kg',
'description' => 'Galyň bölekli goş göwresi, akderweýi bilen duzlanan we 12 sagat galadan agachynda tüsse edilen.',
'image' => null,
'sort_order' => 2,
'is_active' => true,
],
[
'name' => 'Açy goş Merguez',
'price' => 280,
'price_unit' => 'kg',
'description' => 'Miras goş harissa, zira we rezene bilen. Demirgazyk Afrikanyň klasykasy.',
'image' => null,
'sort_order' => 3,
'is_active' => true,
],
[
'name' => 'Miras göýün taý kebi',
'price' => 650,
'price_unit' => 'kg',
'description' => 'Bellik taý kebi, usta taýýarlykda frenc we baglanan.',
'image' => null,
'sort_order' => 4,
'is_active' => true,
],
];
foreach ($items as $item) {
SignatureItem::create($item);
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace Database\Seeders;
use App\Models\SiteSetting;
use Illuminate\Database\Seeder;
class SiteSettingSeeder extends Seeder
{
public function run(): void
{
$settings = [
'butchers_tale_title' => 'Kesimçiniň hekaýasy',
'butchers_tale_body' => 'Bizi tutuş haýwan kesim sungatynda özüni bagyşlanan ustaçylyk maşgalasy. Esasyndan bäri senagatçilik ýoluny ret edip, ýerli çärikçiler bilen dogry gatnaşyklary, wagtyň synagdan geçen gowaldyryş usullaryny we hil boýunça bäsdeşsiz yhlasyny saýladyk.',
'butchers_tale_image' => null,
'footer_brand_name' => 'DARAGT',
'footer_copyright' => '© 2026 DARAGT USTA KESIMÇILERI. EL BILEN TAÝÝARLANAN.',
'footer_address' => 'Aşgabat, Türkmenistan',
'footer_email' => 'info@daragt.tm',
'footer_phone' => '+993 61 92 92 48',
];
foreach ($settings as $key => $value) {
SiteSetting::create(['key' => $key, 'value' => $value]);
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Database\Seeders;
use App\Models\SocialLink;
use Illuminate\Database\Seeder;
class SocialLinkSeeder extends Seeder
{
public function run(): void
{
$links = [
['platform' => 'Telegram', 'url' => 'https://t.me/daragt', 'icon' => 'social_leaderboard', 'sort_order' => 1],
['platform' => 'Instagram', 'url' => 'https://instagram.com/daragt', 'icon' => 'photo_camera', 'sort_order' => 2],
['platform' => 'Email', 'url' => 'mailto:info@daragt.tm', 'icon' => 'mail', 'sort_order' => 3],
];
foreach ($links as $link) {
SocialLink::create($link);
}
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Database\Seeders;
use App\Models\TimelineEntry;
use Illuminate\Database\Seeder;
class TimelineEntrySeeder extends Seeder
{
public function run(): void
{
$entries = [
[
'year' => 1987,
'title' => 'Esasy',
'body' => 'Daragt taryhy merkezi bazarynda ilkinji kiçijik dükançasyny açýar, diňe ýerli çörleri sygyr etine üns berýär.',
'icon' => 'storefront',
'sort_order' => 1,
],
[
'year' => 1995,
'title' => 'Tüsse otagy',
'body' => 'Ilkinji ýörite dub tüsse otagyny gurýarys, meşhur duzlanan we tüsse edilen kolbasa hatarlarymyzy başladýarys.',
'icon' => 'outdoor_grill',
'sort_order' => 2,
],
[
'year' => 2010,
'title' => 'Döwlet boýunça eltip bermek',
'body' => 'Sowuk zynjyrlawly logistika bilen hyzmatdaş bolup, usta taýýarlanan böleklerimizi döwlet boýunça öý aşpezlerine eltip berýäris.',
'icon' => 'local_shipping',
'sort_order' => 3,
],
[
'year' => 2023,
'title' => 'Resept kitaby',
'body' => 'Miras reseptler toplumynyň çykarylysy — adaty taýýarlamany häzirki aşpezçilik usullary bilen baglaşdyrýarys.',
'icon' => 'menu_book',
'sort_order' => 4,
],
];
foreach ($entries as $entry) {
TimelineEntry::create($entry);
}
}
}

1623
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,5 +12,8 @@
"laravel-vite-plugin": "^3.1",
"tailwindcss": "^4.0.0",
"vite": "^8.0.0"
},
"dependencies": {
"@splidejs/splide": "^4.1.4"
}
}

View File

@@ -0,0 +1,67 @@
@font-face {
font-family: 'Archivo Narrow';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(../fonts/tss2ApVBdCYD5Q7hcxTE1ArZ0bb1iXxw2d8o.woff2) format('woff2');
}
@font-face {
font-family: 'Archivo Narrow';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(../fonts/tss0ApVBdCYD5Q7hcxTE1ArZ0Ybyg3tS2w.woff2) format('woff2');
}
@font-face {
font-family: 'Playfair Display';
font-style: italic;
font-weight: 400 900;
font-display: swap;
src: url(../fonts/nuFkD-vYSZviVYUb_rj3ij__anPXDTnYgEM86xQ.woff2) format('woff2');
}
@font-face {
font-family: 'Playfair Display';
font-style: normal;
font-weight: 400 900;
font-display: swap;
src: url(../fonts/nuFiD-vYSZviVYUb_rj3ij__anPXPT7Sh2E-.woff2) format('woff2');
}
@font-face {
font-family: 'Source Serif 4';
font-style: italic;
font-weight: 200 900;
font-display: swap;
src: url(../fonts/vEFK2_tTDB4M7-auWDN0ahZJW1ge8te1Xb7G.woff2) format('woff2');
}
@font-face {
font-family: 'Source Serif 4';
font-style: normal;
font-weight: 200 900;
font-display: swap;
src: url(../fonts/vEFI2_tTDB4M7-auWDN0ahZJW2gZ-NCXXw.woff2) format('woff2');
}
/* fallback */
@font-face {
font-family: 'Material Symbols Outlined';
font-style: normal;
font-weight: 100 700;
font-display: swap;
src: url(../fonts/kJEPBvYX7BgnkSrUwT8OhrdQw4oELdPIeeII9v6oDMzBwG-RpA6RzaxHMPdY40KH8nGzv3fzfVJO1USv9ls.woff2) format('woff2');
}
.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;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
function a({state:r}){return{state:r,rows:[],init(){this.updateRows(),this.rows.length<=0?this.rows.push({key:"",value:""}):this.updateState(),this.$watch("state",(e,t)=>{if(!Array.isArray(e))return;let s=i=>i===null?0:Array.isArray(i)?i.length:typeof i!="object"?0:Object.keys(i).length;s(e)===0&&s(t)===0||this.updateRows()})},addRow(){this.rows.push({key:"",value:""}),this.updateState()},deleteRow(e){this.rows.splice(e,1),this.rows.length<=0&&this.addRow(),this.updateState()},reorderRows(e){let t=Alpine.raw(this.rows);this.rows=[];let s=t.splice(e.oldIndex,1)[0];t.splice(e.newIndex,0,s),this.$nextTick(()=>{this.rows=t,this.updateState()})},updateRows(){let t=Alpine.raw(this.state).map(({key:s,value:i})=>({key:s,value:i}));this.rows.forEach(s=>{(s.key===""||s.key===null)&&t.push({key:"",value:s.value})}),this.rows=t},updateState(){let e=[];this.rows.forEach(t=>{t.key===""||t.key===null||e.push({key:t.key,value:t.value})}),JSON.stringify(this.state)!==JSON.stringify(e)&&(this.state=e)}}}export{a 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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
function s({state:n,splitKeys:a}){return{newTag:"",state:n,createTag(){if(this.newTag=this.newTag.trim(),this.newTag!==""){if(this.state.includes(this.newTag)){this.newTag="";return}this.state.push(this.newTag),this.newTag=""}},deleteTag(t){this.state=this.state.filter(e=>e!==t)},reorderTags(t){let e=this.state.splice(t.oldIndex,1)[0];this.state.splice(t.newIndex,0,e),this.state=[...this.state]},input:{"x-on:blur":"createTag()","x-model":"newTag","x-on:keydown"(t){["Enter",...a].includes(t.key)&&(t.preventDefault(),t.stopPropagation(),this.createTag())},"x-on:paste"(){this.$nextTick(()=>{if(a.length===0){this.createTag();return}let t=a.map(e=>e.replace(/[/\-\\^$*+?.()|[\]{}]/g,"\\$&")).join("|");this.newTag.split(new RegExp(t,"g")).forEach(e=>{this.newTag=e,this.createTag()})})}}}}export{s as default};

View File

@@ -0,0 +1 @@
function n({initialHeight:e,shouldAutosize:i,state:h}){return{state:h,wrapperEl:null,init(){this.wrapperEl=this.$el.parentNode,this.setInitialHeight(),i?this.$watch("state",()=>{this.resize()}):this.setUpResizeObserver()},setInitialHeight(){this.$el.scrollHeight<=0||(this.wrapperEl.style.height=e+"rem")},resize(){if(this.$el.scrollHeight<=0)return;let t=this.$el.style.height;this.$el.style.height="0px";let r=this.$el.scrollHeight;this.$el.style.height=t;let l=parseFloat(e)*parseFloat(getComputedStyle(document.documentElement).fontSize),s=Math.max(r,l)+"px";this.wrapperEl.style.height!==s&&(this.wrapperEl.style.height=s)},setUpResizeObserver(){new ResizeObserver(()=>{this.wrapperEl.style.height=this.$el.style.height}).observe(this.$el)}}}export{n as default};

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