From 0f798e5edb6f7a219ba1a9eb5bb20d7ee91661eb Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Wed, 3 Jul 2024 12:13:46 -0400 Subject: [PATCH] Add custom component --- app/Filament/Forms/SelectEndpoint.php | 10 + .../ServerResource/Pages/CreateServer.php | 34 +-- .../components/filament/wrapper.blade.php | 223 ++++++++++++++++++ .../filament/components/select.blade.php | 98 ++++++++ 4 files changed, 340 insertions(+), 25 deletions(-) create mode 100644 app/Filament/Forms/SelectEndpoint.php create mode 100644 resources/views/components/filament/wrapper.blade.php create mode 100644 resources/views/filament/components/select.blade.php diff --git a/app/Filament/Forms/SelectEndpoint.php b/app/Filament/Forms/SelectEndpoint.php new file mode 100644 index 000000000..5a3eb4fe7 --- /dev/null +++ b/app/Filament/Forms/SelectEndpoint.php @@ -0,0 +1,10 @@ +columns(4) ->schema([ Forms\Components\TagsInput::make('ports') - ->columnSpanFull() + ->columnSpan(2) ->hintIcon('tabler-question-mark') ->hintIconTooltip('Ports are limited from 1025 to 65535') ->placeholder('Example: 25565, 8080, 1337-1340') ->splitKeys(['Tab', ' ', ',']) ->helperText(new HtmlString(' - These are the ports that users can connect to this Server through. - You would typically port forward these on your home network. - ')) + These are the ports that users can connect to this Server through. + You would typically port forward these on your home network. + ')) ->label('Ports') ->afterStateUpdated(self::ports(...)) ->live(), - Forms\Components\Repeater::make('ip') - ->columnSpan(2) - ->defaultItems(5) - ->label('IP Assignments') - ->live() - ->addable(false) - ->deletable(false) - ->reorderable(false) - ->hintIcon('tabler-question-mark') - ->hintIconTooltip('These are the IPs available on the selected Node.') - ->simple( - Forms\Components\Select::make('port') - ->live() - ->placeholder('Select an IP') -// ->afterStateUpdated() - ->options(fn () => $this->node?->ipAddresses()) - ->required(), - ), - Forms\Components\Repeater::make('assignments') ->columnSpan(2) ->defaultItems(fn () => count($this->eggDefaultPorts)) @@ -372,11 +354,13 @@ class CreateServer extends CreateRecord ->deletable(false) ->reorderable(false) ->simple( - Forms\Components\Select::make('port') + SelectEndpoint::make('port') + ->columnSpanFull() + ->label('') ->live() ->placeholder('Select a Port') ->disabled(fn (Forms\Get $get) => empty($get('../../ports')) || empty($get('../../assignments'))) - ->prefix(function (Forms\Components\Component $component) { + ->suffix(function (Forms\Components\Component $component) { $key = str($component->getStatePath())->beforeLast('.')->afterLast('.')->toString(); return $key; diff --git a/resources/views/components/filament/wrapper.blade.php b/resources/views/components/filament/wrapper.blade.php new file mode 100644 index 000000000..6f4fc6ebe --- /dev/null +++ b/resources/views/components/filament/wrapper.blade.php @@ -0,0 +1,223 @@ +@props([ + 'alpineDisabled' => null, + 'alpineValid' => null, + 'disabled' => false, + 'inlinePrefix' => false, + 'inlineSuffix' => false, + 'prefix' => null, + 'prefixActions' => [], + 'prefixIcon' => null, + 'prefixIconColor' => 'gray', + 'prefixIconAlias' => null, + 'suffix' => null, + 'suffixActions' => [], + 'suffixIcon' => null, + 'suffixIconColor' => 'gray', + 'suffixIconAlias' => null, + 'valid' => true, +]) + +@php + $prefixActions = array_filter( + $prefixActions, + fn (\Filament\Forms\Components\Actions\Action $prefixAction): bool => $prefixAction->isVisible(), + ); + + $suffixActions = array_filter( + $suffixActions, + fn (\Filament\Forms\Components\Actions\Action $suffixAction): bool => $suffixAction->isVisible(), + ); + + $hasPrefix = count($prefixActions) || $prefixIcon || filled($prefix); + $hasSuffix = count($suffixActions) || $suffixIcon || filled($suffix); + + $hasAlpineDisabledClasses = filled($alpineDisabled); + $hasAlpineValidClasses = filled($alpineValid); + $hasAlpineClasses = $hasAlpineDisabledClasses || $hasAlpineValidClasses; + + $enabledWrapperClasses = 'bg-white dark:bg-white/5 [&:not(:has(.fi-ac-action:focus))]:focus-within:ring-2'; + $disabledWrapperClasses = 'fi-disabled bg-gray-50 dark:bg-transparent'; + $validWrapperClasses = 'ring-gray-950/10'; + $invalidWrapperClasses = 'fi-invalid ring-danger-600 dark:ring-danger-500'; + $enabledValidWrapperClasses = 'dark:ring-white/20 [&:not(:has(.fi-ac-action:focus))]:focus-within:ring-primary-600 dark:[&:not(:has(.fi-ac-action:focus))]:focus-within:ring-primary-500'; + $enabledInvalidWrapperClasses = '[&:not(:has(.fi-ac-action:focus))]:focus-within:ring-danger-600 dark:[&:not(:has(.fi-ac-action:focus))]:focus-within:ring-danger-500'; + $disabledValidWrapperClasses = 'dark:ring-white/10'; + + $actionsClasses = 'flex items-center gap-3'; + $labelClasses = 'fi-input-wrp-label whitespace-nowrap text-sm text-gray-500 dark:text-gray-400'; + + $getIconClasses = fn (string | array $color = 'gray'): string => \Illuminate\Support\Arr::toCssClasses([ + 'fi-input-wrp-icon h-5 w-5', + match ($color) { + 'gray' => 'text-gray-400 dark:text-gray-500', + default => 'text-custom-500', + }, + ]); + + $getIconStyles = fn (string | array $color = 'gray'): string => \Illuminate\Support\Arr::toCssStyles([ + \Filament\Support\get_color_css_variables( + $color, + shades: [500], + alias: 'input-wrapper.icon', + ) => $color !== 'gray', + ]); + + $wireTarget = $attributes->whereStartsWith(['wire:target'])->first(); + + $hasLoadingIndicator = filled($wireTarget); + + if ($hasLoadingIndicator) { + $loadingIndicatorTarget = html_entity_decode($wireTarget, ENT_QUOTES); + } +@endphp + +
except(['wire:target']) + ->class([ + 'fi-input-wrp flex rounded-lg shadow-sm ring-1 transition duration-75', + $enabledWrapperClasses => (! $hasAlpineClasses) && (! $disabled), + $disabledWrapperClasses => (! $hasAlpineClasses) && $disabled, + $validWrapperClasses => (! $hasAlpineClasses) && $valid, + $invalidWrapperClasses => (! $hasAlpineClasses) && (! $valid), + $enabledValidWrapperClasses => (! $hasAlpineClasses) && (! $disabled) && $valid, + $enabledInvalidWrapperClasses => (! $hasAlpineClasses) && (! $disabled) && (! $valid), + $disabledValidWrapperClasses => (! $hasAlpineClasses) && $disabled && $valid, + ]) + }} +> + + @php $hasPrefix = true; @endphp + +
$hasPrefix, + 'hidden' => ! $hasPrefix, + 'pe-1' => $inlinePrefix && filled($prefix), + 'pe-2' => $inlinePrefix && blank($prefix), + 'border-e border-gray-200 pe-3 ps-3 dark:border-white/10' => ! $inlinePrefix, + ]) + > + @if (count($prefixActions)) +
+ @foreach ($prefixActions as $prefixAction) + {{ $prefixAction }} + @endforeach +
+ @endif + + @if ($prefixIcon) + + @endif + + @if ($hasLoadingIndicator) + + @endif + + + + @foreach ((\App\Models\Node::find(6))->ipAddresses() as $ip) + + @endforeach + + +
+ + +
$hasPrefix, + 'pe-1' => $inlinePrefix && filled($prefix), + 'pe-2' => $inlinePrefix && blank($prefix), + 'border-e border-gray-200 pe-3 ps-3 dark:border-white/10' => ! $inlinePrefix, + ]) + > + : +
+ +
$hasLoadingIndicator && (! $hasPrefix) && $inlinePrefix, + ]) + > + {{ $slot }} +
+ + @if ($hasSuffix) +
$inlineSuffix && filled($suffix), + 'ps-2' => $inlineSuffix && blank($suffix), + 'border-s border-gray-200 ps-3 dark:border-white/10' => ! $inlineSuffix, + ]) + > + @if (filled($suffix)) + + {{ $suffix }} + + @endif + + @if ($suffixIcon) + + @endif + + @if (count($suffixActions)) +
+ @foreach ($suffixActions as $suffixAction) + {{ $suffixAction }} + @endforeach +
+ @endif +
+ @endif +
diff --git a/resources/views/filament/components/select.blade.php b/resources/views/filament/components/select.blade.php new file mode 100644 index 000000000..11aee4418 --- /dev/null +++ b/resources/views/filament/components/select.blade.php @@ -0,0 +1,98 @@ +@php + use Filament\Support\Facades\FilamentView; + + $canSelectPlaceholder = $canSelectPlaceholder(); + $isDisabled = $isDisabled(); + $isPrefixInline = $isPrefixInline(); + $isSuffixInline = $isSuffixInline(); + $prefixActions = $getPrefixActions(); + $prefixIcon = $getPrefixIcon(); + $prefixLabel = $getPrefixLabel(); + $suffixActions = $getSuffixActions(); + $suffixIcon = $getSuffixIcon(); + $suffixLabel = $getSuffixLabel(); + $statePath = $getStatePath(); +@endphp + + + + + @php + $isHtmlAllowed = $isHtmlAllowed(); + @endphp + + @if ($canSelectPlaceholder) + + @endif + + @foreach ($getOptions() as $value => $label) + @if (is_array($label)) + + @foreach ($label as $groupedValue => $groupedLabel) + + @endforeach + + @else + + @endif + @endforeach + + + +