Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions resources/views/components/checkbox.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{--
Themed checkbox with an inline label.

The <label> wraps the <input> so clicking the label text toggles the checkbox.
All extra attributes (name, value, wire:model, etc.)
are passed through to the underlying <input> element.

Props:
disabled — disables the input (default: false)

Usage:
<x-checkbox name="remember">Remember me</x-checkbox>
<x-checkbox wire:model="agreed">I agree to the terms</x-checkbox>
--}}
@props(['disabled' => false])

<label class="flex cursor-pointer items-center gap-2 text-sm text-muted">
<input
type="checkbox"
@disabled($disabled)
{{ $attributes->merge(['class' => 'rounded border-border text-accent focus-visible:ring-[var(--color-border-focus)]']) }}
/>
{{ $slot }}
</label>
21 changes: 17 additions & 4 deletions resources/views/components/input-label.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,27 @@
Form field label.

Props:
for — the id of the associated input element
value — label text (alternative to using the slot)
for — the id of the associated input element
value — label text (alternative to using the slot)
compact — renders as xs/uppercase/muted; use for panel section headers
above compact controls (e.g. state selectors in map panels)

Usage:
<x-input-label for="email" value="Email address" />
<x-input-label for="email">Email address</x-input-label>
<x-input-label for="state" compact class="mb-1.5">State</x-input-label>
--}}
@props(['for' => null, 'value' => null])
@props(['for' => null, 'value' => null, 'compact' => false])

@php
$classes = $compact
? 'block text-xs font-medium uppercase tracking-wider text-muted'
: 'block text-sm font-medium text-text';
@endphp

<label
@if ($for) for="{{ $for }}" @endif
{{ $attributes->merge(['class' => 'block text-sm font-medium text-text']) }}
{{ $attributes->merge(['class' => $classes]) }}
>
{{ $value ?? $slot }}
</label>
27 changes: 27 additions & 0 deletions resources/views/components/radio.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{--
Themed radio button with an inline label.

The <label> wraps the <input> so clicking the label text selects the radio.
All extra attributes (x-bind:checked, @change, wire:model, name, value, etc.)
are passed through to the underlying <input> element.

Props:
disabled — disables the input (default: false)

Usage:
<x-radio name="unit" x-bind:checked="unit === 'km'" @change="switchUnit('km')">Kilometers</x-radio>

NOTE: Use x-bind:checked (not the :checked shorthand) for Alpine bindings.
Blade evaluates :attr as PHP on component attributes, causing "Undefined constant"
errors for Alpine JS variables. x-bind:checked bypasses this.
--}}
@props(['disabled' => false])

<label class="flex cursor-pointer items-center gap-2 text-sm text-text">
<input
type="radio"
@disabled($disabled)
{{ $attributes->merge(['class' => 'accent-[var(--color-accent)]']) }}
/>
{{ $slot }}
</label>
62 changes: 24 additions & 38 deletions resources/views/livewire/pages/quake-watch.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@
window.dispatchEvent(new CustomEvent('map-location-set', { detail: { lat, lng, meters: radiusKm * 1000 } }));
$wire.search(lat, lng, radiusKm, minMag, 'UTC')
})"
@map-clicked.window="lat = $event.detail.lat; lng = $event.detail.lng; timezone = $event.detail.timezone ?? 'UTC'"
@map-clicked.window="lat = $event.detail.lat; lng = $event.detail.lng; timezone = $event.detail.timezone ?? 'UTC'; $wire.search(lat, lng, radiusKm, minMag, timezone)"
>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-text">QuakeWatch</h1>
<p class="mt-1 text-sm text-muted">
Click anywhere on the map to set a search origin, then adjust the radius and hit Search.
Click anywhere on the map to search. Adjust the radius and magnitude, then click Search to re-run.
</p>
</div>

Expand All @@ -73,37 +73,37 @@

{{-- Radius input --}}
<div>
<label for="quake-radius" class="mb-1.5 block text-sm font-medium text-text">
<x-input-label for="quake-radius" class="mb-1.5">
Search radius (<span x-text="unit"></span>)
</label>
<input
</x-input-label>
<x-input
id="quake-radius"
type="number"
min="1"
step="1"
placeholder="50"
x-model="radius"
@change="dispatchRadius()"
class="no-spin w-full rounded-lg border border-border bg-surface px-4 py-2.5 text-text placeholder:text-muted focus:border-accent focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/20"
class="no-spin"
/>
</div>

{{-- Minimum magnitude --}}
<div>
<label for="quake-min-mag" class="mb-1.5 block text-sm font-medium text-text">
<x-input-label for="quake-min-mag" class="mb-1.5">
Earthquakes above this magnitude
</label>
<select
</x-input-label>
<x-select
id="quake-min-mag"
x-model.number="minMag"
class="w-full rounded-lg border border-border bg-surface px-4 py-2.5 text-text focus:border-accent focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/20"
class="w-full"
>
<option value="0">Any magnitude</option>
@foreach (range(8, 80) as $step)
@php $val = $step / 10; @endphp
<option value="{{ $val }}">M {{ number_format($val, 1) }}+</option>
@endforeach
</select>
</x-select>
</div>

{{-- Unit toggle --}}
Expand All @@ -112,26 +112,12 @@ class="w-full rounded-lg border border-border bg-surface px-4 py-2.5 text-text f
fires switchUnit(), which sees this.unit already changed and bails early
before converting the radius value. --}}
<div class="flex gap-5">
<label class="flex cursor-pointer items-center gap-2 text-sm text-text">
<input
type="radio"
name="radius-unit"
:checked="unit === 'km'"
@change="switchUnit('km')"
class="accent-[var(--color-accent)]"
/>
<x-radio name="radius-unit" x-bind:checked="unit === 'km'" @change="switchUnit('km')">
Kilometers
</label>
<label class="flex cursor-pointer items-center gap-2 text-sm text-text">
<input
type="radio"
name="radius-unit"
:checked="unit === 'mi'"
@change="switchUnit('mi')"
class="accent-[var(--color-accent)]"
/>
</x-radio>
<x-radio name="radius-unit" x-bind:checked="unit === 'mi'" @change="switchUnit('mi')">
Miles
</label>
</x-radio>
</div>

{{-- Selected location display --}}
Expand Down Expand Up @@ -167,15 +153,15 @@ class="accent-[var(--color-accent)]"
</div>

{{-- Search button --}}
<button
type="button"
:disabled="lat === null"
<x-button
variant="primary"
class="w-full"
x-bind:disabled="lat === null"
@click="$wire.search(lat, lng, radiusKm, minMag, timezone)"
class="w-full rounded-lg bg-accent px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-accent-hover focus:outline-none focus:ring-2 focus:ring-[var(--color-accent)]/40 disabled:cursor-not-allowed disabled:opacity-40"
>
<span wire:loading.remove wire:target="search">Search</span>
<span wire:loading wire:target="search">Searching…</span>
</button>
</x-button>

{{-- Save this search (auth-gated, shown once results exist) --}}
@auth
Expand All @@ -190,13 +176,13 @@ class="w-full rounded-lg bg-accent px-4 py-2.5 text-sm font-semibold text-white
maxlength="100"
class="flex-1 text-sm"
/>
<button
type="button"
<x-button
variant="secondary"
class="shrink-0"
@click="$wire.saveSearch(lat, lng, radiusKm, minMag)"
class="shrink-0 rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm font-medium text-text transition hover:bg-surface-hover"
>
Save
</button>
</x-button>
</div>
@if ($saveMessage)
<p class="mt-2 text-xs {{ $saveSuccess ? 'text-success' : 'text-danger' }}">
Expand Down
Loading