feat(planner): restyle Export + SaveToJournal buttons on tokens
Bring the two slotted topbar actions onto the design system so the bar reads as one cohesive surface: - SaveToJournalButton: primary Button primitive; "saved" uses the accent, error uses a new --color-danger token, and the return link gets secondary token styling. - ExportButton: token split-button (secondary look, chevron icon, single divider) and a token dropdown menu (raised surface, soft shadow, muted descriptions). - New --color-danger token (#a03c3c, the no-go hue at full strength) for error text. Behavior and i18n unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2bc6afcf4f
commit
1d3ba956cb
3 changed files with 32 additions and 31 deletions
|
|
@ -52,45 +52,45 @@ export function ExportButton({ yjs }: { yjs: YjsState }) {
|
|||
|
||||
const hasMultipleDays = hasDayBreaks(yjs);
|
||||
|
||||
const item =
|
||||
"block w-full px-3 py-1.5 text-left transition-colors hover:bg-bg-subtle";
|
||||
const split =
|
||||
"h-7 border border-border bg-bg-raised text-sm font-medium text-text-hi transition-colors hover:bg-bg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent";
|
||||
|
||||
return (
|
||||
<div ref={ref} className="relative z-[1001]">
|
||||
<div className="flex">
|
||||
<button
|
||||
onClick={handleExportRoute}
|
||||
className="rounded-l bg-gray-100 px-3 py-1 text-sm text-gray-700 hover:bg-gray-200"
|
||||
className={`${split} rounded-l-md border-r-0 px-3`}
|
||||
>
|
||||
{t("exportGpx")}
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); setOpen((v) => !v); }}
|
||||
className="rounded-r border-l border-gray-300 bg-gray-100 px-2.5 py-1 text-sm text-gray-700 hover:bg-gray-200"
|
||||
aria-label={t("exportGpx")}
|
||||
aria-expanded={open}
|
||||
className={`${split} rounded-r-md px-2 text-text-md`}
|
||||
>
|
||||
▾
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
|
||||
<polyline points="6 9 12 15 18 9" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{open && (
|
||||
<div className="absolute left-0 top-full z-50 mt-1 w-56 rounded border border-gray-200 bg-white py-1 shadow-lg">
|
||||
<button
|
||||
onClick={handleExportRoute}
|
||||
className="block w-full px-3 py-1.5 text-left hover:bg-gray-100"
|
||||
>
|
||||
<span className="text-sm text-gray-700">{t("exportRoute")}</span>
|
||||
<span className="block text-xs text-gray-400">{t("exportRouteDesc")}</span>
|
||||
<div className="absolute left-0 top-full z-50 mt-1 w-56 rounded-md border border-border bg-bg-raised py-1 shadow-md">
|
||||
<button onClick={handleExportRoute} className={item}>
|
||||
<span className="text-sm text-text-hi">{t("exportRoute")}</span>
|
||||
<span className="block text-xs text-text-lo">{t("exportRouteDesc")}</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={handleExportPlan}
|
||||
className="block w-full px-3 py-1.5 text-left hover:bg-gray-100"
|
||||
>
|
||||
<span className="text-sm text-gray-700">{t("exportPlan")}</span>
|
||||
<span className="block text-xs text-gray-400">{t("exportPlanDesc")}</span>
|
||||
<button onClick={handleExportPlan} className={item}>
|
||||
<span className="text-sm text-text-hi">{t("exportPlan")}</span>
|
||||
<span className="block text-xs text-text-lo">{t("exportPlanDesc")}</span>
|
||||
</button>
|
||||
{hasMultipleDays && (
|
||||
<button
|
||||
onClick={handleExportDays}
|
||||
className="block w-full px-3 py-1.5 text-left hover:bg-gray-100"
|
||||
>
|
||||
<span className="text-sm text-gray-700">{t("exportDays")}</span>
|
||||
<span className="block text-xs text-gray-400">{t("exportDaysDesc")}</span>
|
||||
<button onClick={handleExportDays} className={item}>
|
||||
<span className="text-sm text-text-hi">{t("exportDays")}</span>
|
||||
<span className="block text-xs text-text-lo">{t("exportDaysDesc")}</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@trails-cool/ui";
|
||||
import { computeSurfaceBreakdown } from "@trails-cool/map-core";
|
||||
import type { YjsState } from "~/lib/use-yjs";
|
||||
import { buildPlanGpx } from "~/lib/gpx-export";
|
||||
|
|
@ -64,17 +65,16 @@ export function SaveToJournalButton({ yjs, sessionId, returnUrl }: SaveToJournal
|
|||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
className="rounded bg-green-600 px-3 py-1 text-sm text-white hover:bg-green-700 disabled:opacity-50"
|
||||
>
|
||||
<Button variant="primary" size="sm" onClick={handleSave} disabled={saving}>
|
||||
{saving ? t("saving") : t("saveToJournal")}
|
||||
</button>
|
||||
{saved && <span className="text-xs text-green-600">{t("saved")}</span>}
|
||||
{error && <span className="text-xs text-red-600">{error}</span>}
|
||||
</Button>
|
||||
{saved && <span className="text-xs text-accent">{t("saved")}</span>}
|
||||
{error && <span className="text-xs text-danger">{error}</span>}
|
||||
{saved && returnUrl && (
|
||||
<a href={returnUrl} className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-700 hover:bg-gray-200">
|
||||
<a
|
||||
href={returnUrl}
|
||||
className="inline-flex h-7 items-center rounded-md border border-border bg-bg-raised px-2.5 text-xs font-medium text-text-hi transition-colors hover:bg-bg-subtle"
|
||||
>
|
||||
{t("returnToJournal")}
|
||||
</a>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue