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
54 changes: 32 additions & 22 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import Root from "@routes/root";
import { DeviceWidthProvider } from "@contexts/DeviceWidthContext";
import "./index.css";

// Support
import {
VersionUpdateNotificationProvider
} from "@components/version-language-switcher/VersionUpdateNotificationContext";
import { SiteWideNotificationProvider } from "@contexts/SiteWideNotificationContext";

import HomePage from "@routes/home";

// Design Tokens

import DesignTokensOverviewPage from "@routes/design-tokens/overview/Overview";
import BorderRadiusPage from "@routes/design-tokens/border-radius/BorderRadius";
import BorderWidthPage from "@routes/design-tokens/border-width/BorderWidth";
Expand All @@ -30,7 +32,6 @@ import SpacingPage from "@routes/design-tokens/spacing/Spacing";
import TypographyPage from "@routes/design-tokens/typography/Typography";

// Get Started

import DevelopersOverviewPage from "@routes/get-started/developers/DevelopersOverview";
import DevelopersSetupPage from "@routes/get-started/developers/DevelopersSetup";
import DevelopersTechnologiesPage from "@routes/get-started/developers/DevelopersTechnologies";
Expand All @@ -50,18 +51,17 @@ import UxDesignerPage from "@routes/get-started/designers/UxDesigner";
import { LtsPolicyPage } from "@routes/get-started/LtsPolicyPage.tsx";

// Content Pages

import ContentLayout from "@routes/content/ContentLayout";
import CapitalizationPage from "@routes/content/Capitalization";
import DateFormatPage from "@routes/content/DateFormat";
import ErrorMessagesPage from "@routes/content/ErrorMessages";
import HelperTextPage from "@routes/content/HelperText";
import CapitalizationPage from "@routes/content/Capitalization.tsx";
import DateFormatPage from "@routes/content/DateFormat.tsx";
import ErrorMessagesPage from "@routes/content/ErrorMessages.tsx";
import HelperTextPage from "@routes/content/HelperText.tsx";
import UserExperienceGuidelinesPage from "@routes/get-started/UserExperienceGuidelines";

import { VersionFromUrlProvider } from "@contexts/VersionFromUrlContext.tsx";
import { ComponentsRouter, PatternsRouter } from "./versioned-router";
import ComponentNotFound from "@routes/not-found/NotFound.tsx";
import { LanguageVersionProvider } from "@contexts/LanguageVersionContext.tsx";
import { LanguageVersionContext, LanguageVersionProvider } from "@contexts/LanguageVersionContext.tsx";
import DevelopersUpgradePage from "@routes/get-started/developers/upgrade-guide/DevelopersUpgrade.tsx";

// Foundations Pages
Expand All @@ -80,7 +80,7 @@ const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Root />}>
<Route path="/" element={<HomePage />} />
<Route path="/components/*" element={<ComponentsRouter />}></Route>
<Route path="/components/*" element={<ComponentsRouter />} />
<Route path="design-tokens" element={<DesignTokens />} errorElement={<ComponentNotFound />}>
<Route index element={<DesignTokensOverviewPage />} />
<Route path="border-width" element={<BorderWidthPage />} />
Expand All @@ -95,9 +95,7 @@ const router = createBrowserRouter(

<Route path="get-started" element={<GetStartedLayout />}>
<Route index element={<GetStartedOverviewPage />} />
<Route path="designers">
<Route index element={<UxDesignerPage />} />
</Route>
<Route path="designers" element={<UxDesignerPage />} />
<Route path="developers">
<Route index element={<DevelopersOverviewPage />} />
<Route path="browsers" element={<SupportedBrowsersPage />} />
Expand All @@ -107,6 +105,7 @@ const router = createBrowserRouter(
<Route path="bug" element={<BugVerificationPage />} />
<Route path="update" element={<DevelopersUpgradePage />} />
</Route>

<Route path="qa-testing">
<Route index element={<QATestingOverviewPage />} />
</Route>
Expand All @@ -122,11 +121,12 @@ const router = createBrowserRouter(
<Route path="report-bug" element={<ReportBugPage />} />
<Route path="request-feature" element={<RequestFeaturePage />} />
</Route>

<Route path="roadmap" element={<RoadmapPage />} />
<Route path="user-experience-guidelines" element={<UserExperienceGuidelinesPage />} />
</Route>

<Route path="foundations" element={<FoundationsLayout />}>
<Route path="foundations" element={<FoundationsLayout />}>
<Route index element={<DesignAtGoAPage />} />
<Route path="accessibility" element={<AccessibilityPage />} />
<Route path="brand-guidelines" element={<BrandGuidelinesPage />} />
Expand All @@ -136,17 +136,19 @@ const router = createBrowserRouter(
<Route path="logo" element={<LogoPage />} />
<Route path="typography" element={<FoundationsTypographyPage />} />
<Route path="layout" element={<FoundationsLayoutPage />} />
</Route>

<Route path="content" element={<ContentLayout />}>
<Route path="capitalization">
<Route index element={<CapitalizationPage />} />
</Route>
<Route path="capitalization" element={<CapitalizationPage />} />
<Route path="date-format" element={<DateFormatPage />} />
<Route path="error-messages" element={<ErrorMessagesPage />} />
<Route path="helper-text" element={<HelperTextPage />} />
</Route>

<Route path="content" element={<ContentLayout />}>
<Route path="/content/capitalization" element={<CapitalizationPage />} />
<Route path="/content/date-format" element={<DateFormatPage />} />
<Route path="/content/error-messages" element={<ErrorMessagesPage />} />
<Route path="/content/helper-text" element={<HelperTextPage />} />
</Route>

<Route path="/patterns/*" element={<PatternsRouter />}></Route>
</Route>
)
Expand All @@ -157,9 +159,17 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<LanguageVersionProvider>
<VersionFromUrlProvider>
<DeviceWidthProvider>
<RouterProvider router={router} />
<LanguageVersionContext.Consumer>
{({ version }) => (
<SiteWideNotificationProvider>
<VersionUpdateNotificationProvider version={version}>
<RouterProvider router={router} />
</VersionUpdateNotificationProvider>
</SiteWideNotificationProvider>
)}
</LanguageVersionContext.Consumer>
</DeviceWidthProvider>
</VersionFromUrlProvider>
</LanguageVersionProvider>
</React.StrictMode>
);
);
38 changes: 38 additions & 0 deletions src/components/version-language-switcher/HelpButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useContext } from "react";
import { useLocation } from "react-router-dom";
import { GoabIconButton, GoabTooltip } from "@abgov/react-components";

import { useVersionUpdateNotification } from "@components/version-language-switcher/VersionUpdateNotificationContext";
import { useSiteWideNotification } from "@contexts/SiteWideNotificationContext";
import { LanguageVersionContext } from "@contexts/LanguageVersionContext";

export function HelpButton() {
const { reset: resetVersion } = useVersionUpdateNotification();
const { reset: resetSiteWideNotification } = useSiteWideNotification();
useContext(LanguageVersionContext);
const location = useLocation();

const handleHelpClick = () => {
const isComponentOrExamplePage =
location.pathname.startsWith("/components") || location.pathname.startsWith("/examples");

if (isComponentOrExamplePage) {
resetVersion();
} else {
resetSiteWideNotification();
}
};

return (
<GoabTooltip content="More information">
<GoabIconButton ml={"s"}
mr={"s"}
variant="color"
size="small"
icon="help-circle"
ariaLabel="Help"
onClick={handleHelpClick}
/>
</GoabTooltip>
);
}
23 changes: 23 additions & 0 deletions src/components/version-language-switcher/SiteWideNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { GoabNotification } from "@abgov/react-components";
import { useLocation } from "react-router-dom";
import { useSiteWideNotification } from "@contexts/SiteWideNotificationContext";
import { MAX_CONTENT_WIDTH } from "../../global-constants.ts";

export function SiteWideNotification() {
const { isDismissed, dismiss } = useSiteWideNotification();
const location = useLocation();

const isComponentOrExamplePage =
location.pathname.startsWith("/components") || location.pathname.startsWith("/examples");

if (isComponentOrExamplePage || isDismissed) return null;

return (
<GoabNotification type="information" onDismiss={dismiss} maxContentWidth={MAX_CONTENT_WIDTH}>
Select your development framework to see all code in your development language. Change framework and version at
the top right of the screen.
</GoabNotification>
);
}

export default SiteWideNotification;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
GoabIcon,
GoabPopover,
GoabPopover, GoabTooltip
} from "@abgov/react-components";
import {
ANGULAR_VERSIONS, getVersionedUrlPath, Language, LanguageVersion,
Expand Down Expand Up @@ -103,6 +103,7 @@ export const VersionLanguageSwitcher = () => {

return (
<>
<GoabTooltip content="Framework">
<GoabPopover
target={
<a className="version-language-switcher__heading" href="#" id="language-switcher" onClick={e => openLanguagePopOver(e)}>
Expand All @@ -118,7 +119,9 @@ export const VersionLanguageSwitcher = () => {
}
</>
</GoabPopover>
</GoabTooltip>

<GoabTooltip content="Version">
<GoabPopover target={
<a className="version-language-switcher__heading" href="#"
onClick={e => openVersionPopOver(e)}>
Expand All @@ -133,7 +136,7 @@ export const VersionLanguageSwitcher = () => {
))}
</>
</GoabPopover>

</GoabTooltip>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useEffect } from "react";
import { GoabNotification } from "@abgov/react-components";
import { MAX_CONTENT_WIDTH } from "../../global-constants";
import { useVersionUpdateNotification } from "./VersionUpdateNotificationContext";
import type { LanguageVersion } from "@components/version-language-switcher/version-language-constants";

interface VersionUpdateNotificationProps {
version: LanguageVersion;
}

export function VersionUpdateNotification({ version }: VersionUpdateNotificationProps) {
const { isDismissed, dismiss, oldLinkRef, newLinkRef } = useVersionUpdateNotification();

useEffect(() => {
const el = document.querySelector("goa-notification");
if (!el) return;

const handleDismiss = () => dismiss();
el.addEventListener("_dismiss", handleDismiss as EventListener);

return () => el.removeEventListener("_dismiss", handleDismiss as EventListener);
}, [dismiss]);

if (isDismissed) return null;

return (
<GoabNotification type={version === "old" ? "important" : "information"} maxContentWidth={MAX_CONTENT_WIDTH}>
{version === "old" ? (
<>
Support for the Long Term Support (LTS) version of the Design system will be available until September
2025.{" "}
<a ref={oldLinkRef} href="/get-started/developers/update">
<span style={{ whiteSpace: "nowrap" }}>View the upgrade guide</span>
</a>
</>
) : (
<>
Upgrading to the latest version of the design system?{" "}
<a ref={newLinkRef} href="/get-started/developers/update">
<span style={{ whiteSpace: "nowrap" }}>View the upgrade guide</span>
</a>
</>
)}
</GoabNotification>
);
}

export default VersionUpdateNotification;
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { createContext, useContext, useEffect, useRef, useState } from "react";
import type { LanguageVersion } from "@components/version-language-switcher/version-language-constants";

interface VersionUpdateNotificationContextType {
isDismissed: boolean;
dismiss: () => void;
reset: () => void;
oldLinkRef: React.RefObject<HTMLAnchorElement>;
newLinkRef: React.RefObject<HTMLAnchorElement>;
}

const VersionUpdateNotificationContext = createContext<VersionUpdateNotificationContextType | undefined>(undefined);

export const VersionUpdateNotificationProvider = ({
version,
children
}: {
version: LanguageVersion;
children: React.ReactNode;
}) => {
const storageKey = `versionUpdateNotificationDismissed-${version}`;
const [isDismissed, setIsDismissed] = useState(false);

const oldLinkRef = useRef<HTMLAnchorElement>(null);
const newLinkRef = useRef<HTMLAnchorElement>(null);

useEffect(() => {
const storedValue = localStorage.getItem(storageKey);
setIsDismissed(storedValue === "true");
}, [version]);

const dismiss = () => {
localStorage.setItem(storageKey, "true");
setIsDismissed(true);
};

const reset = () => {
localStorage.removeItem(storageKey);
setIsDismissed(false);
};

return (
<VersionUpdateNotificationContext.Provider value={{ isDismissed, dismiss, reset, oldLinkRef, newLinkRef }}>
{children}
</VersionUpdateNotificationContext.Provider>
);
};

export const useVersionUpdateNotification = () => {
const context = useContext(VersionUpdateNotificationContext);
if (!context) {
throw new Error("useVersionUpdateNotification must be used within VersionUpdateNotificationProvider");
}
return context;
};
2 changes: 1 addition & 1 deletion src/contexts/LanguageVersionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@components/version-language-switcher/version-language-constants.ts";
import { DEFAULT_LANGUAGE, DEFAULT_VERSION } from "../global-constants";

interface LanguageVersionContextProps {
export interface LanguageVersionContextProps {
language: Language;
version: LanguageVersion;
setLanguage: (lang: Language) => void;
Expand Down
39 changes: 39 additions & 0 deletions src/contexts/SiteWideNotificationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createContext, useContext, useState } from "react";

interface SiteWideNotificationContextType {
isDismissed: boolean;
dismiss: () => void;
reset: () => void;
}

const SiteWideNotificationContext = createContext<SiteWideNotificationContextType | undefined>(undefined);

export const SiteWideNotificationProvider = ({ children }: { children: React.ReactNode }) => {
const [isDismissed, setIsDismissed] = useState(() => {
const stored = localStorage.getItem("siteWideDismissed");
return stored === "true";
});
const dismiss = () => {
localStorage.setItem("siteWideDismissed", "true");
setIsDismissed(true);
};

const reset = () => {
localStorage.removeItem("siteWideDismissed");
setIsDismissed(false);
};

return (
<SiteWideNotificationContext.Provider value={{ isDismissed, dismiss, reset }}>
{children}
</SiteWideNotificationContext.Provider>
);
};

export const useSiteWideNotification = () => {
const context = useContext(SiteWideNotificationContext);
if (!context) {
throw new Error("useSiteWideNotification must be used within SiteWideNotificationProvider");
}
return context;
};
Loading