diff --git a/README.md b/README.md index 00c439c..5243f99 100644 --- a/README.md +++ b/README.md @@ -94,26 +94,6 @@ public function setUp(): void > The `setUp` method is called on `mount` of the widget. See [livewire lifecycle hooks](https://laravel-livewire.com/docs/2.x/lifecycle-hooks) for more information. -### Global Configuration - -If you want to set a default configuration for all instances of the map widget, you can use the `configureUsing` method in a service provider: - -```php -MyMap::configureUsing(function (ResellerMap $widget) { - $widget->mapMarkers([ - Marker::make('id') - ->lat(51.505) - ->lng(-0.09) - ->popup('I am a popup') - ->tooltip('I am a tooltip'), - ]) - ->tileLayerUrl('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png') - ->tileLayerOptions([ - 'attribution' => 'Map data © OpenStreetMap contributors', - ]) -}); -``` - ## Tile Layers The map uses OpenStreetMap tiles by default, but you can change it to use any other provider using `$tileLayerUrl` property or `tileLayerUrl` method. It's recommended to also use the `tileLayerOptions` to set correct attributions. @@ -566,24 +546,6 @@ $livewire->addCircle(Circle::make('circle-name')->lat(...)->lng(...)->options([. $livewire->removeCircle('circle-name'); $livewire->updateCircle(Circle::make('circle-name')->lat(...)->lng(...)->options([...])); ``` - -### Update Map / Polling - -set pollingInterval to anything you like inside your widget: -```php - protected static ?string $pollingInterval = '10s'; -``` - -then inside your widget declare public function named updateMap, and add any logic you wish inside it - -```php - public function updateMap(): void - { - // for example this clears markers, you can add markers, polygon ..etc - $this->mapMarkers([]); - } -``` - ## Images ![Header & Footer](https://raw.githubusercontent.com/webbingbrasil/filament-maps/main/docs/images/image-header-footer.png) diff --git a/composer.json b/composer.json index 534a45e..7455a38 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ ], "require": { "php": "^8.0", - "filament/filament": "^3.0.0", + "filament/filament": "^4.0 || ^5.0", "spatie/laravel-package-tools": "^1.16" }, "autoload": { diff --git a/resources/views/button-action.blade.php b/resources/views/button-action.blade.php index 65af881..d6a88d4 100644 --- a/resources/views/button-action.blade.php +++ b/resources/views/button-action.blade.php @@ -2,5 +2,4 @@ :action="$action" :label="$getLabel()" component="filament-maps::icon-button" - class="filament-page-icon-button-action" /> diff --git a/resources/views/components/actions/action.blade.php b/resources/views/components/actions/action.blade.php index 978eae1..c7f9dce 100644 --- a/resources/views/components/actions/action.blade.php +++ b/resources/views/components/actions/action.blade.php @@ -4,25 +4,34 @@ 'icon' => null, ]) +@php + $isDisabled = $action->isDisabled(); + $url = $action->getUrl(); +@endphp + {{ $slot }} diff --git a/resources/views/components/actions/index.blade.php b/resources/views/components/actions/index.blade.php index 5713eeb..f5a0ad7 100644 --- a/resources/views/components/actions/index.blade.php +++ b/resources/views/components/actions/index.blade.php @@ -1,35 +1,3 @@ -@props([ - 'actions', - 'alignment' => 'left', - 'fullWidth' => false, -]) - -@if ($actions instanceof \Illuminate\Contracts\View\View) - {{ $actions }} -@elseif (is_array($actions)) - @php - $actions = array_filter( - $actions, - fn (\Filament\Pages\Actions\Action | \Filament\Pages\Actions\ActionGroup $action): bool => ! $action->isHidden(), - ); - @endphp - - @if (count($actions)) -
class([ - 'filament-page-actions', - 'flex flex-wrap items-center gap-4' => ! $fullWidth, - match ($alignment) { - 'center' => 'justify-center', - 'right' => 'flex-row-reverse space-x-reverse', - default => 'justify-start', - } => ! $fullWidth, - 'grid gap-2 grid-cols-[repeat(auto-fit,minmax(0,1fr))]' => $fullWidth, - ]) }} - > - @foreach ($actions as $action) - {{ $action }} - @endforeach -
- @endif -@endif + diff --git a/resources/views/components/card/heading.blade.php b/resources/views/components/card/heading.blade.php new file mode 100644 index 0000000..3f81bc8 --- /dev/null +++ b/resources/views/components/card/heading.blade.php @@ -0,0 +1,5 @@ +

class(['fi-maps-card-header-heading text-base font-semibold leading-6 text-gray-950 dark:text-white']) }} +> + {{ $slot }} +

diff --git a/resources/views/components/card/index.blade.php b/resources/views/components/card/index.blade.php new file mode 100644 index 0000000..aa796ca --- /dev/null +++ b/resources/views/components/card/index.blade.php @@ -0,0 +1,60 @@ +@props([ + 'hasBorder' => true, + 'heading' => null, + 'footer' => null, +]) + +@php + $hasHeading = filled($heading); + $hasHeader = $hasHeading; + + $hasFooter = filled($footer); +@endphp + +
+ @if ($hasHeader) +
'px-4 py-2.5', + false => 'px-6 py-4', + } + ])> +
+ @if ($hasHeading) +
+ @if ($hasHeading) + + {{ $heading }} + + @endif +
+ @endif +
+
+ @endif + +
'p-6', + false => '', + }, + ]) + > + {{ $slot }} +
+ + @if ($hasFooter) +
'px-4 py-2.5', + false => 'px-6 py-4', + } + ])> + {{ $footer }} +
+ @endif +
diff --git a/resources/views/components/icon-button.blade.php b/resources/views/components/icon-button.blade.php index aea0ee8..399caa6 100644 --- a/resources/views/components/icon-button.blade.php +++ b/resources/views/components/icon-button.blade.php @@ -1,79 +1,138 @@ +@php + use Filament\Support\Enums\ActionSize; + use Filament\Support\Enums\IconSize; +@endphp + @props([ + 'badge' => null, + 'badgeColor' => 'primary', + 'badgeSize' => 'xs', 'color' => 'primary', - 'darkMode' => config('filament.dark_mode'), 'disabled' => false, 'form' => null, - 'iconAlias' => null, + 'formId' => null, + 'href' => null, 'icon' => null, + 'iconAlias' => null, + 'iconSize' => null, 'keyBindings' => null, - 'indicator' => null, 'label' => null, - 'size' => 'md', + 'loadingIndicator' => true, + 'size' => ActionSize::Medium, + 'spaMode' => null, 'tag' => 'button', + 'target' => null, 'tooltip' => null, 'type' => 'button', ]) @php - $buttonClasses = array_merge([ - "filament-button filament-button-size-{$size} inline-flex items-center justify-center py-1 gap-1 font-medium rounded-lg border transition-colors focus:outline-none focus:ring-offset-2 focus:ring-2 focus:ring-inset", - 'dark:focus:ring-offset-0' => $darkMode, - 'opacity-70 cursor-not-allowed pointer-events-none' => $disabled, - 'min-h-[2.25rem] px-2 text-sm' => $size === 'md', - 'min-h-[2rem] px-1 text-sm' => $size === 'sm', - 'min-h-[2.75rem] px-4 text-lg' => $size === 'lg', - ], [ - 'text-white shadow focus:ring-white border-transparent' => $color !== 'secondary', - 'bg-primary-600 hover:bg-primary-500 focus:bg-primary-700 focus:ring-offset-primary-700' => $color === 'primary', - 'bg-success-600 hover:bg-success-500 focus:bg-success-700 focus:ring-offset-success-700' => $color === 'success', - 'bg-danger-600 hover:bg-danger-500 focus:bg-danger-700 focus:ring-offset-danger-700' => $color === 'danger', - 'bg-warning-600 hover:bg-warning-500 focus:bg-warning-700 focus:ring-offset-warning-700' => $color === 'warning', - 'bg-gray-600 hover:bg-gray-500 focus:bg-gray-700 focus:ring-offset-gray-700' => $color === 'gray', - 'text-gray-800 bg-white border-gray-300 hover:bg-gray-50 focus:ring-primary-600 focus:text-primary-600 focus:bg-primary-50 focus:border-primary-600' => $color === 'secondary', - 'dark:bg-gray-800 dark:hover:bg-gray-700 dark:border-gray-600 dark:hover:border-gray-500 dark:text-gray-200 dark:focus:text-primary-400 dark:focus:border-primary-400 dark:focus:bg-gray-800' => $color === 'secondary' && $darkMode, + if (! $size instanceof ActionSize) { + $size = filled($size) ? (ActionSize::tryFrom($size) ?? $size) : null; + } + + $iconSize ??= match ($size) { + ActionSize::ExtraSmall => IconSize::Small, + ActionSize::Small, ActionSize::Medium => IconSize::Medium, + ActionSize::Large, ActionSize::ExtraLarge => IconSize::Large, + default => IconSize::Medium, + }; + + if (! $iconSize instanceof IconSize) { + $iconSize = filled($iconSize) ? (IconSize::tryFrom($iconSize) ?? $iconSize) : null; + } + + $buttonClasses = \Illuminate\Support\Arr::toCssClasses([ + ...[ + 'fi-icon-btn relative grid-flow-col items-center justify-center font-semibold outline-none transition duration-75 focus-visible:ring-2 shadow-sm rounded-lg', + 'pointer-events-none opacity-70' => $disabled, + 'cursor-pointer' => $tag === 'label', + match ($color) { + 'gray' => null, + default => 'fi-color-custom', + }, + is_string($color) ? "fi-color-{$color}" : null, + ($size instanceof ActionSize) ? "fi-size-{$size->value}" : null, + match ($size) { + ActionSize::ExtraSmall => 'gap-1 px-2 py-1.5 text-xs', + ActionSize::Small => 'gap-1 px-2.5 py-1.5 text-sm', + ActionSize::Medium => 'gap-1.5 px-3 py-2 text-sm', + ActionSize::Large => 'gap-1.5 px-3.5 py-2.5 text-sm', + ActionSize::ExtraLarge => 'gap-1.5 px-4 py-3 text-sm', + default => $size, + }, + 'bg-white text-gray-950 hover:bg-gray-50 dark:bg-white/5 dark:text-white dark:hover:bg-white/10' => ($color === 'gray') || ($tag === 'label'), + 'ring-1 ring-gray-950/10 dark:ring-white/20' => (($color === 'gray') || ($tag === 'label')), + 'bg-custom-600 text-white hover:bg-custom-500 focus-visible:ring-custom-500/50 dark:bg-custom-500 dark:hover:bg-custom-400 dark:focus-visible:ring-custom-400/50' => ($color !== 'gray') && ($tag !== 'label'), + '[input:checked+&]:bg-custom-600 [input:checked+&]:text-white [input:checked+&]:ring-0 [input:checked+&]:hover:bg-custom-500 dark:[input:checked+&]:bg-custom-500 dark:[input:checked+&]:hover:bg-custom-400 [input:checked:focus-visible+&]:ring-custom-500/50 dark:[input:checked:focus-visible+&]:ring-custom-400/50 [input:focus-visible+&]:z-10 [input:focus-visible+&]:ring-2 [input:focus-visible+&]:ring-gray-950/10 dark:[input:focus-visible+&]:ring-white/20' => ($color !== 'gray') && ($tag === 'label'), + '[input:checked+&]:bg-gray-400 [input:checked+&]:text-white [input:checked+&]:ring-0 [input:checked+&]:hover:bg-gray-300 dark:[input:checked+&]:bg-gray-600 dark:[input:checked+&]:hover:bg-gray-500' => ($color === 'gray'), + ], ]); - $iconClasses = \Illuminate\Support\Arr::toCssClasses([ - 'filament-icon-button-icon', - 'w-5 h-5' => $size === 'md', - 'w-4 h-4' => $size === 'sm', - 'w-4 h-4 md:w-5 md:h-5' => $size === 'sm md:md', - 'w-6 h-6' => $size === 'lg', + $buttonStyles = \Illuminate\Support\Arr::toCssStyles([ + \Filament\Support\get_color_css_variables( + $color, + shades: [400, 500, 600], + alias: 'button', + ) => $color !== 'gray', ]); - $indicatorClasses = \Illuminate\Support\Arr::toCssClasses([ - 'filament-icon-button-indicator absolute rounded-full text-xs inline-block w-4 h-4 -top-0.5 -right-0.5', - 'bg-primary-500/10' => $color === 'primary', - 'bg-danger-500/10' => $color === 'danger', - 'bg-gray-500/10' => $color === 'secondary', - 'bg-success-500/10' => $color === 'success', - 'bg-warning-500/10' => $color === 'warning', + $iconClasses = \Illuminate\Support\Arr::toCssClasses([ + 'fi-icon-btn-icon transition duration-75', + match ($iconSize) { + IconSize::Small => 'h-4 w-4', + IconSize::Medium => 'h-5 w-5', + IconSize::Large => 'h-6 w-6', + default => $iconSize, + }, + 'text-gray-400 dark:text-gray-500' => ($color === 'gray') || ($tag === 'label'), + 'text-white' => ($color !== 'gray') && ($tag !== 'label'), + '[:checked+*>&]:text-white' => $tag === 'label', ]); - $hasLoadingIndicator = filled($attributes->get('wire:target')) || filled($attributes->get('wire:click')) || (($type === 'submit') && filled($form)); + $badgeContainerClasses = 'fi-icon-btn-badge-ctn absolute start-full top-1 z-[1] w-max -translate-x-1/2 -translate-y-1/2 rounded-md bg-white dark:bg-gray-900 rtl:translate-x-1/2'; + + $wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null; + + $hasLoadingIndicator = filled($wireTarget) || ($type === 'submit' && filled($form)); if ($hasLoadingIndicator) { - $loadingIndicatorTarget = html_entity_decode($attributes->get('wire:target', $attributes->get('wire:click', $form)), ENT_QUOTES); + $loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES); } + + $hasTooltip = filled($tooltip); @endphp @if ($tag === 'button') @elseif ($tag === 'a') map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }} - @endif - @if ($label) - title="{{ $label }}" + {{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }} + @if ($keyBindings || $hasTooltip) + x-data="{}" @endif - @if ($tooltip) - x-tooltip.raw="{{ $tooltip }}" + @if ($keyBindings) + x-bind:id="$id('key-bindings')" + x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()" @endif - @if ($keyBindings || $tooltip) - x-data="{}" + @if ($hasTooltip) + x-tooltip="{ + content: @js($tooltip), + theme: $store.theme, + }" @endif - {{ $attributes->class($buttonClasses) }} + {{ + $attributes + ->merge([ + 'title' => $hasTooltip ? null : $label, + ], escape: true) + ->class([$buttonClasses]) + ->style([$buttonStyles]) + }} > @if ($label) @@ -137,10 +211,12 @@ :class="$iconClasses" /> - @if ($indicator) - - {{ $indicator }} - + @if (filled($badge)) +
+ + {{ $badge }} + +
@endif
@endif diff --git a/resources/views/components/map.blade.php b/resources/views/components/map.blade.php index 8542bcf..849eb55 100644 --- a/resources/views/components/map.blade.php +++ b/resources/views/components/map.blade.php @@ -12,6 +12,7 @@ 'modals' => null, 'rounded' => true, 'fullpage' => false, + 'pollingInterval' => null, ]) @php @@ -20,7 +21,15 @@ fn (\Webbingbrasil\FilamentMaps\Actions\Action $action ): bool => ! $action->isHidden(), ); @endphp -
+
class([ 'h-full w-full overflow-hidden', @@ -28,6 +37,7 @@ ]) }} {{ $extraAttributeBag }}>
- + diff --git a/resources/views/widgets/map.blade.php b/resources/views/widgets/map.blade.php index e71d3ed..7cafa91 100644 --- a/resources/views/widgets/map.blade.php +++ b/resources/views/widgets/map.blade.php @@ -1,47 +1,20 @@ -@php - $heading = $this->getHeading(); - $footer = $this->getFooter(); - $hasBorder = $this->getHasBorder(); - $rounded = $this->getRounded(); -@endphp - - - @if ($heading) -
$hasBorder, - 'px-6 py-4' => !$hasBorder, - ])> -
- {{ $heading }} -
-
- @endif - -
$hasBorder]) - @if ($pollingInterval = $this->getPollingInterval()) - wire:poll.{{ $pollingInterval }}.visible="updateMap" - @endif - > - -
- - @if ($footer) -
$hasBorder, - 'px-6 py-4' => !$hasBorder, - ])> - {{ $footer }} -
- @endif -
+ + + + - diff --git a/resources/views/zoom-action.blade.php b/resources/views/zoom-action.blade.php index 250458c..4a2426e 100644 --- a/resources/views/zoom-action.blade.php +++ b/resources/views/zoom-action.blade.php @@ -1,19 +1,17 @@ @php - $zoomIn = $action; - $zoomOut = (clone $action)->icon('heroicon-o-minus'); + $zoomIn = $action; + $zoomOut = (clone $action)->icon('heroicon-o-minus'); @endphp diff --git a/src/Widgets/MapWidget.php b/src/Widgets/MapWidget.php index 58b130a..ebcb806 100644 --- a/src/Widgets/MapWidget.php +++ b/src/Widgets/MapWidget.php @@ -30,14 +30,13 @@ abstract class MapWidget extends Widget implements HasForms, HasActions use Concerns\HasPolygones; use Concerns\HasRectangles; use Concerns\HasCircles; + use CanPoll; use Configurable { configure as protected configureWidget; } - protected static string $view = 'filament-maps::widgets.map'; - - protected static ?string $pollingInterval = null; + protected string $view = 'filament-maps::widgets.map'; protected string $height = '400px'; @@ -60,23 +59,16 @@ public function mount() public function configure(): static { - return $this + $this ->configureMarkers() ->configurePolylines() ->configurePolygones() ->configureRectangles() ->configureCircles(); -// ->configureWidget(); - } - protected function getPollingInterval(): ?string - { - return static::$pollingInterval; - } + $this->setUp(); - public function updateMap(): void - { - // Add Code you want to update map with. + return $this; } public function height(string $height): self @@ -136,7 +128,7 @@ public function rounded(bool $rounded = true): self public function getRounded(): bool { - return $this->rounded; + return $this->rounded && $this->getHasBorder(); } public function isFullPage(): bool