Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions apps/web/src/components/BingLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Microsoft Bing "Fluent" mark used as the visual label for outbound links to
* Bing search. Brand teal-to-blue gradients (IDs namespaced to avoid clashing
* with other inlined SVGs); sized via `className`.
*/
export default function BingLogo({ className }: { className?: string }) {
return (
<svg
focusable="false"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 678 1024"
fill="none"
aria-label="Bing"
className={className}
>
<title>Bing</title>
<path
fill="url(#bing-a)"
d="M0 778.3c14.6 123.8 223.8 143 236.8 79.9-.3-.4-.5-678.1-.5-678.1-3.6-46-26.2-72-61.6-96.5-33-22.7-74.4-50.4-96.9-66.4C14.2-28 .1 31.4 0 33.2c0 0 .3 746.4 0 745.1z"
/>
<path
fill="url(#bing-b)"
d="M236.8 832.8c-96.2 72.5-217 42.7-234.4-44-.8-4.2-2.4-10.4-2.4-10.4s.9 8.5 2 16.6c1.2 8.5 3.7 20.8 6.3 31.3 30 117.8 132.1 186 230.4 196.6C373.3 1034.8 497.4 931 599 855.8c6.3-6.2 15.4-16.2 18.1-20.1 66.2-95-13.6-197-72.5-193a59154 59154 0 0 0-307.7 190.1Z"
/>
<path
fill="url(#bing-c)"
fillRule="evenodd"
clipRule="evenodd"
d="M312.8 381c7.4 47 34.6 108.7 59.6 172.6 20.2 41.3 62 53.4 103 65.5 42.4 12.6 65.6 21 85.6 30.9 138.5 68.7 38.5 207.7 59.6 181.4 89-110.7 79.7-325.4-90-418.1-57.6-28.7-115.4-66.6-156.5-83.6-41-17-68.7 4.3-61.3 51.3z"
/>
<defs>
<radialGradient
id="bing-c"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(-347 -399.3 287.3 -249.8 655 722)"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#00CACC" />
<stop offset="1" stopColor="#048FCE" />
</radialGradient>
<radialGradient
id="bing-b"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(526 -225.4 375.6 876.6 88.8 915.1)"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#00BBEC" />
<stop offset="1" stopColor="#2756A9" />
</radialGradient>
<linearGradient
id="bing-a"
x1="118.4"
x2="118.4"
y1="0"
y2="884.4"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#00BBEC" />
<stop offset="1" stopColor="#2756A9" />
</linearGradient>
</defs>
</svg>
);
}
108 changes: 108 additions & 0 deletions apps/web/src/components/DuckDuckGoLogo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* DuckDuckGo "Dax" mascot badge used as the visual label for outbound links to
* DuckDuckGo search. Full brand colour (orange disc, white duck, green bow tie);
* clip/gradient IDs namespaced to avoid clashing with other inlined SVGs. Sized
* via `className`.
*/
export default function DuckDuckGoLogo({ className }: { className?: string }) {
return (
<svg
focusable="false"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
aria-label="DuckDuckGo"
className={className}
>
<title>DuckDuckGo</title>
<g transform="matrix(.266667 0 0 .266667 -17.954934 -5.057333)">
<defs>
<clipPath id="ddg-clip">
<path d="M178.684 78.824c0 28.316-23.035 51.354-51.354 51.354-28.313 0-51.348-23.04-51.348-51.354s23.036-51.35 51.348-51.35c28.318 0 51.354 23.036 51.354 51.35z" />
</clipPath>
<linearGradient
id="ddg-eyebrow-l"
gradientUnits="userSpaceOnUse"
x1="105.318"
y1="60.979"
x2="113.887"
y2="60.979"
>
<stop offset=".006" stopColor="#6176b9" />
<stop offset=".691" stopColor="#394a9f" />
</linearGradient>
<linearGradient
id="ddg-eyebrow-r"
gradientUnits="userSpaceOnUse"
x1="132.273"
y1="58.371"
x2="140.078"
y2="58.371"
>
<stop offset=".006" stopColor="#6176b9" />
<stop offset=".691" stopColor="#394a9f" />
</linearGradient>
</defs>
<circle cx="127.332" cy="78.966" r="51.15" fill="#de5833" />
<g clipPath="url(#ddg-clip)">
<path
d="M148.293 155.158c-1.8-8.285-12.262-27.04-16.23-34.97s-7.938-19.1-6.13-26.322c.328-1.312-3.436-11.308-2.354-12.015 8.416-5.5 10.632.6 14.002-1.862 1.734-1.273 4.1 1.047 4.7-1.06 2.158-7.567-3.006-20.76-8.77-26.526-1.885-1.88-4.77-3.06-8.03-3.687-1.254-1.713-3.275-3.36-6.138-4.88-3.188-1.697-10.12-3.938-13.717-4.535-2.492-.4-3.055.287-4.12.46.992.088 5.7 2.414 6.615 2.55-.916.62-3.607-.028-5.324.742-.865.392-1.512 1.877-1.506 2.58 4.9-.496 12.574-.016 17.1 2-3.602.4-9.08.867-11.436 2.105-6.848 3.608-9.873 12.035-8.07 22.133 1.804 10.075 9.738 46.85 12.262 59.13 2.525 12.264-5.408 20.2-10.455 22.354l5.408.363-1.8 3.967c6.484.72 13.695-1.44 13.695-1.44-1.438 3.965-11.176 5.412-11.176 5.412s4.7 1.438 12.258-1.447l12.263-4.688 3.604 9.373 6.854-6.847 2.885 7.2c.014-.001 5.424-1.808 3.62-10.103z"
fill="#d5d7d8"
/>
<path
d="M150.47 153.477c-1.795-8.3-12.256-27.043-16.228-34.98s-7.935-19.112-6.13-26.32c.335-1.3.34-6.668 1.43-7.38 8.4-5.494 7.812-.184 11.187-2.645 1.74-1.27 3.133-2.806 3.738-4.912 2.164-7.572-3.006-20.76-8.773-26.53-1.88-1.88-4.768-3.062-8.023-3.686-1.252-1.718-3.27-3.36-6.13-4.882-5.4-2.862-12.074-4.006-18.266-2.883 1 .1 3.256 2.138 4.168 2.273-1.38.936-5.053.815-5.03 2.896 4.916-.492 10.303.285 14.834 2.297-3.602.4-6.955 1.3-9.3 2.543-6.854 3.603-8.656 10.812-6.854 20.914 1.807 10.097 9.742 46.873 12.256 59.126 2.527 12.26-5.402 20.188-10.45 22.354l5.408.36-1.8 3.973c6.484.72 13.695-1.44 13.695-1.44-1.438 3.974-11.176 5.406-11.176 5.406s4.686 1.44 12.258-1.445l12.27-4.688 3.604 9.373 6.852-6.85 2.9 7.215c-.016.007 5.388-1.797 3.58-10.088z"
fill="#fff"
/>
<path
d="M109.02 70.69c0-2.093 1.693-3.787 3.79-3.787 2.1 0 3.785 1.694 3.785 3.787s-1.695 3.786-3.785 3.786c-2.096.001-3.79-1.692-3.79-3.786z"
fill="#2d4f8e"
/>
<path
d="M113.507 69.43a.98.98 0 0 1 .98-.983c.543 0 .984.438.984.983s-.44.984-.984.984c-.538.001-.98-.44-.98-.984z"
fill="#fff"
/>
<path
d="M134.867 68.445c0-1.793 1.46-3.25 3.252-3.25 1.8 0 3.256 1.457 3.256 3.25 0 1.8-1.455 3.258-3.256 3.258a3.26 3.26 0 0 1-3.252-3.258z"
fill="#2d4f8e"
/>
<path
d="M138.725 67.363c0-.463.38-.843.838-.843a.84.84 0 0 1 .846.843c0 .47-.367.842-.846.842a.84.84 0 0 1-.838-.842z"
fill="#fff"
/>
<path
d="M113.886 59.718s-2.854-1.3-5.63.453-2.668 3.523-2.668 3.523-1.473-3.283 2.453-4.892 5.844.916 5.844.916z"
fill="url(#ddg-eyebrow-l)"
/>
<path
d="M140.078 59.458s-2.05-1.172-3.643-1.152c-3.27.043-4.162 1.488-4.162 1.488s.55-3.445 4.732-2.754c2.268.377 3.073 2.418 3.073 2.418z"
fill="url(#ddg-eyebrow-r)"
/>
</g>
<path
d="M124.4 85.295c.38-2.3 6.3-6.625 10.5-6.887 4.2-.265 5.5-.205 9-1.043s12.535-3.088 15.033-4.242c2.504-1.156 13.104.572 5.63 4.738-3.232 1.8-11.943 5.13-18.172 6.987-6.22 1.86-10-1.776-12.06 1.28-1.646 2.432-.334 5.762 7.1 6.453 10.037.93 19.66-4.52 20.72-1.625s-8.625 6.508-14.525 6.623c-5.893.1-17.77-3.896-19.555-5.137s-4.165-4.13-3.67-7.148z"
fill="#fdd20a"
/>
<path
d="M128.943 115.592s-14.102-7.52-14.332-4.47c-.238 3.056 0 15.5 1.643 16.45s13.396-6.108 13.396-6.108zm5.403-.474s9.635-7.285 11.754-6.815c2.1.48 2.582 15.5.7 16.23-1.88.7-12.908-3.813-12.908-3.813z"
fill="#65bc46"
/>
<path
d="M125.53 116.4c0 4.932-.7 7.05 1.4 7.52s6.104 0 7.518-.938.232-7.28-.232-8.465c-.477-1.174-8.696-.232-8.696 1.884z"
fill="#43a244"
/>
<path
d="M126.426 115.292c0 4.933-.707 7.05 1.4 7.52 2.106.48 6.104 0 7.52-.938 1.4-.94.23-7.28-.236-8.466-.473-1.173-8.692-.227-8.692 1.885z"
fill="#65bc46"
/>
<circle
cx="127.331"
cy="78.965"
r="57.5"
fill="none"
stroke="#de5833"
strokeWidth="5"
/>
</g>
</svg>
);
}
34 changes: 34 additions & 0 deletions apps/web/src/components/SeeMoreLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ExternalLink } from 'lucide-react';
import type { ReactNode } from 'react';

/**
* Outbound pill link for the "See more on" section: a glass pill with an
* optional brand logo, optional text label, and a trailing external-link icon,
* opening in a new tab. `brand-link` is inert unless the logo carries
* `brand-mark`, so it's safe to share across tinted and brand-coloured logos.
*/
export function SeeMoreLink({
href,
logo,
label,
ariaLabel,
}: {
href: string;
logo?: ReactNode;
label?: string;
ariaLabel?: string;
}) {
return (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
aria-label={ariaLabel}
className="glass brand-link inline-flex w-fit items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium text-black no-underline transition-[box-shadow]! duration-300! dark:text-white"
>
{logo}
{label && <span>{label}</span>}
<ExternalLink size={14} aria-hidden="true" />
</a>
);
}
67 changes: 34 additions & 33 deletions apps/web/src/routes/company.$id.$slug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ import { companyProfileQueryOptions } from '../api/companiesHouse';
import { flagStateQueryOptions } from '../api/flags';
import { getHmrcBySlug, hmrcBySlugIdQueryOptions } from '../api/hmrc';
import { AddressMap } from '../components/AddressMap';
import BingLogo from '../components/BingLogo';
import DuckDuckGoLogo from '../components/DuckDuckGoLogo';
import GoogleLogo from '../components/GoogleLogo';
import GovUkLogo from '../components/GovUkLogo';
import LinkedInLogo from '../components/LinkedInLogo';
import { NameHistory } from '../components/NameHistory';
import { SeeMoreLink } from '../components/SeeMoreLink';
import { StatusBadge } from '../components/StatusBadge';
import {
companySearchName,
Expand Down Expand Up @@ -428,44 +431,42 @@ function CompanyDetail() {
See more on
</h3>
<div className="flex flex-wrap gap-4 sm:gap-x-2">
{/* GOV.UK needs the Companies House record; Google/LinkedIn search by name. */}
{/* GOV.UK needs the Companies House record; the search engines query by name. */}
{profile?.company_number && (
<a
<SeeMoreLink
href={`https://find-and-update.company-information.service.gov.uk/company/${profile.company_number}`}
target="_blank"
rel="noopener noreferrer"
className="glass inline-flex w-fit items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium text-black no-underline transition-[box-shadow]! duration-300! dark:text-white"
>
{flagState.govukBranded ? (
<GovUkLogo className="h-5 w-auto" />
) : (
'GOV.UK'
)}
<ExternalLink size={14} aria-hidden="true" />
</a>
logo={
flagState.govukBranded ? (
<GovUkLogo className="h-5 w-auto" />
) : undefined
}
label={flagState.govukBranded ? undefined : 'GOV.UK'}
/>
Comment on lines +436 to +444

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add ariaLabel for consistency and accessibility.

The GOV.UK link omits the ariaLabel prop while the Google and LinkedIn links below include descriptive aria labels. When flagState.govukBranded is true and only the logo is displayed, the link's accessible name relies entirely on the SVG's internal accessibility attributes.

For consistency and to ensure a clear, descriptive accessible name regardless of the branding flag state, provide an explicit ariaLabel such as "View company details on GOV.UK".

♿ Suggested fix
 <SeeMoreLink
   href={`https://find-and-update.company-information.service.gov.uk/company/${profile.company_number}`}
   logo={
     flagState.govukBranded ? (
       <GovUkLogo className="h-5 w-auto" />
     ) : undefined
   }
   label={flagState.govukBranded ? undefined : 'GOV.UK'}
+  ariaLabel="View company details on GOV.UK"
 />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/routes/company`.$id.$slug.tsx around lines 434 - 442, The GOV.UK
SeeMoreLink is missing an explicit accessible name; update the SeeMoreLink
invocation (the component named SeeMoreLink where flagState.govukBranded and
GovUkLogo are used, referencing profile.company_number) to include an ariaLabel
prop (e.g. "View company details on GOV.UK") so the link has a descriptive
accessible name regardless of flagState.govukBranded or the SVG internals.

)}
<a
<SeeMoreLink
href={`https://www.google.com/search?q=${searchQuery}`}
target="_blank"
rel="noopener noreferrer"
aria-label={`Search Google for ${displayName}`}
className="glass brand-link inline-flex w-fit items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium text-black no-underline transition-[box-shadow]! duration-300! dark:text-white"
>
<GoogleLogo className="brand-mark h-5 w-auto" />
<span>Google</span>
<ExternalLink size={14} aria-hidden="true" />
</a>
<a
logo={<GoogleLogo className="brand-mark h-5 w-auto" />}
label="Google"
ariaLabel={`Search Google for ${displayName}`}
/>
<SeeMoreLink
href={`https://www.bing.com/search?q=${searchQuery}`}
logo={<BingLogo className="brand-mark h-5 w-auto" />}
label="Bing"
ariaLabel={`Search Bing for ${displayName}`}
/>
<SeeMoreLink
href={`https://duckduckgo.com/?q=${searchQuery}`}
logo={<DuckDuckGoLogo className="brand-mark h-5 w-auto" />}
label="DuckDuckGo"
ariaLabel={`Search DuckDuckGo for ${displayName}`}
/>
<SeeMoreLink
href={`https://www.linkedin.com/search/results/companies/?keywords=${searchQuery}`}
target="_blank"
rel="noopener noreferrer"
aria-label={`Search LinkedIn for ${displayName}`}
className="glass brand-link inline-flex w-fit items-center gap-2 rounded-full px-5 py-2.5 text-sm font-medium text-black no-underline transition-[box-shadow]! duration-300! dark:text-white"
>
<LinkedInLogo className="brand-mark h-5 w-auto" />
<span>LinkedIn</span>
<ExternalLink size={14} aria-hidden="true" />
</a>
logo={<LinkedInLogo className="brand-mark h-5 w-auto" />}
label="LinkedIn"
ariaLabel={`Search LinkedIn for ${displayName}`}
/>
</div>
</div>
</section>
Expand Down
Loading