Streamline UI: hide map filters on mobile, icon-only buttons, collapse multilingual country names
Reduces clutter on small screens and in the header/toolbar by trimming labels down to icons, and shows a single primary country name instead of full slash-separated translations. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
8d4448b28c
commit
1cb9a2e133
5 changed files with 42 additions and 20 deletions
|
|
@ -22,9 +22,23 @@ export function AppShell() {
|
||||||
{user?.isAdmin && <NavLink to="/admin/users">Users</NavLink>}
|
{user?.isAdmin && <NavLink to="/admin/users">Users</NavLink>}
|
||||||
</nav>
|
</nav>
|
||||||
<div className="app-user">
|
<div className="app-user">
|
||||||
<span className="app-user-name">{user?.displayName || user?.username}</span>
|
<button
|
||||||
<button type="button" className="btn btn-ghost" onClick={handleLogout}>
|
type="button"
|
||||||
Log out
|
className="btn btn-ghost btn-icon"
|
||||||
|
onClick={handleLogout}
|
||||||
|
aria-label="Log out"
|
||||||
|
title="Log out"
|
||||||
|
>
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M15 17l5-5-5-5M20 12H9M12 19H6a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h6"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ import type { City } from '@citytracker/shared';
|
||||||
|
|
||||||
export function cityMarkerIcon(city: City): L.DivIcon {
|
export function cityMarkerIcon(city: City): L.DivIcon {
|
||||||
const color = city.status === 'visited' ? '#2f9e44' : '#1971c2';
|
const color = city.status === 'visited' ? '#2f9e44' : '#1971c2';
|
||||||
const heart = city.liked ? '<span class="marker-heart">♥</span>' : '';
|
|
||||||
return L.divIcon({
|
return L.divIcon({
|
||||||
className: 'city-marker',
|
className: 'city-marker',
|
||||||
html: `<span class="marker-pin" style="background:${color}"></span>${heart}`,
|
html: `<span class="marker-pin" style="background:${color}"></span>`,
|
||||||
iconSize: [22, 22],
|
iconSize: [22, 22],
|
||||||
iconAnchor: [11, 11],
|
iconAnchor: [11, 11],
|
||||||
popupAnchor: [0, -14],
|
popupAnchor: [0, -14],
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
import { useCities } from '../hooks/useCities';
|
import { useCities } from '../hooks/useCities';
|
||||||
|
|
||||||
|
function primaryCountryName(country: string): string {
|
||||||
|
return country.split('/')[0].trim();
|
||||||
|
}
|
||||||
|
|
||||||
export function CityListPage() {
|
export function CityListPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
@ -62,7 +66,7 @@ export function CityListPage() {
|
||||||
{city.name}
|
{city.name}
|
||||||
{city.liked && <span className="cities-table-heart"> ♥</span>}
|
{city.liked && <span className="cities-table-heart"> ♥</span>}
|
||||||
</td>
|
</td>
|
||||||
<td>{city.country}</td>
|
<td>{primaryCountryName(city.country)}</td>
|
||||||
<td>
|
<td>
|
||||||
<span className={`badge badge-${city.status}`}>
|
<span className={`badge badge-${city.status}`}>
|
||||||
{city.status === 'visited' ? 'Visited' : 'Planned'}
|
{city.status === 'visited' ? 'Visited' : 'Planned'}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,14 @@ export function MapDashboardPage() {
|
||||||
) : (
|
) : (
|
||||||
<CityMap cities={cities ?? []} focusCity={latestCity} />
|
<CityMap cities={cities ?? []} focusCity={latestCity} />
|
||||||
)}
|
)}
|
||||||
<button type="button" className="btn btn-primary fab" onClick={() => navigate('/cities/new')}>
|
<button
|
||||||
+ Add city
|
type="button"
|
||||||
|
className="btn btn-primary fab"
|
||||||
|
onClick={() => navigate('/cities/new')}
|
||||||
|
aria-label="Add city"
|
||||||
|
title="Add city"
|
||||||
|
>
|
||||||
|
+
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,11 @@ a {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
padding: var(--spacing-2);
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* App shell */
|
/* App shell */
|
||||||
|
|
||||||
.app-shell {
|
.app-shell {
|
||||||
|
|
@ -154,10 +159,6 @@ a {
|
||||||
gap: var(--spacing-3);
|
gap: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-user-name {
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-main {
|
.app-main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
@ -256,6 +257,12 @@ a {
|
||||||
background: var(--color-bg);
|
background: var(--color-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.map-filters {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
padding: var(--spacing-1) var(--spacing-3);
|
padding: var(--spacing-1) var(--spacing-3);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
|
|
@ -299,14 +306,6 @@ a {
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.marker-heart {
|
|
||||||
position: absolute;
|
|
||||||
top: -8px;
|
|
||||||
right: -6px;
|
|
||||||
color: #e64980;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.map-popup {
|
.map-popup {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue