fix(web): better alignment on mobile for table views
This commit is contained in:
parent
32c0935124
commit
ff8f0c781e
6 changed files with 89 additions and 36 deletions
|
|
@ -97,7 +97,7 @@
|
|||
{% call table::pagination_header(bags, navigator, "#bag-list") %}
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<table class="responsive-table min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<thead class="bg-amber-200/60 text-xs font-semibold tracking-wide text-amber-900">
|
||||
<tr>
|
||||
{% call table::sortable_header("Roaster", "roaster", navigator, "#bag-list") %} {%
|
||||
|
|
@ -110,13 +110,13 @@
|
|||
<tbody class="divide-y divide-amber-200/70">
|
||||
{% for bag in bags.items %}
|
||||
<tr class="bg-amber-50/40 transition hover:bg-amber-50">
|
||||
<td class="px-4 py-3 whitespace-nowrap font-medium text-stone-600">
|
||||
<td data-label="Roaster" class="px-4 py-3 whitespace-nowrap font-medium text-stone-600">
|
||||
{{ bag.roaster_name }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ bag.roast_name }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ bag.amount }}g</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ bag.created_at }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ bag.finished_at }}</td>
|
||||
<td data-label="Roast" class="px-4 py-3 whitespace-nowrap">{{ bag.roast_name }}</td>
|
||||
<td data-label="Weight" class="px-4 py-3 whitespace-nowrap">{{ bag.amount }}g</td>
|
||||
<td data-label="Added" class="px-4 py-3 whitespace-nowrap">{{ bag.created_at }}</td>
|
||||
<td data-label="Finished" class="px-4 py-3 whitespace-nowrap">{{ bag.finished_at }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
{% call table::pagination_header(brews, navigator, "#brew-list") %}
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<table class="responsive-table min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<thead class="bg-amber-200/60 text-xs font-semibold tracking-wide text-amber-900">
|
||||
<tr>
|
||||
<th scope="col" class="px-4 py-3">Coffee</th>
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
<tbody class="divide-y divide-amber-200/70">
|
||||
{% for brew in brews.items %}
|
||||
<tr class="bg-amber-50/40 transition hover:bg-amber-50">
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Coffee" class="px-4 py-3 whitespace-nowrap">
|
||||
<div class="font-medium text-stone-800">
|
||||
<a href="/roasters/{{ brew.roaster_slug }}/roasts/{{ brew.roast_slug }}" class="hover:text-amber-700 hover:underline">
|
||||
{{ brew.roast_name }}
|
||||
|
|
@ -34,24 +34,24 @@
|
|||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Grind" class="px-4 py-3 whitespace-nowrap">
|
||||
<div>{{ brew.grind_setting }}</div>
|
||||
<div class="text-xs text-stone-500">{{ brew.grinder_name }}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Recipe" class="px-4 py-3 whitespace-nowrap">
|
||||
<div>{{ brew.coffee_weight }} / {{ brew.water_volume }}</div>
|
||||
<div class="text-xs text-stone-500 font-mono">{{ brew.ratio }}</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ brew.water_temp }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Temp" class="px-4 py-3 whitespace-nowrap">{{ brew.water_temp }}</td>
|
||||
<td data-label="Brewer" class="px-4 py-3 whitespace-nowrap">
|
||||
<div>{{ brew.brewer_name }}</div>
|
||||
{% if let Some(fp_name) = brew.filter_paper_name %}
|
||||
<div class="text-xs text-stone-500">{{ fp_name }}</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-stone-500">{{ brew.created_at }}</td>
|
||||
<td data-label="Date" class="px-4 py-3 whitespace-nowrap text-stone-500">{{ brew.created_at }}</td>
|
||||
{% if is_authenticated %}
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td data-label="" class="px-4 py-3 text-right">
|
||||
<form class="inline" data-on:submit="@post('/api/v1/brews?{{ navigator.query() }}', {contentType: 'form', responseOverrides: {selector: '#brew-list', mode: 'replace'}})">
|
||||
<input type="hidden" name="bag_id" value="{{ brew.bag_id }}" />
|
||||
<input type="hidden" name="coffee_weight" value="{{ brew.coffee_weight_raw }}" />
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
{% call table::pagination_header(gear, navigator, "#gear-list") %}
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<table class="responsive-table min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<thead class="bg-amber-200/60 text-xs font-semibold tracking-wide text-amber-900">
|
||||
<tr>
|
||||
{% call table::sortable_header("Category", "category", navigator, "#gear-list") %}
|
||||
|
|
@ -28,22 +28,22 @@
|
|||
<tbody class="divide-y divide-amber-200/70">
|
||||
{% for item in gear.items %}
|
||||
<tr class="bg-amber-50/40 transition hover:bg-amber-50">
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Category" class="px-4 py-3 whitespace-nowrap">
|
||||
<span class="inline-flex rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-800">
|
||||
{{ item.category_label }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap font-medium text-stone-600">
|
||||
<td data-label="Make" class="px-4 py-3 whitespace-nowrap font-medium text-stone-600">
|
||||
{{ item.make }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Model" class="px-4 py-3 whitespace-nowrap">
|
||||
{{ item.model }}
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">
|
||||
<td data-label="Added" class="px-4 py-3 whitespace-nowrap">
|
||||
{{ item.created_at }}
|
||||
</td>
|
||||
{% if is_authenticated %}
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td data-label="" class="px-4 py-3 text-right">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-stone-500 transition hover:text-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<section class="rounded-lg border border-amber-300 bg-amber-100/80 shadow-sm">
|
||||
{% call table::pagination_header(roasts, navigator, "#roast-list") %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<table class="responsive-table min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<thead class="bg-amber-200/60 text-xs font-semibold tracking-wide text-amber-900">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#roast-list") %} {%
|
||||
|
|
@ -36,10 +36,10 @@
|
|||
data-sort-producer="{{ roast.producer }}"
|
||||
class="bg-amber-50/40 transition hover:bg-amber-50"
|
||||
>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-xs font-medium text-stone-600">
|
||||
<td data-label="Added" class="whitespace-nowrap px-4 py-3 text-xs font-medium text-stone-600">
|
||||
{{ roast.created_at }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<td data-label="Roast" class="px-4 py-3">
|
||||
<div class="flex flex-col">
|
||||
<a
|
||||
href="{{ roast.detail_path }}"
|
||||
|
|
@ -48,10 +48,10 @@
|
|||
>
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ roast.roaster_label }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ roast.origin }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ roast.producer }}</td>
|
||||
<td class="px-4 py-3">
|
||||
<td data-label="Roaster" class="px-4 py-3 whitespace-nowrap">{{ roast.roaster_label }}</td>
|
||||
<td data-label="Origin" class="px-4 py-3 whitespace-nowrap">{{ roast.origin }}</td>
|
||||
<td data-label="Producer" class="px-4 py-3 whitespace-nowrap">{{ roast.producer }}</td>
|
||||
<td data-label="Notes" class="px-4 py-3">
|
||||
{% if roast.tasting_notes.is_empty() %}
|
||||
<span class="text-xs text-stone-500">No tasting notes yet.</span>
|
||||
{% else %}
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
{% endif %}
|
||||
</td>
|
||||
{% if is_authenticated %}
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td data-label="" class="px-4 py-3 text-right">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-stone-500 transition hover:text-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<section class="rounded-lg border border-amber-300 bg-amber-100/80 shadow-sm">
|
||||
{% call table::pagination_header(roasters, navigator, "#roaster-list") %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<table class="responsive-table min-w-full divide-y divide-amber-200 text-left text-sm text-stone-700">
|
||||
<thead class="bg-amber-200/60 text-xs font-semibold tracking-wide text-amber-900">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#roaster-list") %} {%
|
||||
|
|
@ -37,19 +37,19 @@
|
|||
data-sort-city="{{ roaster.city }}"
|
||||
class="bg-amber-50/40 transition hover:bg-amber-50"
|
||||
>
|
||||
<td class="whitespace-nowrap px-4 py-3 text-xs font-medium text-stone-600">
|
||||
<td data-label="Added" class="whitespace-nowrap px-4 py-3 text-xs font-medium text-stone-600">
|
||||
{{ roaster.created_at }}
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<td data-label="Name" class="px-4 py-3">
|
||||
<a
|
||||
href="{{ roaster.detail_path }}"
|
||||
class="font-semibold text-amber-800 hover:text-amber-600"
|
||||
>{{ roaster.name }}</a
|
||||
>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ roaster.country }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap">{{ roaster.city }}</td>
|
||||
<td class="px-4 py-3">
|
||||
<td data-label="Country" class="px-4 py-3 whitespace-nowrap">{{ roaster.country }}</td>
|
||||
<td data-label="City" class="px-4 py-3 whitespace-nowrap">{{ roaster.city }}</td>
|
||||
<td data-label="Homepage" class="mobile-hidden px-4 py-3">
|
||||
{% if roaster.has_homepage %}
|
||||
<a
|
||||
class="inline-flex items-center justify-center rounded-md border border-amber-400 bg-amber-200/50 p-2 text-amber-800 transition hover:border-amber-500 hover:text-amber-900"
|
||||
|
|
@ -73,9 +73,9 @@
|
|||
<span class="text-stone-400">—</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-stone-600">{{ roaster.notes }}</td>
|
||||
<td data-label="Notes" class="mobile-hidden px-4 py-3 text-sm text-stone-600">{{ roaster.notes }}</td>
|
||||
{% if is_authenticated %}
|
||||
<td class="px-4 py-3 text-right">
|
||||
<td data-label="" class="px-4 py-3 text-right">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-stone-500 transition hover:text-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
|
||||
|
|
|
|||
|
|
@ -96,6 +96,59 @@ a {
|
|||
display: block;
|
||||
}
|
||||
|
||||
/* Responsive tables: convert rows to cards on mobile */
|
||||
@media (max-width: 767px) {
|
||||
.responsive-table thead {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.responsive-table tbody {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.responsive-table tr {
|
||||
display: block;
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid rgba(217, 169, 55, 0.35);
|
||||
}
|
||||
|
||||
.responsive-table tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.responsive-table td {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
padding: 0.25rem 0;
|
||||
white-space: normal;
|
||||
font-size: 0.875rem; /* normalize all values to text-sm */
|
||||
}
|
||||
|
||||
.responsive-table td::before {
|
||||
content: attr(data-label);
|
||||
flex-shrink: 0;
|
||||
min-width: 5.5rem;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: #78350f; /* amber-900 */
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
|
||||
.responsive-table td[data-label=""]::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.responsive-table td[data-label=""] {
|
||||
justify-content: flex-end;
|
||||
padding-top: 0.25rem;
|
||||
}
|
||||
|
||||
.responsive-table td.mobile-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop: alternating cards with central line */
|
||||
@media (min-width: 768px) {
|
||||
.timeline-heading {
|
||||
|
|
|
|||
Loading…
Reference in a new issue