Polish the locale mismatch banner layout
Use a full-bleed bar with clearer actions and a stacked mobile layout so long language labels stay usable. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
import { GlobeIcon, XIcon } from "@phosphor-icons/react";
|
import { GlobeIcon, XIcon } from "@phosphor-icons/react";
|
||||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||||
import { Callout } from "@probo/ui/src/v2/Callout/Callout";
|
|
||||||
import { IconButton } from "@probo/ui/src/v2/IconButton/IconButton";
|
import { IconButton } from "@probo/ui/src/v2/IconButton/IconButton";
|
||||||
|
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { graphql, useFragment } from "react-relay";
|
import { graphql, useFragment } from "react-relay";
|
||||||
@@ -46,8 +46,8 @@ interface LocaleMismatchCalloutProps {
|
|||||||
identityKey: LocaleMismatchCallout_identity$key;
|
identityKey: LocaleMismatchCallout_identity$key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Soft notice when the URL locale differs from the signed-in identity preference.
|
// Full-bleed notice when the URL locale differs from the signed-in identity
|
||||||
// Dismissed state is React-only (no localStorage/cookies).
|
// preference. Dismissed state is React-only (no localStorage/cookies).
|
||||||
export function LocaleMismatchCallout({ identityKey }: LocaleMismatchCalloutProps) {
|
export function LocaleMismatchCallout({ identityKey }: LocaleMismatchCalloutProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const identity = useFragment(localeMismatchCalloutFragment, identityKey);
|
const identity = useFragment(localeMismatchCalloutFragment, identityKey);
|
||||||
@@ -75,45 +75,61 @@ export function LocaleMismatchCallout({ identityKey }: LocaleMismatchCalloutProp
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-b border-sand-6 bg-sand-2 px-4 py-3">
|
<aside
|
||||||
<Callout size={1} variant="soft" color="gold" icon={<GlobeIcon weight="fill" />}>
|
className="flex w-full items-center gap-3 bg-gold-3 px-8 py-2.5 max-md:flex-col max-md:items-stretch max-md:gap-3 max-md:px-4 max-md:py-3"
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
role="status"
|
||||||
<p className="min-w-0 flex-1 text-2 text-sand-12">
|
>
|
||||||
{t("locale.mismatch.message", { language: urlLabel })}
|
<div className="flex min-w-0 flex-1 items-start gap-2">
|
||||||
</p>
|
<GlobeIcon weight="fill" className="mt-0.5 size-4 shrink-0 text-gold-11" aria-hidden />
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<Text size={2} color="neutral" highContrast className="min-w-0 flex-1">
|
||||||
<Button
|
{t("locale.mismatch.message", { language: urlLabel })}
|
||||||
size={1}
|
</Text>
|
||||||
variant="soft"
|
<IconButton
|
||||||
color="neutral"
|
size={1}
|
||||||
disabled={busy}
|
variant="ghost"
|
||||||
onClick={switchToSaved}
|
color="neutral"
|
||||||
>
|
aria-label={t("locale.mismatch.dismiss")}
|
||||||
{t("locale.mismatch.switchToMine", { language: savedLabel })}
|
disabled={busy}
|
||||||
</Button>
|
className="md:hidden"
|
||||||
<Button
|
onClick={() => setDismissed(true)}
|
||||||
size={1}
|
>
|
||||||
variant="solid"
|
<XIcon />
|
||||||
color="neutral"
|
</IconButton>
|
||||||
highContrast
|
</div>
|
||||||
disabled={busy}
|
<div className="flex shrink-0 items-center gap-2 max-md:flex-col max-md:items-stretch">
|
||||||
onClick={adoptUrlLocale}
|
<Button
|
||||||
>
|
size={1}
|
||||||
{t("locale.mismatch.useThis", { language: urlLabel })}
|
variant="solid"
|
||||||
</Button>
|
color="gold"
|
||||||
<IconButton
|
disabled={busy}
|
||||||
size={1}
|
className="max-md:w-full"
|
||||||
variant="ghost"
|
onClick={switchToSaved}
|
||||||
color="neutral"
|
>
|
||||||
aria-label={t("locale.mismatch.dismiss")}
|
{t("locale.mismatch.switchToMine", { language: savedLabel })}
|
||||||
disabled={busy}
|
</Button>
|
||||||
onClick={() => setDismissed(true)}
|
<Button
|
||||||
>
|
size={1}
|
||||||
<XIcon />
|
variant="solid"
|
||||||
</IconButton>
|
color="neutral"
|
||||||
</div>
|
highContrast
|
||||||
</div>
|
disabled={busy}
|
||||||
</Callout>
|
className="max-md:w-full"
|
||||||
</div>
|
onClick={adoptUrlLocale}
|
||||||
|
>
|
||||||
|
{t("locale.mismatch.useThis", { language: urlLabel })}
|
||||||
|
</Button>
|
||||||
|
<IconButton
|
||||||
|
size={1}
|
||||||
|
variant="ghost"
|
||||||
|
color="neutral"
|
||||||
|
aria-label={t("locale.mismatch.dismiss")}
|
||||||
|
disabled={busy}
|
||||||
|
className="max-md:hidden"
|
||||||
|
onClick={() => setDismissed(true)}
|
||||||
|
>
|
||||||
|
<XIcon />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user