mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-21 06:26:26 +00:00
fix(journey): a dead translation key, and two cards that spoke differently
`common.errorOccurred` is in no locale. It sat in the reorder failure toast already and I copied it into three more places, so a failed dismiss, restore or reorder printed the key at the reader. They all say `common.errorTitle` now. The suggestion mark on a phone card was the word spelled out, which took a third of a 136px card and pushed the date off it; it is the same plus the desktop suggestion card offers, and the card's italic dimmed title carries the rest. Dismissing a suggestion from the entry sheet has its own full-width row above the buttons rather than a two-line label wedged between Delete and Cancel. And two cards that should have been one design: the dashboard's spotlight trip wrote its facts in capitals on a panel of dark glass, the journey hero wrote them in sentence case on a gradient with its badge loose in a corner. The journey card is built the way the trip card is now, and the trip card's three pills are set like the DAY x OF y badge beside them, a size down and on the same ground.
This commit is contained in:
@@ -412,9 +412,16 @@ function MSpotlightCard({ trip, t, onOpen, actions }: {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* One fact about the spotlight trip: how long, how many places, how many people.
|
||||
*
|
||||
* Set like the DAY x OF y badge above it, a size down. The three used to be
|
||||
* sentence case while the two badges over them were capitals, so the card had two
|
||||
* voices in the same corner.
|
||||
*/
|
||||
function SpotlightPill({ icon, label }: { icon: React.ReactElement; label: string }): React.ReactElement {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/20 px-[9px] py-[3px] font-geist text-[0.625rem] font-bold text-white backdrop-blur-[6px]">
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/[.28] px-[9px] py-[3px] font-geist text-[0.5625rem] font-bold tracking-[.07em] text-white uppercase backdrop-blur-[6px]">
|
||||
{icon}
|
||||
{label}
|
||||
</span>
|
||||
|
||||
@@ -103,41 +103,47 @@ function HeroCard({ journey, onOpen }: { journey: JourneyListItem; onOpen: () =>
|
||||
const src = journeyCoverSrc(journey.cover_image)
|
||||
|
||||
return (
|
||||
// Built like the dashboard's spotlight trip: the photo carries the card and
|
||||
// everything written sits on one panel of dark glass at its foot, rather than
|
||||
// a badge floating in one corner and text bleeding into a gradient at the
|
||||
// other. Two hero cards, two different languages, was the complaint.
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpen}
|
||||
className="relative mb-3 block h-[180px] w-full overflow-hidden rounded-[22px] text-left shadow-[0_16px_38px_-20px_rgba(0,0,0,.5)]"
|
||||
className="relative mb-3 block h-[220px] w-full overflow-hidden rounded-[26px] text-left shadow-[0_24px_56px_-22px_rgba(0,0,0,.5)]"
|
||||
>
|
||||
{src ? (
|
||||
<img src={src} alt="" className="h-full w-full object-cover" />
|
||||
<img src={src} alt="" className="absolute inset-0 h-full w-full object-cover" />
|
||||
) : (
|
||||
<div className="h-full w-full" style={journeyCoverStyle(journey)} />
|
||||
<div className="absolute inset-0" style={journeyCoverStyle(journey)} />
|
||||
)}
|
||||
<div className="absolute inset-0 bg-[linear-gradient(180deg,rgba(0,0,0,.05)_40%,rgba(0,0,0,.66))]" />
|
||||
<span className="absolute left-[11px] top-[11px] flex items-center gap-1 rounded-full bg-white/90 px-[10px] py-1 font-geist text-[0.59375rem] font-extrabold uppercase tracking-[.04em] text-[#101013]">
|
||||
{t('mobileJourney.latestJourney')}
|
||||
</span>
|
||||
<div className="absolute bottom-[13px] left-[14px] right-[14px] text-white">
|
||||
<div className="truncate text-[1.25rem] font-extrabold">{journey.title}</div>
|
||||
<div className="absolute right-[10px] bottom-[10px] left-[10px] rounded-[18px] border border-white/[.16] bg-[rgba(14,14,17,.52)] p-[12px_14px] text-white backdrop-blur-[22px] backdrop-saturate-[1.6]">{/* theme-lint-disable — fixed dark glass on the cover photo */}
|
||||
<span className="flex gap-[6px]">
|
||||
<span className="rounded-full bg-white/[.92] px-2 py-[3px] text-[0.625rem] font-bold tracking-[.07em] text-[#101013] uppercase">{/* theme-lint-disable — fixed on-photo badge */}
|
||||
{t('mobileJourney.latestJourney')}
|
||||
</span>
|
||||
</span>
|
||||
<div className="mt-[7px] truncate text-[1.4375rem] font-bold">{journey.title}</div>
|
||||
<div className="mt-[9px] flex gap-[6px]">
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/20 px-[9px] py-[3px] font-geist text-[0.59375rem] font-bold backdrop-blur-[6px]">
|
||||
<NotebookPen size={10} strokeWidth={2.2} />
|
||||
{t('mobileJourney.entriesCount', { count: journey.entry_count ?? 0 })}
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/20 px-[9px] py-[3px] font-geist text-[0.59375rem] font-bold backdrop-blur-[6px]">
|
||||
<Image size={10} strokeWidth={2.2} />
|
||||
{t('mobileJourney.photosCount', { count: journey.photo_count ?? 0 })}
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/20 px-[9px] py-[3px] font-geist text-[0.59375rem] font-bold backdrop-blur-[6px]">
|
||||
<MapPin size={10} strokeWidth={2.2} />
|
||||
{t('mobileJourney.placesCount', { count: journey.place_count ?? 0 })}
|
||||
</span>
|
||||
<HeroPill icon={<NotebookPen size={10} strokeWidth={2.2} />} label={t('mobileJourney.entriesCount', { count: journey.entry_count ?? 0 })} />
|
||||
<HeroPill icon={<Image size={10} strokeWidth={2.2} />} label={t('mobileJourney.photosCount', { count: journey.photo_count ?? 0 })} />
|
||||
<HeroPill icon={<MapPin size={10} strokeWidth={2.2} />} label={t('mobileJourney.placesCount', { count: journey.place_count ?? 0 })} />
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
/** One fact about the journey, set like the spotlight trip's pills on the dashboard. */
|
||||
function HeroPill({ icon, label }: { icon: React.ReactElement; label: string }) {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-white/[.28] px-[9px] py-[3px] font-geist text-[0.5625rem] font-bold tracking-[.07em] uppercase backdrop-blur-[6px]">
|
||||
{icon}
|
||||
{label}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
function GridCard({ journey, onOpen }: { journey: JourneyListItem; onOpen: () => void }) {
|
||||
const entries = journey.entry_count ?? 0
|
||||
const photos = journey.photo_count ?? 0
|
||||
|
||||
@@ -158,7 +158,7 @@ export default function MJourneyDetail() {
|
||||
await reorderEntries(current.id, reordered.map(e => e.id))
|
||||
await loadJourney(current.id)
|
||||
} catch {
|
||||
toast.error(t('common.errorOccurred'))
|
||||
toast.error(t('common.errorTitle'))
|
||||
}
|
||||
}, [current, entries, reorderEntries, loadJourney, toast, t])
|
||||
|
||||
|
||||
@@ -963,6 +963,24 @@ export default function MJourneyEntrySheet({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* A suggestion is not deleted, it is put down: the row survives so the trip
|
||||
sync does not offer the same place again (discussion #2299).
|
||||
|
||||
Its own row above the buttons rather than among them: the sentence is
|
||||
longer than a button label and wrapped into two lines between Delete and
|
||||
Cancel. Full width, it reads as what it is, an alternative to saving this
|
||||
suggestion rather than a fourth thing competing with them. */}
|
||||
{!readOnly && onDismiss && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onDismiss}
|
||||
className="mx-[18px] mt-1 mb-[10px] flex flex-none items-center gap-[9px] rounded-[14px] border border-[color:var(--m-rowbr)] bg-[color:var(--m-ic)] px-[13px] py-[10px] text-left"
|
||||
>
|
||||
<EyeOff size={15} strokeWidth={2} className="flex-none text-m-muted" />
|
||||
<span className="min-w-0 flex-1 text-[0.8125rem] font-semibold">{t('journey.suggestions.dismiss')}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="flex flex-none items-center gap-2 border-t border-[color:var(--m-rowbr)] px-[18px] pb-4 pt-3">
|
||||
{!readOnly && onDelete && (
|
||||
<button
|
||||
@@ -974,18 +992,6 @@ export default function MJourneyEntrySheet({
|
||||
{t('common.delete')}
|
||||
</button>
|
||||
)}
|
||||
{/* A suggestion is not deleted, it is put down: the row survives so the trip
|
||||
sync does not offer the same place again (discussion #2299). */}
|
||||
{!readOnly && onDismiss && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onDismiss}
|
||||
className="flex items-center gap-[5px] text-[0.75rem] font-bold text-m-muted"
|
||||
>
|
||||
<EyeOff size={13} strokeWidth={2} />
|
||||
{t('journey.suggestions.dismiss')}
|
||||
</button>
|
||||
)}
|
||||
{!readOnly && captureOnly && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user