Split Link/Anchor from button navigators
Rename button-styled Link/Anchor to ButtonLink/ ButtonAnchor and add underlined text Link/Anchor so names match look and element. Hero meta uses plain Anchors for contact and custom links. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
import { EnvelopeIcon, GlobeSimpleIcon, MapPinSimpleIcon } from "@phosphor-icons/react";
|
||||
import { Anchor } from "@probo/ui/src/v2/Link/Anchor";
|
||||
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
|
||||
@@ -39,8 +40,8 @@ interface CompliancePortalContactInfoProps {
|
||||
compliancePortalKey: CompliancePortalContactInfo_compliancePortal$key;
|
||||
}
|
||||
|
||||
// Compliance portal contact details (website, email, HQ) rendered as an icon +
|
||||
// label row. Owns its fragment so it can be reused wherever the portal is in scope.
|
||||
// Compliance portal contact details (website, email, HQ) rendered as icon +
|
||||
// label items for the shared hero meta row. The parent band owns the divider.
|
||||
export function CompliancePortalContactInfo({ compliancePortalKey }: CompliancePortalContactInfoProps) {
|
||||
const compliancePortal = useFragment(compliancePortalContactInfoFragment, compliancePortalKey);
|
||||
|
||||
@@ -48,35 +49,39 @@ export function CompliancePortalContactInfo({ compliancePortalKey }: ComplianceP
|
||||
const hasEmail = compliancePortal.email != null && compliancePortal.email !== "";
|
||||
const hasAddress = compliancePortal.headquarterAddress != null && compliancePortal.headquarterAddress !== "";
|
||||
|
||||
// Nothing to show — render no row (and therefore no divider) at all.
|
||||
if (!hasWebsite && !hasEmail && !hasAddress) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { root, item, link } = organizationContactInfo();
|
||||
const { item, link } = organizationContactInfo();
|
||||
|
||||
return (
|
||||
<div className={root()}>
|
||||
<>
|
||||
{hasWebsite && (
|
||||
<a
|
||||
<Anchor
|
||||
className={link()}
|
||||
href={externalHref(compliancePortal.websiteUrl)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size={2}
|
||||
color="neutral"
|
||||
underline={false}
|
||||
iconStart={<GlobeSimpleIcon />}
|
||||
>
|
||||
<GlobeSimpleIcon />
|
||||
<Text size={2} color="neutral">
|
||||
{hostnameOf(compliancePortal.websiteUrl)}
|
||||
</Text>
|
||||
</a>
|
||||
{hostnameOf(compliancePortal.websiteUrl)}
|
||||
</Anchor>
|
||||
)}
|
||||
{hasEmail && (
|
||||
<a className={link()} href={`mailto:${compliancePortal.email}`}>
|
||||
<EnvelopeIcon />
|
||||
<Text size={2} color="neutral">
|
||||
{compliancePortal.email}
|
||||
</Text>
|
||||
</a>
|
||||
<Anchor
|
||||
className={link()}
|
||||
href={`mailto:${compliancePortal.email}`}
|
||||
size={2}
|
||||
color="neutral"
|
||||
underline={false}
|
||||
iconStart={<EnvelopeIcon />}
|
||||
>
|
||||
{compliancePortal.email}
|
||||
</Anchor>
|
||||
)}
|
||||
{hasAddress && (
|
||||
<div className={item()}>
|
||||
@@ -86,6 +91,6 @@ export function CompliancePortalContactInfo({ compliancePortalKey }: ComplianceP
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import {
|
||||
FacebookLogoIcon,
|
||||
GlobeSimpleIcon,
|
||||
type Icon,
|
||||
LinkedinLogoIcon,
|
||||
XLogoIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { detectSocialName } from "@probo/helpers";
|
||||
import { Anchor } from "@probo/ui/src/v2/Link/Anchor";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
|
||||
import { externalHref } from "#/lib/url/hostname";
|
||||
|
||||
import type { CompliancePortalCustomLinks_compliancePortal$key } from "./__generated__/CompliancePortalCustomLinks_compliancePortal.graphql";
|
||||
import { organizationContactInfo } from "./variants";
|
||||
|
||||
const compliancePortalCustomLinksFragment = graphql`
|
||||
fragment CompliancePortalCustomLinks_compliancePortal on CompliancePortal {
|
||||
customLinks(first: 20) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface CompliancePortalCustomLinksProps {
|
||||
compliancePortalKey: CompliancePortalCustomLinks_compliancePortal$key;
|
||||
}
|
||||
|
||||
function iconForUrl(url: string): Icon {
|
||||
switch (detectSocialName(url)) {
|
||||
case "LinkedIn":
|
||||
return LinkedinLogoIcon;
|
||||
case "X":
|
||||
return XLogoIcon;
|
||||
case "Facebook":
|
||||
return FacebookLogoIcon;
|
||||
default:
|
||||
return GlobeSimpleIcon;
|
||||
}
|
||||
}
|
||||
|
||||
// Organization custom links (social / external URLs) as icon + label items,
|
||||
// appended after contact details in the shared hero meta row.
|
||||
export function CompliancePortalCustomLinks({
|
||||
compliancePortalKey,
|
||||
}: CompliancePortalCustomLinksProps) {
|
||||
const compliancePortal = useFragment(
|
||||
compliancePortalCustomLinksFragment,
|
||||
compliancePortalKey,
|
||||
);
|
||||
const links = compliancePortal.customLinks.edges.map(edge => edge.node);
|
||||
|
||||
if (links.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { link } = organizationContactInfo();
|
||||
|
||||
return (
|
||||
<>
|
||||
{links.map((customLink) => {
|
||||
const Icon = iconForUrl(customLink.url);
|
||||
|
||||
return (
|
||||
<Anchor
|
||||
key={customLink.id}
|
||||
className={link()}
|
||||
href={externalHref(customLink.url)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size={2}
|
||||
color="neutral"
|
||||
underline={false}
|
||||
iconStart={<Icon />}
|
||||
>
|
||||
{customLink.name}
|
||||
</Anchor>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
|
||||
import type { CompliancePortalHeroMeta_compliancePortal$key } from "./__generated__/CompliancePortalHeroMeta_compliancePortal.graphql";
|
||||
import { CompliancePortalContactInfo } from "./CompliancePortalContactInfo";
|
||||
import { CompliancePortalCustomLinks } from "./CompliancePortalCustomLinks";
|
||||
import { organizationContactInfo } from "./variants";
|
||||
|
||||
const compliancePortalHeroMetaFragment = graphql`
|
||||
fragment CompliancePortalHeroMeta_compliancePortal on CompliancePortal {
|
||||
websiteUrl
|
||||
email
|
||||
headquarterAddress
|
||||
customLinks(first: 20) {
|
||||
edges {
|
||||
__typename
|
||||
}
|
||||
}
|
||||
...CompliancePortalContactInfo_compliancePortal
|
||||
...CompliancePortalCustomLinks_compliancePortal
|
||||
}
|
||||
`;
|
||||
|
||||
interface CompliancePortalHeroMetaProps {
|
||||
compliancePortalKey: CompliancePortalHeroMeta_compliancePortal$key;
|
||||
}
|
||||
|
||||
// Shared hero bottom band: contact details and custom links in one row with a
|
||||
// single top divider. Hidden entirely when both are empty.
|
||||
export function CompliancePortalHeroMeta({
|
||||
compliancePortalKey,
|
||||
}: CompliancePortalHeroMetaProps) {
|
||||
const compliancePortal = useFragment(
|
||||
compliancePortalHeroMetaFragment,
|
||||
compliancePortalKey,
|
||||
);
|
||||
|
||||
const hasWebsite = compliancePortal.websiteUrl != null && compliancePortal.websiteUrl !== "";
|
||||
const hasEmail = compliancePortal.email != null && compliancePortal.email !== "";
|
||||
const hasAddress
|
||||
= compliancePortal.headquarterAddress != null && compliancePortal.headquarterAddress !== "";
|
||||
const hasContact = hasWebsite || hasEmail || hasAddress;
|
||||
const hasCustomLinks = compliancePortal.customLinks.edges.length > 0;
|
||||
|
||||
if (!hasContact && !hasCustomLinks) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { root } = organizationContactInfo();
|
||||
|
||||
return (
|
||||
<div className={root()}>
|
||||
<CompliancePortalContactInfo compliancePortalKey={compliancePortal} />
|
||||
<CompliancePortalCustomLinks compliancePortalKey={compliancePortal} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -34,8 +34,8 @@ export interface HeroProps {
|
||||
|
||||
// Landing hero (home): a size-8 title (+ optional description) in the shared
|
||||
// white band, plus an optional bottom slot for page-specific content (the org
|
||||
// contact row). The slot content owns its own divider/spacing so it disappears
|
||||
// cleanly when empty.
|
||||
// meta row: contact + custom links). The slot content owns its own
|
||||
// divider/spacing so it disappears cleanly when empty.
|
||||
export function Hero({ title, description, children }: HeroProps) {
|
||||
const { content, section } = hero();
|
||||
|
||||
|
||||
@@ -25,12 +25,14 @@ import { HeaderBand } from "#/components/HeaderBand/HeaderBand";
|
||||
|
||||
import { hero, organizationContactInfo } from "./variants";
|
||||
|
||||
// Width per contact item, roughly sized to its typical content (hostname /
|
||||
// email / address). See .cursor/rules/skeleton-width-sync.mdc.
|
||||
const CONTACT_ITEMS = [
|
||||
// Width per meta item, roughly sized to its typical content (hostname /
|
||||
// email / address / custom link). See .cursor/rules/skeleton-width-sync.mdc.
|
||||
const META_ITEMS = [
|
||||
{ key: "website", width: "w-28" },
|
||||
{ key: "email", width: "w-40" },
|
||||
{ key: "location", width: "w-36" },
|
||||
{ key: "customLink1", width: "w-24" },
|
||||
{ key: "customLink2", width: "w-16" },
|
||||
] as const;
|
||||
|
||||
// Loading placeholder paired with Hero: reuses the same layout slots with
|
||||
@@ -47,9 +49,9 @@ export function HeroSkeleton() {
|
||||
<TextSkeleton size={2} className="w-full max-w-2xl" />
|
||||
</div>
|
||||
<div className={root()}>
|
||||
{CONTACT_ITEMS.map(contact => (
|
||||
<div key={contact.key} className={item()}>
|
||||
<TextSkeleton size={2} className={contact.width} />
|
||||
{META_ITEMS.map(meta => (
|
||||
<div key={meta.key} className={item()}>
|
||||
<TextSkeleton size={2} className={meta.width} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
import { tv } from "tailwind-variants/lite";
|
||||
|
||||
// Landing hero content rendered inside the shared HeaderBand: a centered
|
||||
// title/description section above an optional bottom slot (the contact row).
|
||||
// Slots are shared by the live Hero and its skeleton.
|
||||
// title/description section above an optional bottom slot (contact + custom
|
||||
// links). Slots are shared by the live Hero and its skeleton.
|
||||
export const hero = tv({
|
||||
slots: {
|
||||
content: "flex w-full flex-col gap-10",
|
||||
@@ -30,14 +30,15 @@ export const hero = tv({
|
||||
},
|
||||
});
|
||||
|
||||
// Organization contact block: a horizontal row of icon + label items, with a
|
||||
// top divider so it reads as the hero's bottom section. Self-contained so the
|
||||
// divider only appears when there is contact info to show.
|
||||
// Hero meta band: contact details and custom links as one icon + label row,
|
||||
// with a single top divider. Link chrome comes from v2 Anchor; these slots
|
||||
// only own the band layout and non-link items (HQ address).
|
||||
export const organizationContactInfo = tv({
|
||||
slots: {
|
||||
// Only a top divider gap; the band's py-8 provides the bottom spacing.
|
||||
root: "flex w-full flex-wrap items-center gap-x-6 gap-y-2 border-t border-sand-a2 pt-4 max-md:flex-col max-md:items-start",
|
||||
item: "flex min-w-0 items-center gap-2 text-sand-11 [&_svg]:size-5 [&_svg]:shrink-0 [&>*]:min-w-0 [&>*:not(svg)]:break-words",
|
||||
link: "flex min-w-0 items-center gap-2 text-sand-11 hover:underline [&_svg]:size-5 [&_svg]:shrink-0 [&>*]:min-w-0 [&>*:not(svg)]:break-all",
|
||||
item: "flex min-w-0 items-center gap-2 text-sand-11 [&_svg]:size-4 [&_svg]:shrink-0 *:min-w-0 [&>*:not(svg)]:wrap-break-word",
|
||||
// Layout extras on top of Anchor (underline/color/size live on Anchor).
|
||||
link: "min-w-0 max-w-full [&>:not(svg)]:break-all",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { ErrorBoundary } from "@probo/ui/src/v2/ErrorBoundary/ErrorBoundary";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
@@ -84,9 +84,9 @@ function RecentUpdatesSectionContent({ compliancePortalKey }: RecentUpdatesSecti
|
||||
<HomeSection
|
||||
title={t("home.sections.recentUpdates")}
|
||||
action={(
|
||||
<Link to={localizedPath("/updates")} variant="ghost" color="neutral" size={2}>
|
||||
<ButtonLink to={localizedPath("/updates")} variant="ghost" color="neutral" size={2}>
|
||||
{t("home.recentUpdates.viewAll")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
)}
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-5 border border-sand-3 bg-sand-1">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import { LockSimpleIcon } from "@phosphor-icons/react";
|
||||
import { Avatar } from "@probo/ui/src/v2/Avatar/Avatar";
|
||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { graphql, useFragment } from "react-relay";
|
||||
@@ -103,7 +103,7 @@ export function TopBar({ queryKey }: TopBarProps) {
|
||||
{TOP_BAR_NAV_ITEMS.map((item) => {
|
||||
const to = localizedPath(item.to);
|
||||
return (
|
||||
<Link
|
||||
<ButtonLink
|
||||
key={item.to}
|
||||
to={to}
|
||||
variant="ghost"
|
||||
@@ -112,7 +112,7 @@ export function TopBar({ queryKey }: TopBarProps) {
|
||||
active={isActive(pathname, to)}
|
||||
>
|
||||
{t(item.labelKey)}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
);
|
||||
})}
|
||||
{data.viewer == null
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
XIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Drawer } from "@probo/ui/src/v2/Drawer/Drawer";
|
||||
import { DrawerBody } from "@probo/ui/src/v2/Drawer/DrawerBody";
|
||||
import { DrawerClose } from "@probo/ui/src/v2/Drawer/DrawerClose";
|
||||
@@ -133,7 +133,7 @@ export function TopBarMobileNav({ identityKey }: TopBarMobileNavProps) {
|
||||
{TOP_BAR_NAV_ITEMS.map((item) => {
|
||||
const to = localizedPath(item.to);
|
||||
return (
|
||||
<Link
|
||||
<ButtonLink
|
||||
key={item.to}
|
||||
to={to}
|
||||
variant="ghost"
|
||||
@@ -144,7 +144,7 @@ export function TopBarMobileNav({ identityKey }: TopBarMobileNavProps) {
|
||||
onClick={close}
|
||||
>
|
||||
{t(item.labelKey)}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
import { FileTextIcon } from "@phosphor-icons/react";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -72,14 +72,14 @@ export function UnsignedNDABanner({ compliancePortalKey }: UnsignedNDABannerProp
|
||||
</Text>
|
||||
)}
|
||||
actions={(
|
||||
<Link
|
||||
<ButtonLink
|
||||
to={ndaHref}
|
||||
size={1}
|
||||
variant="ghost"
|
||||
color="amber"
|
||||
>
|
||||
{t("nda.unsignedBanner.sign")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
)}
|
||||
dismissLabel={t("nda.unsignedBanner.dismiss")}
|
||||
onDismiss={() => setDismissed(true)}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import { ForbiddenError, InternalServerError, UnAuthenticatedError } from "@probo/relay";
|
||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { ErrorState } from "@probo/ui/src/v2/ErrorState/ErrorState";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@@ -76,9 +76,9 @@ export function GlobalError({ error, onRetry, fullPage = false }: GlobalErrorPro
|
||||
description={t(descriptionKey)}
|
||||
actions={(
|
||||
<>
|
||||
<Link to={localizedPath("/")} variant="solid" color="neutral" highContrast size={2}>
|
||||
<ButtonLink to={localizedPath("/")} variant="solid" color="neutral" highContrast size={2}>
|
||||
{t("errors.actions.backToCompliancePortal")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
{onRetry && (
|
||||
<Button variant="soft" color="neutral" size={2} onClick={onRetry}>
|
||||
{t("errors.actions.tryAgain")}
|
||||
|
||||
@@ -23,7 +23,7 @@ import type { PreloadedQuery } from "react-relay";
|
||||
import { graphql, usePreloadedQuery } from "react-relay";
|
||||
|
||||
import { ComplianceFrameworksSection } from "#/components/ComplianceFrameworks/ComplianceFrameworksSection";
|
||||
import { CompliancePortalContactInfo } from "#/components/Hero/CompliancePortalContactInfo";
|
||||
import { CompliancePortalHeroMeta } from "#/components/Hero/CompliancePortalHeroMeta";
|
||||
import { Hero } from "#/components/Hero/Hero";
|
||||
import { RecentUpdatesSection } from "#/components/RecentUpdates/RecentUpdatesSection";
|
||||
import { SecurityCommitmentsSection } from "#/components/SecurityCommitments/SecurityCommitmentsSection";
|
||||
@@ -35,7 +35,7 @@ export const homePageQuery = graphql`
|
||||
query HomePageQuery @throwOnFieldError {
|
||||
currentCompliancePortal @required(action: THROW) {
|
||||
entityName
|
||||
...CompliancePortalContactInfo_compliancePortal
|
||||
...CompliancePortalHeroMeta_compliancePortal
|
||||
...ComplianceFrameworksSection_compliancePortal
|
||||
...SecurityCommitmentsSection_compliancePortal
|
||||
...TrustedBySection_compliancePortal
|
||||
@@ -60,7 +60,7 @@ export function HomePage({ queryRef }: HomePageProps) {
|
||||
title={t("home.heroTitle", { name: entityName })}
|
||||
description={t("home.heroDescription")}
|
||||
>
|
||||
<CompliancePortalContactInfo compliancePortalKey={currentCompliancePortal} />
|
||||
<CompliancePortalHeroMeta compliancePortalKey={currentCompliancePortal} />
|
||||
</Hero>
|
||||
<div className="flex w-full flex-col items-center px-8 max-md:px-4">
|
||||
<div className="flex w-full max-w-5xl flex-col">
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Heading } from "@probo/ui/src/v2/typography/Heading";
|
||||
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -41,9 +41,9 @@ export default function NotFoundPage() {
|
||||
<Text size={2} color="neutral">
|
||||
{t("notFound.description")}
|
||||
</Text>
|
||||
<Link to={localizedPath("/")} variant="soft" color="neutral" highContrast size={2}>
|
||||
<ButtonLink to={localizedPath("/")} variant="soft" color="neutral" highContrast size={2}>
|
||||
{t("notFound.backHome")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
</div>
|
||||
</HeaderBand>
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
import { ArrowRightIcon, ClockIcon, LockSimpleIcon, SpinnerGapIcon } from "@phosphor-icons/react";
|
||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface DocumentAccessActionProps {
|
||||
@@ -100,7 +100,7 @@ export function DocumentAccessAction({
|
||||
|
||||
if (isAuthorized) {
|
||||
return (
|
||||
<Link
|
||||
<ButtonLink
|
||||
to={viewHref}
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
@@ -108,7 +108,7 @@ export function DocumentAccessAction({
|
||||
iconStart={<ArrowRightIcon />}
|
||||
>
|
||||
{t("actions.view")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
import { CaretLeftIcon, SpinnerGapIcon } from "@phosphor-icons/react";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Heading } from "@probo/ui/src/v2/typography/Heading";
|
||||
import { useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -98,9 +98,9 @@ export function DocumentViewer({ title, dataUri = null, downloadName = title, lo
|
||||
<div className={slots.root()}>
|
||||
<HeaderBand flushBottomSpace={!isLocked}>
|
||||
<div className={slots.header()}>
|
||||
<Link to={localizedPath("/documents")} variant="ghost" color="neutral" size={1} iconStart={<CaretLeftIcon />} className={slots.back()}>
|
||||
<ButtonLink to={localizedPath("/documents")} variant="ghost" color="neutral" size={1} iconStart={<CaretLeftIcon />} className={slots.back()}>
|
||||
{t("viewer.back")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
<Heading level={1} size={7} weight="medium" highContrast className="truncate">
|
||||
{title}
|
||||
</Heading>
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
MagnifyingGlassPlusIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { Button } from "@probo/ui/src/v2/Button/Button";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Callout } from "@probo/ui/src/v2/Callout/Callout";
|
||||
import { IconButton } from "@probo/ui/src/v2/IconButton/IconButton";
|
||||
import { Separator } from "@probo/ui/src/v2/Separator/Separator";
|
||||
@@ -236,7 +236,7 @@ export function NDAPage({ queryRef }: NDAPageProps) {
|
||||
<div className={slots.root()}>
|
||||
<HeaderBand flushBottomSpace>
|
||||
<div className={slots.header()}>
|
||||
<Link
|
||||
<ButtonLink
|
||||
to={localizedPath("/documents")}
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
@@ -245,7 +245,7 @@ export function NDAPage({ queryRef }: NDAPageProps) {
|
||||
className={slots.back()}
|
||||
>
|
||||
{t("back")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
<div className={slots.text()}>
|
||||
<Heading level={1} size={7} weight="medium" highContrast>
|
||||
{t("title")}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
import { CaretLeftIcon, NewspaperIcon } from "@phosphor-icons/react";
|
||||
import { Link } from "@probo/ui/src/v2/Button/Link";
|
||||
import { ButtonLink } from "@probo/ui/src/v2/Button/ButtonLink";
|
||||
import { Heading } from "@probo/ui/src/v2/typography/Heading";
|
||||
import { Text } from "@probo/ui/src/v2/typography/Text";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -68,9 +68,9 @@ export function UpdateDetailPage({ queryRef }: UpdateDetailPageProps) {
|
||||
<>
|
||||
<HeaderBand>
|
||||
<div className={toolbar()}>
|
||||
<Link to={localizedPath("/updates")} variant="soft" color="neutral" highContrast iconStart={<CaretLeftIcon />}>
|
||||
<ButtonLink to={localizedPath("/updates")} variant="soft" color="neutral" highContrast iconStart={<CaretLeftIcon />}>
|
||||
{t("backToUpdates")}
|
||||
</Link>
|
||||
</ButtonLink>
|
||||
<UpdatesSubscribeButton />
|
||||
</div>
|
||||
</HeaderBand>
|
||||
|
||||
Reference in New Issue
Block a user