Skip to main content

Content & marketing

Map Marker List code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/map-marker-list.blade.php

@props([
    'markers' => [],
    'paths' => [],
    'allowPlacement' => false,
    'placementLabel' => 'Waypoint',
])

@php
    $markerItems = collect($markers)->values();
    $pathItems = collect($paths)->values();
    $sequentialPath = $pathItems->contains(fn (array $path): bool => (bool) ($path['sequential'] ?? false));

    $markerVariant = function (array $marker): string {
        $explicit = strtolower((string) ($marker['variant'] ?? ''));

        if (in_array($explicit, ['brand', 'red', 'amber', 'green', 'blue', 'gray'], true)) {
            return $explicit;
        }

        return match (strtolower((string) ($marker['type'] ?? ''))) {
            'city' => 'brand',
            'town', 'village' => 'amber',
            'military', 'danger' => 'red',
            'supply', 'medical' => 'green',
            'objective', 'waypoint' => 'blue',
            'neutral' => 'gray',
            default => 'brand',
        };
    };

    $markerInitial = function (array $marker): string {
        $label = trim((string) ($marker['label'] ?? $marker['title'] ?? ''));

        return $label !== '' ? strtoupper(substr($label, 0, 1)) : '•';
    };
@endphp

<div {{ $attributes }}>
    @if ($pathItems->isNotEmpty())
        <div class="mb-3 space-y-2 border-b border-gray-200 px-2 pb-3 dark:border-gray-800">
            @foreach ($pathItems as $path)
                @php
                    $pathVariant = match (strtolower((string) ($path['variant'] ?? 'brand'))) {
                        'red' => 'red',
                        'amber' => 'amber',
                        'green' => 'green',
                        'blue' => 'blue',
                        'gray' => 'gray',
                        default => 'brand',
                    };
                @endphp

                <div class="flex items-center gap-2 rounded-lg bg-gray-50 px-2.5 py-2 dark:bg-gray-950/60">
                    <span @class([
                        'h-0.5 w-5 rounded-full',
                        'bg-brand-600' => $pathVariant === 'brand',
                        'bg-red-600' => $pathVariant === 'red',
                        'bg-amber-600' => $pathVariant === 'amber',
                        'bg-green-600' => $pathVariant === 'green',
                        'bg-accent-600' => $pathVariant === 'blue',
                        'bg-gray-600' => $pathVariant === 'gray',
                    ])></span>
                    <span class="min-w-0 truncate text-xs font-semibold text-gray-700 dark:text-gray-300">
                        {{ $path['label'] ?? 'Path' }}
                    </span>
                    @if ($path['sequential'] ?? false)
                        <x-ui.badge variant="gray" size="sm">Sequential</x-ui.badge>
                    @endif
                </div>
            @endforeach
        </div>
    @endif

    <ul class="space-y-1" data-map-marker-list>
        @unless ($allowPlacement)
            @foreach ($markerItems as $index => $marker)
                @php
                    $variant = $markerVariant($marker);
                    $badgeVariant = match ($variant) {
                        'red' => 'red',
                        'amber' => 'amber',
                        'green' => 'green',
                        'blue' => 'blue',
                        'gray' => 'gray',
                        default => 'brand',
                    };
                @endphp

                <li>
                    <button
                        type="button"
                        data-map-marker-item
                        data-map-marker-index="{{ $index }}"
                        class="harbour-map-marker-list-item group flex w-full items-start gap-3 rounded-xl px-3 py-2.5 text-left transition hover:bg-gray-50 dark:hover:bg-gray-800/60"
                    >
                        <span @class([
                            'inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg text-xs font-bold ring-1',
                            'bg-brand-50 text-brand-700 ring-brand-100 dark:bg-brand-950/60 dark:text-brand-300 dark:ring-brand-900/60' => $variant === 'brand',
                            'bg-red-50 text-red-700 ring-red-100 dark:bg-red-950/60 dark:text-red-300 dark:ring-red-900/60' => $variant === 'red',
                            'bg-amber-50 text-amber-700 ring-amber-100 dark:bg-amber-950/60 dark:text-amber-300 dark:ring-amber-900/60' => $variant === 'amber',
                            'bg-green-50 text-green-700 ring-green-100 dark:bg-green-950/60 dark:text-green-300 dark:ring-green-900/60' => $variant === 'green',
                            'bg-accent-50 text-accent-700 ring-accent-100 dark:bg-accent-950/60 dark:text-accent-300 dark:ring-accent-900/60' => $variant === 'blue',
                            'bg-gray-100 text-gray-700 ring-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:ring-gray-700' => $variant === 'gray',
                        ])>
                            {{ $markerInitial($marker) }}
                        </span>

                        <span class="min-w-0 flex-1">
                            <span class="flex items-center gap-2">
                                @if (isset($marker['order']) || ($sequentialPath && $markerItems->count() > 1))
                                    <span class="inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-gray-100 px-1.5 text-[0.6875rem] font-bold tabular-nums text-gray-600 dark:bg-gray-800 dark:text-gray-300">
                                        {{ $marker['order'] ?? ($index + 1) }}
                                    </span>
                                @endif

                                <span class="truncate text-sm font-semibold text-gray-900 dark:text-white">
                                    {{ $marker['label'] ?? $marker['title'] ?? 'Map marker' }}
                                </span>
                            </span>

                            @if (filled($marker['type'] ?? null))
                                <x-ui.badge :variant="$badgeVariant" size="sm" class="mt-1">{{ $marker['type'] }}</x-ui.badge>
                            @endif

                            @if (filled($marker['description'] ?? null))
                                <span class="mt-1 block line-clamp-2 text-xs leading-5 text-gray-500 dark:text-gray-400">
                                    {{ $marker['description'] }}
                                </span>
                            @endif

                            @if (isset($marker['x'], $marker['z']))
                                <span class="mt-1 block text-[0.6875rem] font-semibold uppercase tracking-wide text-gray-400 dark:text-gray-500">
                                    X {{ number_format((float) $marker['x'], 0) }} / Z {{ number_format((float) $marker['z'], 0) }}
                                </span>
                            @endif
                        </span>

                        <x-ui.icon name="arrow-right" size="sm" class="mt-1 shrink-0 text-gray-300 transition group-hover:text-brand-600 dark:text-gray-600 dark:group-hover:text-brand-400" />
                    </button>
                </li>
            @endforeach
        @else
            <li data-map-marker-empty class="rounded-xl px-3 py-8 text-center text-sm text-gray-500 dark:text-gray-400">
                Click the map to place your first {{ Str::lower($placementLabel) }}.
            </li>
        @endunless
    </ul>
</div>