diff --git a/pwa/package-lock.json b/pwa/package-lock.json index 5b5af1b17..37194d3ed 100644 --- a/pwa/package-lock.json +++ b/pwa/package-lock.json @@ -8,8 +8,8 @@ "name": "skeleton-pip", "version": "1.0.0", "dependencies": { - "@conduction/components": "2.2.20", - "@conduction/theme": "1.0.50", + "@conduction/components": "2.2.24", + "@conduction/theme": "1.0.52", "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/free-brands-svg-icons": "6.4.2", "@fortawesome/free-regular-svg-icons": "6.4.2", @@ -1897,9 +1897,9 @@ } }, "node_modules/@conduction/components": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/@conduction/components/-/components-2.2.20.tgz", - "integrity": "sha512-FsvkfRebglGNmx3bQE+U+02K85Q6GDs2hm8tMwb5N+lWfQemZ2iqf45J/io7mrQS0d3ctkqMwVBjTpWSJEJ4WQ==", + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/@conduction/components/-/components-2.2.24.tgz", + "integrity": "sha512-hGKHdGf+8FBVX2WwQS1DkwbJq/9UW1B3pi6y91aWW3v1T0l4Fh15c1JogqClhHlosb5KQHvwnGThu1bKpxzTlg==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.2.0", @@ -1918,7 +1918,8 @@ }, "node_modules/@conduction/components/node_modules/@fortawesome/react-fontawesome": { "version": "0.2.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "dependencies": { "prop-types": "^15.8.1" }, @@ -1929,11 +1930,13 @@ }, "node_modules/@conduction/components/node_modules/memoize-one": { "version": "5.2.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, "node_modules/@conduction/components/node_modules/react-select": { "version": "5.3.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.3.2.tgz", + "integrity": "sha512-W6Irh7U6Ha7p5uQQ2ZnemoCQ8mcfgOtHfw3wuMzG6FAu0P+CYicgofSLOq97BhjMx8jS+h+wwWdCBeVVZ9VqlQ==", "dependencies": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", @@ -1949,9 +1952,9 @@ } }, "node_modules/@conduction/theme": { - "version": "1.0.50", - "resolved": "https://registry.npmjs.org/@conduction/theme/-/theme-1.0.50.tgz", - "integrity": "sha512-VdkN12+r12WORjVtl2W1kSLMaeZLtqRdrwtHJKuuUFGZmUnqDoxrdjPnX9c5in+MROLgIbBN1Xp/8/Ucy/Y6Lg==", + "version": "1.0.52", + "resolved": "https://registry.npmjs.org/@conduction/theme/-/theme-1.0.52.tgz", + "integrity": "sha512-TEp3B60/yjgJ0i1vn5HwTltCKONMOHvzmZU3sFDF0gJ9Ov7d7sXh9fd2cLQ3mZfMJB3CYDoRyS1Wxnt6GYh5IQ==", "dependencies": { "@nl-design-system-unstable/rotterdam-design-tokens": "^1.0.0-alpha.100" } @@ -2127,18 +2130,16 @@ }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", - "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", "hasInstallScript": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", - "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@fortawesome/fontawesome-common-types": "6.4.2" }, @@ -2148,9 +2149,8 @@ }, "node_modules/@fortawesome/free-brands-svg-icons": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz", - "integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==", "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", "dependencies": { "@fortawesome/fontawesome-common-types": "6.4.2" }, @@ -2160,9 +2160,8 @@ }, "node_modules/@fortawesome/free-regular-svg-icons": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.2.tgz", - "integrity": "sha512-0+sIUWnkgTVVXVAPQmW4vxb9ZTHv0WstOa3rBx9iPxrrrDH6bNLsDYuwXF9b6fGm+iR7DKQvQshUH/FJm3ed9Q==", "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", "dependencies": { "@fortawesome/fontawesome-common-types": "6.4.2" }, @@ -2172,9 +2171,8 @@ }, "node_modules/@fortawesome/free-solid-svg-icons": { "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz", - "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==", "hasInstallScript": true, + "license": "(CC-BY-4.0 AND MIT)", "dependencies": { "@fortawesome/fontawesome-common-types": "6.4.2" }, @@ -2184,8 +2182,7 @@ }, "node_modules/@fortawesome/react-fontawesome": { "version": "0.1.19", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", - "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "license": "MIT", "dependencies": { "prop-types": "^15.8.1" }, @@ -3993,8 +3990,7 @@ }, "node_modules/@types/qs": { "version": "6.9.9", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", - "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==" + "license": "MIT" }, "node_modules/@types/reach__router": { "version": "1.3.11", @@ -4067,8 +4063,7 @@ }, "node_modules/@types/showdown": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.3.tgz", - "integrity": "sha512-cFuAcA3p2YPq8HR8KxvDXnOdccOZ74ypANB3kb3AL5Srji0QnteVw6vf4o7GJ8hMyz+uZ+nSQHVgXSgjYD1a5g==" + "license": "MIT" }, "node_modules/@types/svg-path-parser": { "version": "1.1.3", @@ -5347,8 +5342,7 @@ }, "node_modules/body-parser/node_modules/qs": { "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -7883,8 +7877,7 @@ }, "node_modules/express/node_modules/qs": { "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -13673,8 +13666,7 @@ }, "node_modules/qs": { "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -13820,7 +13812,7 @@ } }, "node_modules/react-datepicker": { - "version": "4.20.0", + "version": "4.21.0", "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.8", @@ -14136,7 +14128,7 @@ } }, "node_modules/react-tooltip": { - "version": "5.21.5", + "version": "5.22.0", "license": "MIT", "dependencies": { "@floating-ui/dom": "^1.0.0", @@ -14831,8 +14823,7 @@ }, "node_modules/showdown": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", - "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "license": "MIT", "dependencies": { "commander": "^9.0.0" }, @@ -14846,8 +14837,7 @@ }, "node_modules/showdown/node_modules/commander": { "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "license": "MIT", "engines": { "node": "^12.20.0 || >=14" } diff --git a/pwa/package.json b/pwa/package.json index bef6523b2..33823b4fd 100644 --- a/pwa/package.json +++ b/pwa/package.json @@ -25,8 +25,8 @@ "prepare": "cd .. && husky install" }, "dependencies": { - "@conduction/components": "2.2.20", - "@conduction/theme": "1.0.50", + "@conduction/components": "2.2.24", + "@conduction/theme": "1.0.52", "@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/free-brands-svg-icons": "6.4.2", "@fortawesome/free-regular-svg-icons": "6.4.2", diff --git a/pwa/src/apiService/resources/components.ts b/pwa/src/apiService/resources/components.ts index eb93021ce..0679a44fb 100644 --- a/pwa/src/apiService/resources/components.ts +++ b/pwa/src/apiService/resources/components.ts @@ -11,7 +11,7 @@ export default class Component { } public getOne = async (id: string): Promise => { - const { data } = await Send(this._instance, "GET", `/components/${id}`); + const { data } = await Send(this._instance, "GET", `/components/${id}?extend[]=all`); return data; }; diff --git a/pwa/src/apiService/resources/organization.ts b/pwa/src/apiService/resources/organization.ts index c39a8c3e0..b43b38d28 100644 --- a/pwa/src/apiService/resources/organization.ts +++ b/pwa/src/apiService/resources/organization.ts @@ -1,7 +1,6 @@ import { Send } from "../apiService"; import { AxiosInstance } from "axios"; import { IFiltersContext } from "../../context/filters"; -import { filtersToQueryParams } from "../../services/filtersToQueryParams"; export default class Organization { private _instance: AxiosInstance; @@ -34,8 +33,8 @@ export default class Organization { return data; }; - public getCount = async (filters: IFiltersContext): Promise => { - const { data } = await Send(this._instance, "GET", `/organizations?limit=1${filtersToQueryParams(filters)}`); + public getCount = async (): Promise => { + const { data } = await Send(this._instance, "GET", `/organizations?limit=1`); return data.total; }; diff --git a/pwa/src/components/buttonLink/ButtonLink.tsx b/pwa/src/components/buttonLink/ButtonLink.tsx deleted file mode 100644 index 7cefb2ea6..000000000 --- a/pwa/src/components/buttonLink/ButtonLink.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import clsx from "clsx"; -import type { GatsbyLinkProps } from "gatsby"; -import { Link as GatsbyLink } from "gatsby"; -import React from "react"; -import type { ButtonLinkProps as DesignSystemButtonLinkProps } from "@utrecht/component-library-react/dist/ButtonLink"; -import { ButtonLink as DesignSystemButtonLink } from "@utrecht/component-library-react/dist/css-module"; - -type GatsbyLinkSubset = Pick, "onClick" | "state" | "to">; - -export interface ButtonLinkProps extends Partial>, DesignSystemButtonLinkProps { - href?: string; -} - -export const ButtonLink = ({ - className, - external, - href, - onClick, - placeholder, - state, - to, - ...restProps -}: ButtonLinkProps): JSX.Element => { - // TODO: `placeholder` is not supported for `GatsbyLink`. - return typeof to === "string" ? ( - - ) : ( - - ); -}; diff --git a/pwa/src/components/categoryCard/CategoryCard.tsx b/pwa/src/components/categoryCard/CategoryCard.tsx index 718ad1512..1befa9389 100644 --- a/pwa/src/components/categoryCard/CategoryCard.tsx +++ b/pwa/src/components/categoryCard/CategoryCard.tsx @@ -12,11 +12,12 @@ export interface CategoryCardProps { description: string | JSX.Element; icon: JSX.Element; domain?: boolean; + titleHrefOnly?: boolean; } -export const CategoryCard: React.FC = ({ title, description, icon, domain }) => { +export const CategoryCard: React.FC = ({ title, description, icon, domain, titleHrefOnly }) => { return ( - navigate(title.href)}> + !titleHrefOnly && navigate(title.href)}> navigate(title.href)}> diff --git a/pwa/src/components/index.ts b/pwa/src/components/index.ts index 2e6fd4b2b..24bc741ee 100644 --- a/pwa/src/components/index.ts +++ b/pwa/src/components/index.ts @@ -1,6 +1,4 @@ export * from "./applicationCard/ApplicationCard"; -export * from "./buttonLink/ButtonLink"; export * from "./categoryCard/CategoryCard"; export * from "./componentCard/ComponentCard"; export * from "./organizationCard/OrganizationCard"; -export * from "./resultsDisplaySwitch/ResultsDisplaySwitch"; diff --git a/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.module.css b/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.module.css deleted file mode 100644 index 6d26e46d6..000000000 --- a/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.resultsDisplaySwitchButtons { - align-items: center; -} diff --git a/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.tsx b/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.tsx deleted file mode 100644 index 5c940b4d3..000000000 --- a/pwa/src/components/resultsDisplaySwitch/ResultsDisplaySwitch.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as React from "react"; -import * as styles from "./ResultsDisplaySwitch.module.css"; -import { Button, ButtonGroup } from "@utrecht/component-library-react/dist/css-module"; -import { useTranslation } from "react-i18next"; -import { useFiltersContext } from "../../context/filters"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faCircleNodes, faGripVertical, faLayerGroup, faTable } from "@fortawesome/free-solid-svg-icons"; -import clsx from "clsx"; -import _ from "lodash"; - -interface AcceptedFilters { - resultDisplayLayout: ["table", "cards", "layer"]; - dependenciesDisplayLayout: ["layer", "relations"]; - landingDisplayLayout: ["layer", "cards"]; - organizationsResultDisplayLayout: ["table", "cards"]; -} - -interface ResultsDisplaySwitchProps { - layoutClassName?: string; - resultsDisplayType: - | "resultDisplayLayout" - | "dependenciesDisplayLayout" - | "landingDisplayLayout" - | "organizationsResultDisplayLayout"; -} - -const ResultsDisplaySwitch: React.FC = ({ layoutClassName, resultsDisplayType }) => { - const { t } = useTranslation(); - const { filters, setFilters } = useFiltersContext(); - - const acceptedFilters: AcceptedFilters = { - resultDisplayLayout: ["table", "cards", "layer"], - dependenciesDisplayLayout: ["layer", "relations"], - landingDisplayLayout: ["layer", "cards"], - organizationsResultDisplayLayout: ["table", "cards"], - }; - - return ( - - {acceptedFilters[resultsDisplayType].map((displayType, idx: number) => { - let icon = faTable; - - if (displayType === "table") icon = faTable; - if (displayType === "cards") icon = faGripVertical; - if (displayType === "layer") icon = faLayerGroup; - if (displayType === "relations") icon = faCircleNodes; - - // TODO: Once the Rotterdam design system supports the "pressed" state, - // remove the `appereance` switch, and use the same appearance for each button. - return ( - - ); - })} - - ); -}; - -export default ResultsDisplaySwitch; diff --git a/pwa/src/context/filters.ts b/pwa/src/context/filters.ts index 9aa111168..b6e9f9959 100644 --- a/pwa/src/context/filters.ts +++ b/pwa/src/context/filters.ts @@ -1,20 +1,8 @@ import * as React from "react"; import { GlobalContext } from "./global"; -export type TComponentResultsLayout = "table" | "cards" | "layer"; -export type TComponentDependenciesLayout = "layer" | "relations"; -export type TLandingDisplayLayout = "layer" | "cards"; -export type TCatagoryDisplayLayout = "table" | "cards" | "layer"; -export type TOrganizationsResultDisplayLayout = "table" | "cards"; - export interface IFiltersContext { - resultDisplayLayout: TComponentResultsLayout; - dependenciesDisplayLayout: TComponentDependenciesLayout; - landingDisplayLayout: TLandingDisplayLayout; - catagoryDisplayLayout: TCatagoryDisplayLayout; isForked: boolean; - - organizationsResultDisplayLayout: TOrganizationsResultDisplayLayout; organizationSearch?: string; _search?: string; @@ -38,11 +26,6 @@ export interface IFiltersContext { } export const defaultFiltersContext: IFiltersContext = { - resultDisplayLayout: "table", - dependenciesDisplayLayout: "layer", - landingDisplayLayout: "cards", - catagoryDisplayLayout: "table", - organizationsResultDisplayLayout: "cards", _search: "", organizationSearch: "", isForked: true, diff --git a/pwa/src/context/global.ts b/pwa/src/context/global.ts index 8fbb20647..eb50edd01 100644 --- a/pwa/src/context/global.ts +++ b/pwa/src/context/global.ts @@ -3,6 +3,7 @@ import { defaultGatsbyContext, IGatsbyContext } from "./gatsby"; import { defaultFiltersContext, IFiltersContext } from "./filters"; import { defaultPaginationContext, IPaginationContext } from "./pagination"; import { defaultQueryLimitContext, IQueryLimitContext } from "./queryLimit"; +import { defaultResultDisplayLayoutContext, IResultDisplayLayoutContext } from "./resultDisplayLayout"; export interface IGlobalContext { initiated: boolean; @@ -10,6 +11,7 @@ export interface IGlobalContext { filters: IFiltersContext; pagination: IPaginationContext; queryLimit: IQueryLimitContext; + resultDisplayLayout: IResultDisplayLayoutContext; } export const defaultGlobalContext: IGlobalContext = { @@ -18,6 +20,7 @@ export const defaultGlobalContext: IGlobalContext = { filters: defaultFiltersContext, pagination: defaultPaginationContext, queryLimit: defaultQueryLimitContext, + resultDisplayLayout: defaultResultDisplayLayoutContext, }; export const GlobalContext = React.createContext< diff --git a/pwa/src/context/resultDisplayLayout.ts b/pwa/src/context/resultDisplayLayout.ts new file mode 100644 index 000000000..2eb185309 --- /dev/null +++ b/pwa/src/context/resultDisplayLayout.ts @@ -0,0 +1,39 @@ +import * as React from "react"; +import { GlobalContext } from "./global"; + +export type TComponentResultsLayout = "table" | "cards" | "layer"; +export type TComponentDependenciesLayout = "layer" | "relations"; +export type TLandingDisplayLayout = "layer" | "cards"; +export type TCatagoryDisplayLayout = "table" | "cards" | "layer"; +export type TOrganizationsResultDisplayLayout = "table" | "cards"; + +export interface IResultDisplayLayoutContext { + componentsDisplayLayout: TComponentResultsLayout; + dependenciesDisplayLayout: TComponentDependenciesLayout; + landingDisplayLayout: TLandingDisplayLayout; + catagoryDisplayLayout: TCatagoryDisplayLayout; + organizationsResultDisplayLayout: TOrganizationsResultDisplayLayout; +} + +export const defaultResultDisplayLayoutContext: IResultDisplayLayoutContext = { + componentsDisplayLayout: "table", + dependenciesDisplayLayout: "layer", + landingDisplayLayout: "cards", + catagoryDisplayLayout: "table", + organizationsResultDisplayLayout: "cards", +}; + +export const useResultDisplayLayoutContext = () => { + const [globalContext, setGlobalContext] = React.useContext(GlobalContext); + + const resultDisplayLayout: IResultDisplayLayoutContext = globalContext.resultDisplayLayout; + + const setResultDisplayLayout = (query: IResultDisplayLayoutContext) => { + setGlobalContext((context) => ({ + ...context, + resultDisplayLayout: { ...globalContext.resultDisplayLayout, ...query }, + })); + }; + + return { setResultDisplayLayout, resultDisplayLayout }; +}; diff --git a/pwa/src/hooks/organization.ts b/pwa/src/hooks/organization.ts index d727568c7..05bfa22a5 100644 --- a/pwa/src/hooks/organization.ts +++ b/pwa/src/hooks/organization.ts @@ -35,8 +35,8 @@ export const useOrganization = (queryClient: QueryClient) => { }, }); - const getCount = (filters: IFiltersContext) => - useQuery(["organizations_count", filters], () => API?.Organization.getCount(filters), { + const getCount = () => + useQuery(["organizations_count"], () => API?.Organization.getCount(), { onError: (error) => { throw new Error(error.message); }, diff --git a/pwa/src/hooks/useHeaderTopNavItems.ts b/pwa/src/hooks/useHeaderTopNavItems.ts new file mode 100644 index 000000000..7ed0ee507 --- /dev/null +++ b/pwa/src/hooks/useHeaderTopNavItems.ts @@ -0,0 +1,129 @@ +import { ITopNavItem } from "@conduction/components/lib/components/topNav/primaryTopNav/PrimaryTopNav"; +import { useGatsbyContext } from "../context/gatsby"; +import { IFiltersContext, defaultFiltersContext, useFiltersContext } from "../context/filters"; +import { navigate } from "gatsby"; +import { useTranslation } from "react-i18next"; + +type THeaderTopNavItem = { + label: string; + type: "markdown" | "internal" | "external"; + current: { + pathname: string; + filterCondition?: { + filterKey: string; + value: string; + }; + }; + handleClick?: { + link: string; + setFilter?: { + filterKey: string; + value: string; + }; + }; +}; + +export const useHeaderTopNavItems = (data: THeaderTopNavItem[]) => { + const { + location: { pathname }, + } = useGatsbyContext(); + const { t } = useTranslation(); + const { filters, setFilters } = useFiltersContext(); + + const headerTopNavItems: ITopNavItem[] = []; + + data?.map((item: any) => { + const isCurrent = (current: any) => { + const prefixedPathname = + process.env.GATSBY_USE_GITHUB_REPOSITORY_NAME_AS_PATH_PREFIX === "true" + ? `/${process.env.GATSBY_GITHUB_REPOSITORY_NAME}${current.pathname}` + : current.pathname; + + const isCurrentRoute = (): boolean => { + if (prefixedPathname === pathname) return true; + + if (current.pathname !== "/") return pathname.includes(current.pathname); + + return false; + }; + + if (!current.filterCondition) { + return isCurrentRoute(); + } + + if (current.filterCondition) { + if (!isCurrentRoute()) return false; + + const currentFilter = filters[current.filterCondition.filterKey as keyof IFiltersContext]; + + if (typeof currentFilter === "object") { + return currentFilter?.toString().includes(current.filterCondition.value); + } + + if (typeof currentFilter === "string") { + return currentFilter === current.filterCondition?.value; + } + } + }; + + const getOnClick = (onClick: any, type: "markdown" | "internal" | "external", label: string) => { + if (!onClick || !type || !label) return; + + if (onClick.link && !onClick.setFilter) { + if (type === "internal") { + navigate(onClick.link); + } + + if (type === "external") { + open(onClick.link); + } + + if (type === "markdown") { + navigate(`/github/${label.replaceAll(" ", "_")}/?link=${onClick.link}`); + } + } + + if (onClick.link && onClick.setFilter && type === "internal") { + const onClickFilter = filters[onClick.setFilter!.filterKey as keyof IFiltersContext]; + + if (typeof onClickFilter === "object") { + setFilters({ ...defaultFiltersContext, [onClick.setFilter!.filterKey]: [onClick.setFilter!.value] }); + } + + if (typeof onClickFilter === "string") { + setFilters({ ...defaultFiltersContext, [onClick.setFilter!.filterKey]: onClick.setFilter!.value }); + } + + navigate(onClick.link); + } + }; + + const setSubItems = (subItems: ITopNavItem[]) => { + if (!subItems) return; + const subItemsArray: ITopNavItem[] = []; + + subItems.map((item: any) => { + subItemsArray.push({ + label: t(item.label), + type: item.type, + current: item.current ? isCurrent(item.current) : false, + handleClick: () => getOnClick(item.handleClick, item.type, item.label), + }); + }); + + const subItemsObject = Object.assign(subItemsArray); + + return subItemsObject; + }; + + headerTopNavItems.push({ + label: t(item.label), + type: item.type, + current: item.current ? isCurrent(item.current) : false, + handleClick: () => getOnClick(item.handleClick, item.type, item.label), + subItems: setSubItems(item.subItems), + }); + }); + + return { headerTopNavItems }; +}; diff --git a/pwa/src/layout/Head.tsx b/pwa/src/layout/Head.tsx index 3292407ea..623479ced 100644 --- a/pwa/src/layout/Head.tsx +++ b/pwa/src/layout/Head.tsx @@ -12,7 +12,11 @@ export const Head: React.FC = () => { class: process.env.GATSBY_NL_DESIGN_THEME_CLASSNAME, }} > - OpenCatalogi + + {process.env.GATSBY_PAGE_TITLE && process.env.GATSBY_PAGE_TITLE !== "" + ? process.env.GATSBY_PAGE_TITLE + : "OpenCatalogi"} + ); }; diff --git a/pwa/src/services/filtersToQueryParams.ts b/pwa/src/services/filtersToQueryParams.ts index c1b84e924..9d7cc80a8 100644 --- a/pwa/src/services/filtersToQueryParams.ts +++ b/pwa/src/services/filtersToQueryParams.ts @@ -57,7 +57,7 @@ export const filtersToUrlQueryParams = (filters: Record, pathname: if (value === null || value === undefined || value === "" || (Array.isArray(value) && _.isEmpty(value))) return null; - if (pathname === "/components" || pathname === "/components/") { + if (pathname === "/components" || pathname === "/components/" || pathname === "/") { if (key === "landingDisplayLayout") return null; if (key === "dependenciesDisplayLayout") return null; if (key === "catagoryDisplayLayout") return null; diff --git a/pwa/src/templates/applicationsDetailTemplate/ApplicationsDetailTemplate.tsx b/pwa/src/templates/applicationsDetailTemplate/ApplicationsDetailTemplate.tsx index cc95a4524..29e70e2f0 100644 --- a/pwa/src/templates/applicationsDetailTemplate/ApplicationsDetailTemplate.tsx +++ b/pwa/src/templates/applicationsDetailTemplate/ApplicationsDetailTemplate.tsx @@ -36,7 +36,13 @@ export const ApplicationsDetailTemplate: React.FC - navigate("/applications")}> + { + e.preventDefault(), navigate("/applications"); + }} + href="/applications" + > diff --git a/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.module.css b/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.module.css index 358867b0e..91997c4f0 100644 --- a/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.module.css +++ b/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.module.css @@ -51,6 +51,10 @@ align-items: baseline !important; } +.loading > span > br { + display: none; +} + /* pagination */ .paginationContainer { diff --git a/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.tsx b/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.tsx index 3898f564b..bb10a1d2f 100644 --- a/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.tsx +++ b/pwa/src/templates/applicationsTemplate/ApplicationsTemplate.tsx @@ -1,5 +1,7 @@ import * as React from "react"; import * as styles from "./ApplicationsTemplate.module.css"; +import clsx from "clsx"; +import Skeleton from "react-loading-skeleton"; import { Heading, Paragraph, Icon, Link } from "@utrecht/component-library-react/dist/css-module"; import { Container, Pagination } from "@conduction/components"; import { useFiltersContext } from "../../context/filters"; @@ -7,7 +9,6 @@ import { useTranslation } from "react-i18next"; import { ApplicationCard } from "../../components/applicationCard/ApplicationCard"; import { QueryClient } from "react-query"; import { useApplications } from "../../hooks/applications"; -import Skeleton from "react-loading-skeleton"; import { usePaginationContext } from "../../context/pagination"; import { PaginationLimitSelectComponent } from "../../components/paginationLimitSelect/PaginationLimitSelect"; import { useQueryLimitContext } from "../../context/queryLimit"; @@ -40,9 +41,17 @@ export const ApplicationsTemplate: React.FC = () => {
- - {t("Applications")} {applicationsCount.data >= 0 && `(${applicationsCount.data})`} + + {t("Applications")}{" "} + {applicationsCount.data >= 0 ? ( + `(${applicationsCount.data})` + ) : ( + <> + () + + )} + Totaal oplossing op basis van een set componenten. Het gaat om werkende software die een oplossing biedt voor een bepaalde{" "} diff --git a/pwa/src/templates/categoriesTemplate/CategoriesTemplate.module.css b/pwa/src/templates/categoriesTemplate/CategoriesTemplate.module.css index 26b16a237..cd319e7da 100644 --- a/pwa/src/templates/categoriesTemplate/CategoriesTemplate.module.css +++ b/pwa/src/templates/categoriesTemplate/CategoriesTemplate.module.css @@ -19,3 +19,8 @@ .description { color: var(--web-app-color-text-grey) !important; } + +.inlineTextLink { + display: inline-flex; + align-items: baseline !important; +} diff --git a/pwa/src/templates/categoriesTemplate/CategoriesTemplate.tsx b/pwa/src/templates/categoriesTemplate/CategoriesTemplate.tsx index d7850f7f7..1965ed4df 100644 --- a/pwa/src/templates/categoriesTemplate/CategoriesTemplate.tsx +++ b/pwa/src/templates/categoriesTemplate/CategoriesTemplate.tsx @@ -5,8 +5,9 @@ import { Container } from "@conduction/components"; import { useTranslation } from "react-i18next"; import { TEMPORARY_PORTFOLIOS } from "../../data/portfolio"; import { CategoriesCardsAccordionTemplate } from "../templateParts/categoriesCardsAccordion/CategoriesCardsAccordionTemplate"; -import { IconExternalLink, IconArrowRight } from "@tabler/icons-react"; import { navigate } from "gatsby-link"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faArrowRight, faExternalLink } from "@fortawesome/free-solid-svg-icons"; export const CategoriesTemplate: React.FC = () => { const { t } = useTranslation(); @@ -24,28 +25,44 @@ export const CategoriesTemplate: React.FC = () => { We verdelen{" "} - navigate("/applications")}> + { + e.preventDefault(), navigate("/applications"); + }} + href="/applications" + > - + - applicaties + {t("Applications").toLowerCase()} {" "} en{" "} - navigate("/components")}> + { + e.preventDefault(), navigate("/components"); + }} + href="/components" + > - + - componenten + {t("Components").toLowerCase()} {" "} in categorieën gebaseerd op de
- + - + Gemma bedrijfsfuncties diff --git a/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.module.css b/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.module.css index d35e52516..781262457 100644 --- a/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.module.css +++ b/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.module.css @@ -39,10 +39,6 @@ color: var(--web-app-color-text-grey) !important; } -.resultsDisplaySwitchButtons { - align-items: center; -} - .results > *:not(:last-child) { margin-block-end: var(--web-app-size-xl); } diff --git a/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.tsx b/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.tsx index 8a3a8ccea..51e7ffe40 100644 --- a/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.tsx +++ b/pwa/src/templates/categoryDetailTemplate/CategoryDetailTemplate.tsx @@ -1,33 +1,26 @@ import * as React from "react"; import * as styles from "./CategoryDetailTemplate.module.css"; -import { - BadgeCounter, - Heading, - Icon, - Button, - ButtonGroup, - DataBadge, - Link, -} from "@utrecht/component-library-react/dist/css-module"; -import { Container } from "@conduction/components"; +import { BadgeCounter, Heading, Icon, DataBadge, Link } from "@utrecht/component-library-react/dist/css-module"; +import { Container, DisplaySwitch } from "@conduction/components"; import { IconArrowLeft } from "@tabler/icons-react"; import { useTranslation } from "react-i18next"; import { TEMPORARY_PORTFOLIOS } from "../../data/portfolio"; import Skeleton from "react-loading-skeleton"; import { TEMPORARY_DOMAINS } from "../../data/domains"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faGripVertical, faLayerGroup, faTable, faTags } from "@fortawesome/free-solid-svg-icons"; -import { useFiltersContext } from "../../context/filters"; +import { faTags } from "@fortawesome/free-solid-svg-icons"; +import { useResultDisplayLayoutContext } from "../../context/resultDisplayLayout"; import { ComponentResultTemplate } from "../templateParts/resultsTemplates/ComponentResultsTemplate"; import { ExpandableLeadParagraph } from "../../components/expandableLeadParagraph/ExpandableLeadParagraph"; import { navigate } from "gatsby-link"; +import { IDisplaySwitchButton } from "@conduction/components/lib/components/displaySwitch/DisplaySwitch"; interface CategoryDetailTemplateProps { categoryId: string; } export const CategoryDetailTemplate: React.FC = ({ categoryId }) => { - const { filters, setFilters } = useFiltersContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const { t } = useTranslation(); const portfolio = TEMPORARY_PORTFOLIOS.find((category) => { @@ -39,14 +32,45 @@ export const CategoryDetailTemplate: React.FC = ({ return domain.title === portfolio.domain; }); - React.useEffect(() => { - setFilters({ ...filters, catagoryDisplayLayout: "table" }); - }, []); + const displaySwitchButtons: IDisplaySwitchButton[] = [ + { + label: t("Table"), + pressed: resultDisplayLayout.catagoryDisplayLayout === "table", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, catagoryDisplayLayout: "table" }), + icon: { + name: "table", + prefix: "fas", + }, + }, + { + label: t("Cards"), + pressed: resultDisplayLayout.catagoryDisplayLayout === "cards", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, catagoryDisplayLayout: "cards" }), + icon: { + name: "grip-vertical", + prefix: "fas", + }, + }, + { + label: t("Layer"), + pressed: resultDisplayLayout.catagoryDisplayLayout === "layer", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, catagoryDisplayLayout: "layer" }), + icon: { + name: "layer-group", + prefix: "fas", + }, + }, + ]; return (
- navigate("/categories")}> + { + e.preventDefault(), navigate("/categories"); + }} + href="/categories" + > @@ -69,7 +93,7 @@ export const CategoryDetailTemplate: React.FC = ({
)} - {filters.catagoryDisplayLayout && ( + {resultDisplayLayout.catagoryDisplayLayout && (
= 100 && styles.maxNumber}> @@ -81,42 +105,11 @@ export const CategoryDetailTemplate: React.FC = ({
- - - - - +
- +
)} diff --git a/pwa/src/templates/componentDetail/ComponentsDetailTemplate.tsx b/pwa/src/templates/componentDetail/ComponentsDetailTemplate.tsx index 354ca8fcd..c5921b1fc 100644 --- a/pwa/src/templates/componentDetail/ComponentsDetailTemplate.tsx +++ b/pwa/src/templates/componentDetail/ComponentsDetailTemplate.tsx @@ -10,6 +10,7 @@ import { Tab, TabPanel, NotificationPopUp as _NotificationPopUp, + DisplaySwitch, } from "@conduction/components"; import { navigate } from "gatsby"; import { IconExternalLink, IconArrowLeft, IconArrowRight, IconPhone } from "@tabler/icons-react"; @@ -37,11 +38,11 @@ import { categories, TCategories } from "../../data/categories"; import { OrganizationCard } from "../../components/organizationCard/OrganizationCard"; import { GitHubLogo } from "../../assets/svgs/GitHub"; import { DependenciesTemplate } from "../templateParts/dependenciesTemplates/ComponentDependenciesTemplate"; -import { useFiltersContext } from "../../context/filters"; +import { useResultDisplayLayoutContext } from "../../context/resultDisplayLayout"; import { ComponentCardsAccordionTemplate } from "../templateParts/componentCardsAccordion/ComponentCardsAccordionTemplate"; import { DownloadTemplate } from "../templateParts/download/DownloadTemplate"; import { RatingOverview } from "../templateParts/ratingOverview/RatingOverview"; -import ResultsDisplaySwitch from "../../components/resultsDisplaySwitch/ResultsDisplaySwitch"; +import { IDisplaySwitchButton } from "@conduction/components/lib/components/displaySwitch/DisplaySwitch"; import { ExpandableLeadParagraph } from "../../components/expandableLeadParagraph/ExpandableLeadParagraph"; import { TOOLTIP_ID } from "../../layout/Layout"; @@ -52,7 +53,7 @@ interface ComponentsDetailTemplateProps { export const ComponentsDetailTemplate: React.FC = ({ componentId, sizeKb }) => { const { t } = useTranslation(); - const { filters } = useFiltersContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const NotificationPopUpController = _NotificationPopUp.controller; const NotificationPopUp = _NotificationPopUp.NotificationPopUp; @@ -72,6 +73,9 @@ export const ComponentsDetailTemplate: React.FC = }); }); + const gemma = _getComponent.data?.embedded?.nl?.embedded?.gemma; + const legal = _getComponent.data?.embedded?.legal; + if (_getComponent.isError) return <>Something went wrong...; const organisation = _getComponent?.data?.embedded?.url?.embedded?.organisation; @@ -85,9 +89,36 @@ export const ComponentsDetailTemplate: React.FC = } }; + const displaySwitchButtons: IDisplaySwitchButton[] = [ + { + label: t("Layer"), + pressed: resultDisplayLayout.dependenciesDisplayLayout === "layer", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, dependenciesDisplayLayout: "layer" }), + icon: { + name: "layer-group", + prefix: "fas", + }, + }, + { + label: t("Relations"), + pressed: resultDisplayLayout.dependenciesDisplayLayout === "relations", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, dependenciesDisplayLayout: "relations" }), + icon: { + name: "circle-nodes", + prefix: "fas", + }, + }, + ]; + return ( - navigate("/components")}> + { + e.preventDefault(), navigate("/components"); + }} + href="/components" + > @@ -328,14 +359,14 @@ export const ComponentsDetailTemplate: React.FC =
{_getComponent.data.embedded?.dependsOn?.embedded.open && ( - )} = {...{ sizeKb }} /> -
-

Meer informatie

- - - - - Gemma - Op dit moment is er geen gemma data beschikbaar. - - - {t("Products")} - - {_getComponent.data.embedded?.nl?.upl && - _getComponent.data.embedded?.nl?.upl.map((product: string, idx: number) => ( - - - - - - {product},{" "} - - - ))} - {(!_getComponent.data.embedded?.nl?.upl || !_getComponent.data.embedded?.nl?.upl.length) && ( - Op dit moment zijn er geen producten beschikbaar. + {gemma?.applicatiefunctie || + gemma?.bedrijfsfuncties || + gemma?.bedrijfsservices || + gemma?.model || + gemma?.referentiecomponenten?.length > 0 || + legal?.license || + (_getComponent.data.embedded?.nl?.upl?.length > 0 && ( +
+

Meer informatie

+ +
+ + {gemma?.applicatiefunctie && ( + + Applicatiefunctie + {gemma.applicatiefunctie} + )} - - - - Standaarden - - Op dit moment zijn er geen standaarden beschikbaar. - - - - Wet en regelgeving - - Op dit moment zijn er geen wetten en regelgevingen beschikbaar. - - - -
-
+ + {gemma?.bedrijfsfuncties && ( + + Bedrijfsfuncties + {gemma.bedrijfsfuncties.join(", ")} + + )} + + {gemma?.bedrijfsservices && ( + + Bedrijfsservices + {gemma.bedrijfsservices.join(", ")} + + )} + + {gemma?.model && ( + + Model + {gemma.model} + + )} + + {gemma?.referentieComponenten?.length > 0 && ( + + Referentie componenten + {gemma.referentieComponenten.join(", ")} + + )} + + {legal?.license && ( + + Licentie + {legal.license} + + )} + + {_getComponent.data.embedded?.nl?.upl?.length > 0 && ( + + {t("Products")} + + {_getComponent.data.embedded?.nl?.upl.map((product: string, idx: number) => ( + + + + + + {product},{" "} + + + ))} + + + )} + + + + ))} )} {_getComponent.isLoading && } diff --git a/pwa/src/templates/components/ComponentsTemplate.module.css b/pwa/src/templates/components/ComponentsTemplate.module.css index d68ece6e5..ccbf92d72 100644 --- a/pwa/src/templates/components/ComponentsTemplate.module.css +++ b/pwa/src/templates/components/ComponentsTemplate.module.css @@ -10,10 +10,6 @@ margin-block-end: var(--web-app-size-lg); } -.resultsDisplaySwitchButtons { - align-items: center; -} - .filtersAndResultsContainer { display: flex; flex-direction: column; @@ -62,6 +58,10 @@ margin-block-start: var(--web-app-size-lg); } +.loading > span > br { + display: none; +} + @media only screen and (min-width: 992px) { .header { display: flex; diff --git a/pwa/src/templates/components/ComponentsTemplate.tsx b/pwa/src/templates/components/ComponentsTemplate.tsx index f1f5aa145..30d0535f1 100644 --- a/pwa/src/templates/components/ComponentsTemplate.tsx +++ b/pwa/src/templates/components/ComponentsTemplate.tsx @@ -1,55 +1,95 @@ import * as React from "react"; import * as styles from "./ComponentsTemplate.module.css"; -import { Container, Pagination } from "@conduction/components"; +import Skeleton from "react-loading-skeleton"; +import clsx from "clsx"; +import { IDisplaySwitchButton } from "@conduction/components/lib/components/displaySwitch/DisplaySwitch"; +import { Container, DisplaySwitch, Pagination } from "@conduction/components"; import { ComponentResultTemplate } from "../templateParts/resultsTemplates/ComponentResultsTemplate"; -import { defaultFiltersContext, useFiltersContext } from "../../context/filters"; +import { useFiltersContext } from "../../context/filters"; import { useTranslation } from "react-i18next"; import { QueryClient } from "react-query"; import { VerticalFiltersTemplate } from "../templateParts/filters/verticalFilters/VerticalFiltersTemplate"; -import Skeleton from "react-loading-skeleton"; import { HorizontalFiltersTemplate } from "../templateParts/filters/horizontalFilters/HorizontalFiltersTemplate"; import { SubmitComponentTemplate } from "../templateParts/submitComponent/SubmitComponentTemplate"; import { useSearch } from "../../hooks/search"; import { ActiveFiltersTemplate } from "../templateParts/filters/activeFilters/ActiveFiltersTemplate"; -import ResultsDisplaySwitch from "../../components/resultsDisplaySwitch/ResultsDisplaySwitch"; import { Alert, Heading, Icon, Paragraph } from "@utrecht/component-library-react/dist/css-module"; import { IconInfoCircle } from "@tabler/icons-react"; import { useComponent } from "../../hooks/components"; import { usePaginationContext } from "../../context/pagination"; import { PaginationLimitSelectComponent } from "../../components/paginationLimitSelect/PaginationLimitSelect"; import { useQueryLimitContext } from "../../context/queryLimit"; +import { useResultDisplayLayoutContext } from "../../context/resultDisplayLayout"; export const ComponentsTemplate: React.FC = () => { const { t } = useTranslation(); const { filters } = useFiltersContext(); const { queryLimit } = useQueryLimitContext(); const { pagination, setPagination } = usePaginationContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const queryClient = new QueryClient(); const _useSearch = useSearch(queryClient); const getComponents = _useSearch.getSearch( - { ...filters, resultDisplayLayout: "table", organizationSearch: "" }, + { ...filters, organizationSearch: "" }, pagination.componentsCurrentPage, queryLimit.componentsSearchQueryLimit, ); // Ensure no refetch on resultDisplayLayout change const _useComponents = useComponent(queryClient); - const componentsCount = _useComponents.getCount(defaultFiltersContext); + const componentsCount = _useComponents.getCount(filters); React.useEffect(() => { setPagination({ ...pagination, componentsCurrentPage: 1 }); }, [queryLimit.componentsSearchQueryLimit]); + const displaySwitchButtons: IDisplaySwitchButton[] = [ + { + label: t("Table"), + pressed: resultDisplayLayout.componentsDisplayLayout === "table", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, componentsDisplayLayout: "table" }), + icon: { + name: "table", + prefix: "fas", + }, + }, + { + label: t("Cards"), + pressed: resultDisplayLayout.componentsDisplayLayout === "cards", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, componentsDisplayLayout: "cards" }), + icon: { + name: "grip-vertical", + prefix: "fas", + }, + }, + { + label: t("Layer"), + pressed: resultDisplayLayout.componentsDisplayLayout === "layer", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, componentsDisplayLayout: "layer" }), + icon: { + name: "layer-group", + prefix: "fas", + }, + }, + ]; + return (
- - {t("Components")} {componentsCount.data >= 0 && `(${componentsCount.data})`} + + {t("Components")}{" "} + {componentsCount.data >= 0 ? ( + `(${componentsCount.data})` + ) : ( + <> + () + + )}
- +
@@ -57,7 +97,7 @@ export const ComponentsTemplate: React.FC = () => {
- {filters.resultDisplayLayout === "table" && ( + {resultDisplayLayout.componentsDisplayLayout === "table" && ( { )} - {filters.resultDisplayLayout === "cards" && ( + {resultDisplayLayout.componentsDisplayLayout === "cards" && ( { Op deze pagina staan alleen applicaties, organisaties en componenten )} - {filters.resultDisplayLayout === "layer" && ( + {resultDisplayLayout.componentsDisplayLayout === "layer" && ( { {getComponents.data?.results && getComponents.data?.results?.length > 0 && ( <> - + {getComponents.data.results.length && ( diff --git a/pwa/src/templates/landing/LandingTemplate.tsx b/pwa/src/templates/landing/LandingTemplate.tsx index 506851915..38e063eb5 100644 --- a/pwa/src/templates/landing/LandingTemplate.tsx +++ b/pwa/src/templates/landing/LandingTemplate.tsx @@ -1,26 +1,49 @@ import * as React from "react"; import * as styles from "./LandingTemplate.module.css"; -import { Container, DetailsCard, ImageAndDetailsCard } from "@conduction/components"; +import { Container, DetailsCard, DisplaySwitch, ImageAndDetailsCard } from "@conduction/components"; import { FeedbackTemplate } from "../templateParts/feedback/FeedbackTemplate"; import overOpenCatalogiImage from "./../../assets/svgs/SpotAPI.svg"; import aanDeSlagMetOpenCatalogiImage from "./../../assets/svgs/SpotForum.svg"; -import { useFiltersContext } from "../../context/filters"; +import { useResultDisplayLayoutContext } from "../../context/resultDisplayLayout"; import { LandingDisplayTemplate } from "../templateParts/landingDisplayTemplates/LandingDisplayTemplate"; import { useGatsbyContext } from "../../context/gatsby"; -import ResultsDisplaySwitch from "../../components/resultsDisplaySwitch/ResultsDisplaySwitch"; +import { IDisplaySwitchButton } from "@conduction/components/lib/components/displaySwitch/DisplaySwitch"; import { Heading, Separator } from "@utrecht/component-library-react/dist/css-module"; import { MarkdownContentTemplate } from "../markdown/MarkdownContentTemplate"; +import { useTranslation } from "react-i18next"; interface LandingTemplateProps { params: any; } export const LandingTemplate: React.FC = ({ params }) => { - const { filters } = useFiltersContext(); + const { t } = useTranslation(); const { screenSize } = useGatsbyContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const detailPageSlug = params.detailPageSlug; const pageSlug = params.pageSlug; + const displaySwitchButtons: IDisplaySwitchButton[] = [ + { + label: t("Layer"), + pressed: resultDisplayLayout.landingDisplayLayout === "layer", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, landingDisplayLayout: "layer" }), + icon: { + name: "layer-group", + prefix: "fas", + }, + }, + { + label: t("Cards"), + pressed: resultDisplayLayout.landingDisplayLayout === "cards", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, landingDisplayLayout: "cards" }), + icon: { + name: "grip-vertical", + prefix: "fas", + }, + }, + ]; + return ( {process.env.GATSBY_OPTIONAL_START_PAGE && @@ -32,12 +55,9 @@ export const LandingTemplate: React.FC = ({ params }) => { {(!process.env.GATSBY_OPTIONAL_START_PAGE || process.env.GATSBY_OPTIONAL_START_PAGE === "false") && ( <>
- + - +
diff --git a/pwa/src/templates/organizationDetail/OrganizationDetailTemplate.tsx b/pwa/src/templates/organizationDetail/OrganizationDetailTemplate.tsx index 4bcf50181..b36d8f6c8 100644 --- a/pwa/src/templates/organizationDetail/OrganizationDetailTemplate.tsx +++ b/pwa/src/templates/organizationDetail/OrganizationDetailTemplate.tsx @@ -36,7 +36,13 @@ export const OrganizationDetailTemplate: React.FC - navigate("/organizations")}> + { + e.preventDefault(), navigate("/organizations"); + }} + href="/organizations" + > diff --git a/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.module.css b/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.module.css index 51bfe4be4..f850c8227 100644 --- a/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.module.css +++ b/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.module.css @@ -32,6 +32,10 @@ margin-block-start: var(--web-app-size-lg); } +.loading > span > br { + display: none; +} + @media only screen and (min-width: 992px) { .header { display: flex; diff --git a/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.tsx b/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.tsx index 057d6a164..0d4c5d61e 100644 --- a/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.tsx +++ b/pwa/src/templates/organizationsTemplate/OrganizationsTemplate.tsx @@ -1,11 +1,12 @@ import * as React from "react"; import * as styles from "./OrganizationsTemplate.module.css"; -import { Container, Pagination } from "@conduction/components"; +import clsx from "clsx"; +import Skeleton from "react-loading-skeleton"; +import { IDisplaySwitchButton } from "@conduction/components/lib/components/displaySwitch/DisplaySwitch"; +import { Container, DisplaySwitch, Pagination } from "@conduction/components"; import { useFiltersContext } from "../../context/filters"; import { useTranslation } from "react-i18next"; import { QueryClient } from "react-query"; -import Skeleton from "react-loading-skeleton"; -import ResultsDisplaySwitch from "../../components/resultsDisplaySwitch/ResultsDisplaySwitch"; import { Heading } from "@utrecht/component-library-react/dist/css-module"; import { useOrganization } from "../../hooks/organization"; import { OrganizationSearchFiltersTemplate } from "../templateParts/filters/organizationSearchFilterTemplate/OrganizationSearchFilterTemplate"; @@ -13,21 +14,46 @@ import { OrganizationDisplayTemplate } from "../templateParts/OrganizationDispla import { usePaginationContext } from "../../context/pagination"; import { PaginationLimitSelectComponent } from "../../components/paginationLimitSelect/PaginationLimitSelect"; import { useQueryLimitContext } from "../../context/queryLimit"; +import { useResultDisplayLayoutContext } from "../../context/resultDisplayLayout"; export const OrganizationsTemplate: React.FC = () => { const { t } = useTranslation(); const { filters } = useFiltersContext(); const { queryLimit } = useQueryLimitContext(); const { pagination, setPagination } = usePaginationContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const queryClient = new QueryClient(); const _useOrganisation = useOrganization(queryClient); const getOrganisations = _useOrganisation.getAll( - { ...filters, organizationsResultDisplayLayout: "cards" }, + { ...filters }, pagination.organizationCurrentPage, queryLimit.organizationsQueryLimit, ); + const organizationCount = _useOrganisation.getCount(); + + const displaySwitchButtons: IDisplaySwitchButton[] = [ + { + label: t("Table"), + pressed: resultDisplayLayout.organizationsResultDisplayLayout === "table", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, organizationsResultDisplayLayout: "table" }), + icon: { + name: "table", + prefix: "fas", + }, + }, + { + label: t("Cards"), + pressed: resultDisplayLayout.organizationsResultDisplayLayout === "cards", + handleClick: () => setResultDisplayLayout({ ...resultDisplayLayout, organizationsResultDisplayLayout: "cards" }), + icon: { + name: "grip-vertical", + prefix: "fas", + }, + }, + ]; + React.useEffect(() => { setPagination({ ...pagination, organizationCurrentPage: 1 }); }, [queryLimit.organizationsQueryLimit]); @@ -36,12 +62,19 @@ export const OrganizationsTemplate: React.FC = () => {
- - {t("Organizations")} + + {t("Organizations")}{" "} + {organizationCount.data >= 0 ? ( + `(${organizationCount.data})` + ) : ( + <> + () + + )}
- +
@@ -56,7 +89,7 @@ export const OrganizationsTemplate: React.FC = () => { <> {getOrganisations.data.results.length && ( diff --git a/pwa/src/templates/templateParts/OrganizationDisplayTemplates/OrganizationDisplayTemplate.tsx b/pwa/src/templates/templateParts/OrganizationDisplayTemplates/OrganizationDisplayTemplate.tsx index a10f3743a..42a304e43 100644 --- a/pwa/src/templates/templateParts/OrganizationDisplayTemplates/OrganizationDisplayTemplate.tsx +++ b/pwa/src/templates/templateParts/OrganizationDisplayTemplates/OrganizationDisplayTemplate.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { TOrganizationsResultDisplayLayout } from "../../../context/filters"; +import { TOrganizationsResultDisplayLayout } from "../../../context/resultDisplayLayout"; import { CardsOrganizationDisplayTemplate } from "./cards/CardsOrganizationDisplayTemplate"; import { TableOrganizationDisplayTemplate } from "./table/TableOrganizationDisplayTemplate"; diff --git a/pwa/src/templates/templateParts/dependenciesTemplates/ComponentDependenciesTemplate.tsx b/pwa/src/templates/templateParts/dependenciesTemplates/ComponentDependenciesTemplate.tsx index b3e4d82b3..bb8bcafd8 100644 --- a/pwa/src/templates/templateParts/dependenciesTemplates/ComponentDependenciesTemplate.tsx +++ b/pwa/src/templates/templateParts/dependenciesTemplates/ComponentDependenciesTemplate.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import * as _ from "lodash"; -import { TComponentDependenciesLayout } from "../../../context/filters"; +import { TComponentDependenciesLayout } from "../../../context/resultDisplayLayout"; import { RelationsDependenciesTemplate } from "./relationsDependenciesTemplate/RelationsDependenciesTemplate"; import { LayerDependenciesTemplate } from "./layerDependenciesTemplate/LayerDependenciesTemplate"; import { LayerAccordionFiltersTemplate } from "../layerAccordion/filters/LayerAccordionFiltersTemplate"; diff --git a/pwa/src/templates/templateParts/feedback/FeedbackTemplate.tsx b/pwa/src/templates/templateParts/feedback/FeedbackTemplate.tsx index 34d63aefe..6a232995c 100644 --- a/pwa/src/templates/templateParts/feedback/FeedbackTemplate.tsx +++ b/pwa/src/templates/templateParts/feedback/FeedbackTemplate.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import * as styles from "./FeedbackTemplate.module.css"; import clsx from "clsx"; -import { ButtonLink } from "../../../components"; +import { ButtonLink } from "@utrecht/component-library-react/dist/css-module"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faExternalLink } from "@fortawesome/free-solid-svg-icons"; @@ -25,6 +25,7 @@ export const FeedbackTemplate: React.FC = ({ layoutClassN Wens of opmerking indienen op GitHub + Roadmap bekijken diff --git a/pwa/src/templates/templateParts/filters/verticalFilters/VerticalFiltersTemplate.tsx b/pwa/src/templates/templateParts/filters/verticalFilters/VerticalFiltersTemplate.tsx index 7b9619b5a..68280fb8d 100644 --- a/pwa/src/templates/templateParts/filters/verticalFilters/VerticalFiltersTemplate.tsx +++ b/pwa/src/templates/templateParts/filters/verticalFilters/VerticalFiltersTemplate.tsx @@ -36,6 +36,7 @@ import { useGatsbyContext } from "../../../../context/gatsby"; import { navigate } from "gatsby"; import { filtersToUrlQueryParams } from "../../../../services/filtersToQueryParams"; import { usePaginationContext } from "../../../../context/pagination"; +import { useResultDisplayLayoutContext } from "../../../../context/resultDisplayLayout"; interface VerticalFiltersTemplateProps { filterSet: any[]; @@ -46,6 +47,7 @@ export const VerticalFiltersTemplate: React.FC = ( const { filters, setFilters } = useFiltersContext(); const { screenSize, location } = useGatsbyContext(); const { pagination, setPagination } = usePaginationContext(); + const { resultDisplayLayout, setResultDisplayLayout } = useResultDisplayLayoutContext(); const [queryParams, setQueryParams] = React.useState(defaultFiltersContext); @@ -100,9 +102,9 @@ export const VerticalFiltersTemplate: React.FC = ( const allFilters = { ...filters, ...pagination }; if (_.isEqual(allFilters, queryParams)) return; - setQueryParams({ ...filters, ...pagination }); - navigate(filtersToUrlQueryParams({ ...filters, ...pagination }, location.pathname)); - }, [filters, pagination]); + setQueryParams({ ...filters, ...pagination, ...resultDisplayLayout }); + navigate(filtersToUrlQueryParams({ ...filters, ...pagination, ...resultDisplayLayout }, location.pathname)); + }, [filters, pagination, resultDisplayLayout]); const handleLayerChange = (layer: any, e: any) => { const currentFilters = filters["embedded.nl.embedded.commonground.layerType"] ?? []; @@ -238,6 +240,10 @@ export const VerticalFiltersTemplate: React.FC = ( ...pagination, componentsCurrentPage: 1, }); + setResultDisplayLayout({ + ...resultDisplayLayout, + componentsDisplayLayout: resultDisplayLayout.componentsDisplayLayout, + }); }, ); @@ -308,7 +314,6 @@ export const VerticalFiltersTemplate: React.FC = ( const handleSetFormValuesFromParams = (params: any): void => { setFilters({ ...filters, - resultDisplayLayout: params.resultDisplayLayout !== undefined ? params.resultDisplayLayout : "table", isForked: params.isForked ? params.isForked : false, softwareType: params.softwareType ? params.softwareType : "", developmentStatus: params.developmentStatus ? params.developmentStatus : "", @@ -337,6 +342,10 @@ export const VerticalFiltersTemplate: React.FC = ( ...pagination, componentsCurrentPage: params.componentsCurrentPage ? _.toNumber(params.componentsCurrentPage) : 1, }); + setResultDisplayLayout({ + ...resultDisplayLayout, + componentsDisplayLayout: params.componentsDisplayLayout !== undefined ? params.componentsDisplayLayout : "table", + }); }; const url = location.search; diff --git a/pwa/src/templates/templateParts/footer/FooterTemplate.module.css b/pwa/src/templates/templateParts/footer/FooterTemplate.module.css index 5eec94a08..36f19875d 100644 --- a/pwa/src/templates/templateParts/footer/FooterTemplate.module.css +++ b/pwa/src/templates/templateParts/footer/FooterTemplate.module.css @@ -33,8 +33,20 @@ cursor: pointer; } +.link { + color: var(--utrecht-page-footer-link-color, inherit) !important; + text-decoration-line: var(--utrecht-page-footer-link-text-decoration, inherit) !important; + text-decoration-color: var(--utrecht-page-footer-link-text-decoration-color, inherit) !important; + text-decoration-thickness: var(--utrecht-page-footer-link-text-decoration-thickness, inherit) !important; + text-underline-offset: var(--utrecht-page-footer-link-text-underline-offset, inherit) !important; + display: inline-flex; +} + .link:hover { cursor: pointer; + color: var(--utrecht-page-footer-link-hover-color, inherit) !important; + text-decoration-line: var(--utrecht-page-footer-link-hover-text-decoration, inherit) !important; + text-decoration-thickness: var(--utrecht-page-footer-link-hover-text-decoration-thickness, inherit) !important; } .withLoveConductionLink { @@ -84,6 +96,11 @@ margin-inline-start: var(--web-app-size-2xs); } +.iconLeft, +.iconRight { + color: var(--utrecht-page-footer-icon-color, inherit); +} + @media only screen and (min-width: 576px) { .contentGrid { grid-template-columns: repeat(2, minmax(0, 1fr)); diff --git a/pwa/src/templates/templateParts/footer/FooterTemplate.tsx b/pwa/src/templates/templateParts/footer/FooterTemplate.tsx index d6b30ced1..e30f6d76b 100644 --- a/pwa/src/templates/templateParts/footer/FooterTemplate.tsx +++ b/pwa/src/templates/templateParts/footer/FooterTemplate.tsx @@ -2,7 +2,16 @@ import * as React from "react"; import * as styles from "./FooterTemplate.module.css"; import clsx from "clsx"; import parse from "html-react-parser"; -import { PageFooter, Link, Heading3, Icon } from "@utrecht/component-library-react/dist/css-module"; +import { + PageFooter, + Link, + Icon, + Heading1, + Heading2, + Heading3, + Heading4, + Heading5, +} from "@utrecht/component-library-react/dist/css-module"; import { navigate } from "gatsby-link"; import { defaultFiltersContext, useFiltersContext } from "../../../context/filters"; import { useTranslation } from "react-i18next"; @@ -83,7 +92,7 @@ const DynamicSection: React.FC<{ content: TDynamicContentItem }> = ({ content }) return (
- {t(content.title)} + {content.items.map((item, idx) => (
@@ -108,6 +117,25 @@ const DynamicSection: React.FC<{ content: TDynamicContentItem }> = ({ content }) ); }; +const DynamicSectionHeading: React.FC<{ content: TDynamicContentItem; heading?: string }> = ({ content, heading }) => { + const { t } = useTranslation(); + + switch (heading) { + case "heading-1": + return {t(content.title)}; + case "heading-2": + return {t(content.title)}; + case "heading-3": + return {t(content.title)}; + case "heading-4": + return {t(content.title)}; + case "heading-5": + return {t(content.title)}; + default: + return {t(content.title)}; + } +}; + const Logo: React.FC = () => { if (process.env.GATSBY_FOOTER_LOGO_URL === "false") return <>; const { t } = useTranslation(); @@ -213,10 +241,13 @@ const InternalLink: React.FC = ({ item }) => { return ( navigate(item.link ?? "")} + onClick={(e: any) => { + e.preventDefault(), navigate(item.link ?? ""); + }} tabIndex={0} aria-label={`${t(item.ariaLabel)}, ${t(item.value)}`} role="button" + href={item.link} > {item.icon && item.icon.placement === "left" && ( @@ -249,10 +280,13 @@ const MarkdownLink: React.FC = ({ item }) => { return ( navigate(`/github/${item.value.replaceAll(" ", "_")}/?link=${item.markdownLink}`)} + onClick={(e: any) => { + e.preventDefault(), navigate(`/github/${item.value.replaceAll(" ", "_")}/?link=${item.markdownLink}`); + }} tabIndex={0} aria-label={`${t(item.ariaLabel)}, ${t(item.markdownLink)}`} role="button" + href={item.markdownLink} > {item.icon && item.icon.placement === "left" && ( diff --git a/pwa/src/templates/templateParts/header/HeaderContent.json b/pwa/src/templates/templateParts/header/HeaderContent.json index 5729de094..02daae25b 100644 --- a/pwa/src/templates/templateParts/header/HeaderContent.json +++ b/pwa/src/templates/templateParts/header/HeaderContent.json @@ -2,10 +2,8 @@ { "label": "Home", "type": "internal", - "current": { - "pathname": "/", - "operator": "equals" + "pathname": "/" }, "handleClick": { "link": "/" @@ -15,8 +13,7 @@ "label": "Categories", "type": "internal", "current": { - "pathname": "/categories", - "operator": "includes" + "pathname": "/categories" }, "handleClick": { "link": "/categories" @@ -26,8 +23,7 @@ "label": "Applications", "type": "internal", "current": { - "pathname": "/applications", - "operator": "includes" + "pathname": "/applications" }, "handleClick": { "link": "/applications" @@ -36,16 +32,14 @@ { "label": "Components", "current": { - "pathname": "/components", - "operator": "includes" + "pathname": "/components" }, "subItems": [ { "label": "All components", "type": "internal", "current": { - "pathname": "/components", - "operator": "includes" + "pathname": "/components" }, "handleClick": { "link": "/components" @@ -56,20 +50,17 @@ "type": "internal", "current": { "pathname": "/components", - "operator": "includes", "filterCondition": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "process", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "process" } }, "handleClick": { "link": "/components", "type": "internal", "setFilter": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "process", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "process" } } }, @@ -78,19 +69,16 @@ "type": "internal", "current": { "pathname": "/components", - "operator": "includes", "filterCondition": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "data", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "data" } }, "handleClick": { "link": "/components", "setFilter": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "data", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "data" } } }, @@ -99,19 +87,16 @@ "type": "internal", "current": { "pathname": "/components", - "operator": "includes", "filterCondition": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "service", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "service" } }, "handleClick": { "link": "/components", "setFilter": { - "filter": "embedded.nl.embedded.commonground.layerType", - "value": "service", - "isObject": true + "filterKey": "embedded.nl.embedded.commonground.layerType", + "value": "service" } } } @@ -121,8 +106,7 @@ "label": "Organizations", "type": "internal", "current": { - "pathname": "/organizations", - "operator": "includes" + "pathname": "/organizations" }, "handleClick": { "link": "/organizations" @@ -133,17 +117,15 @@ "type": "internal", "current": { "pathname": "/components", - "operator": "includes", "filterCondition": { - "filter": "developmentStatus", - "value": "concept", - "isObject": true + "filterKey": "developmentStatus", + "value": "concept" } }, "handleClick": { "link": "/components", "setFilter": { - "filter": "developmentStatus", + "filterKey": "developmentStatus", "value": "concept" } } @@ -151,16 +133,14 @@ { "label": "Documentatie", "current": { - "pathname": "/documentation", - "operator": "includes" + "pathname": "/documentation" }, "subItems": [ { "label": "About", "type": "internal", "current": { - "pathname": "/documentation/about", - "operator": "equals" + "pathname": "/documentation/about" }, "handleClick": { "link": "/documentation/about" @@ -170,8 +150,7 @@ "label": "Use", "type": "internal", "current": { - "pathname": "/documentation/usage", - "operator": "equals" + "pathname": "/documentation/usage" }, "handleClick": { "link": "/documentation/usage" diff --git a/pwa/src/templates/templateParts/header/HeaderTemplate.module.css b/pwa/src/templates/templateParts/header/HeaderTemplate.module.css index ceee307b1..3507f14e6 100644 --- a/pwa/src/templates/templateParts/header/HeaderTemplate.module.css +++ b/pwa/src/templates/templateParts/header/HeaderTemplate.module.css @@ -18,6 +18,7 @@ background-color: var(--conduction-primary-top-nav-background-color, inherit); box-shadow: 0px 10px 13px -14px #000000; z-index: 1; + top: 0; display: flex; justify-content: space-between; diff --git a/pwa/src/templates/templateParts/header/HeaderTemplate.tsx b/pwa/src/templates/templateParts/header/HeaderTemplate.tsx index c3645dda9..f3db4cd66 100644 --- a/pwa/src/templates/templateParts/header/HeaderTemplate.tsx +++ b/pwa/src/templates/templateParts/header/HeaderTemplate.tsx @@ -2,10 +2,9 @@ import * as React from "react"; import * as styles from "./HeaderTemplate.module.css"; import clsx from "clsx"; import LogoRotterdam from "../../../assets/svgs/LogoRotterdam.svg"; -import { Paragraph, Heading } from "@utrecht/component-library-react/dist/css-module"; import { useTranslation } from "react-i18next"; import { navigate } from "gatsby"; -import { Container, PrimaryTopNav, SecondaryTopNav } from "@conduction/components"; +import { Container, Jumbotron, PrimaryTopNav, SecondaryTopNav } from "@conduction/components"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCircleUser } from "@fortawesome/free-solid-svg-icons"; import { useGatsbyContext } from "../../../context/gatsby"; @@ -14,11 +13,12 @@ import { PageHeader } from "@utrecht/component-library-react"; import { isHomepage } from "../../../services/isHomepage"; import { Breadcrumbs } from "../../../components/breadcrumbs/Breadcrumbs"; import { ITopNavItem } from "@conduction/components/lib/components/topNav/primaryTopNav/PrimaryTopNav"; -import { IFiltersContext, defaultFiltersContext, useFiltersContext } from "../../../context/filters"; +import { useFiltersContext } from "../../../context/filters"; import { useHeaderContent } from "../../../hooks/headerContent"; +import { useHeaderTopNavItems } from "../../../hooks/useHeaderTopNavItems"; export const DEFAULT_HEADER_CONTENT_URL = - "https://raw.githubusercontent.com/OpenCatalogi/web-app/348679b7537b20e51767dfdc6086349602afe219/pwa/src/templates/templateParts/header/HeaderContent.json"; + "https://raw.githubusercontent.com/OpenCatalogi/web-app/main/pwa/src/templates/templateParts/header/HeaderContent.json"; interface HeaderTemplateProps { layoutClassName?: string; @@ -26,8 +26,14 @@ interface HeaderTemplateProps { export const HeaderTemplate: React.FC = ({ layoutClassName }) => { const { t } = useTranslation(); + const { filters } = useFiltersContext(); const [topNavItems, setTopNavItems] = React.useState([]); + const _useHeaderContent = useHeaderContent(); + const getHeaderContent = _useHeaderContent.getContent(); + + const { headerTopNavItems } = useHeaderTopNavItems(getHeaderContent.data); + const { pageContext: { breadcrumb: { crumbs }, @@ -36,7 +42,6 @@ export const HeaderTemplate: React.FC = ({ layoutClassName screenSize, } = useGatsbyContext(); - const { filters, setFilters } = useFiltersContext(); const secondaryTopNavItemsMobile: ITopNavItem[] = [ { label: t("Login"), @@ -61,117 +66,15 @@ export const HeaderTemplate: React.FC = ({ layoutClassName }, ]; - const _useHeaderContent = useHeaderContent(); - const getHeaderContent = _useHeaderContent.getContent(); - React.useEffect(() => { - const itemsArray: ITopNavItem[] = []; - - getHeaderContent.isSuccess && - getHeaderContent.data.map((item: any) => { - const isCurrent = (current: any) => { - if (current && !current.filterCondition) { - switch (current.operator) { - case "equals": - if (process.env.GATSBY_USE_GITHUB_REPOSITORY_NAME_AS_PATH_PREFIX === "true") { - return pathname === `/${process.env.GATSBY_GITHUB_REPOSITORY_NAME}${current.pathname}`; - } else { - return pathname === current.pathname; - } - - case "includes": - return pathname.includes(current.pathname); - } - } - if (current && current.filterCondition) { - switch (current.operator) { - case "equals": - if (process.env.GATSBY_USE_GITHUB_REPOSITORY_NAME_AS_PATH_PREFIX === "true") { - return pathname === `/${process.env.GATSBY_GITHUB_REPOSITORY_NAME}${current.pathname}` && - current.filterCondition?.isObject === true - ? filters[current.filterCondition.filter as keyof IFiltersContext] - ?.toString() - .includes(current.filterCondition.value) - : filters[current.filterCondition.filter as keyof IFiltersContext] === current.filterConditon.value; - } else { - return pathname === current.pathname && current.filterCondition?.isObject === true - ? filters[current.filterCondition.filter as keyof IFiltersContext] - ?.toString() - ?.includes(current.filterCondition.value) - : filters[current.filterCondition.filter as keyof IFiltersContext] === current.filterConditon.value; - } - - case "includes": - return current.filterCondition?.isObject === true - ? pathname.includes(current.pathname) && - filters[current.filterCondition.filter as keyof IFiltersContext] - ?.toString() - ?.includes(current.filterCondition?.value) - : pathname.includes(current.pathname) && - filters[current.filterCondition.filter as keyof IFiltersContext] === - current.filterCondition?.value; - } - } - }; - - const getOnClick = (onClick: any, type: "readme" | "internal" | "external", label: string) => { - if (!onClick || !type || !label) return; - - if (onClick.link && !onClick.setFilter) { - if (type === "internal") { - navigate(onClick.link); - } - if (type === "external") { - open(onClick.link); - } - if (type === "readme") { - navigate(`/github/${label.replaceAll(" ", "_")}/?link=${onClick.link}`); - } - } - if (onClick.link && onClick.setFilter && type === "internal") { - onClick.setFilter?.isObject === true - ? setFilters({ ...defaultFiltersContext, [onClick.setFilter!.filter]: [onClick.setFilter!.value] }) - : setFilters({ ...defaultFiltersContext, [onClick.setFilter!.filter]: onClick.setFilter!.value }); - navigate(onClick.link); - } - }; - - const setSubItems = (subItems: ITopNavItem[]) => { - if (!subItems) return; - const subItemsArray: ITopNavItem[] = []; - - subItems.map((item: any) => { - subItemsArray.push({ - label: t(item.label), - type: item.type, - current: isCurrent(item.current), - handleClick: () => getOnClick(item.handleClick, item.type, item.label), - }); - }); - - const subItemsObject = Object.assign(subItemsArray); - - return subItemsObject; - }; - - itemsArray.push({ - label: t(item.label), - type: item.type, - current: isCurrent(item.current), - handleClick: () => getOnClick(item.handleClick, item.type, item.label), - subItems: setSubItems(item.subItems), - }); - }); - if (screenSize === "desktop") { - setTopNavItems(itemsArray); - + setTopNavItems(headerTopNavItems); return; } process.env.GATSBY_HEADER_SHOW_LOGIN === "true" - ? setTopNavItems([...itemsArray, ...secondaryTopNavItemsMobile]) - : setTopNavItems(itemsArray); + ? setTopNavItems([...headerTopNavItems, ...secondaryTopNavItemsMobile]) + : setTopNavItems(headerTopNavItems); }, [screenSize, pathname, crumbs, filters, getHeaderContent.isSuccess]); return ( @@ -201,24 +104,52 @@ export const HeaderTemplate: React.FC = ({ layoutClassName
{isHomepage(pathname) && ( - -
-
- - {process.env.GATSBY_JUMBOTRON_TITLE && process.env.GATSBY_JUMBOTRON_TITLE !== "" - ? process.env.GATSBY_JUMBOTRON_TITLE - : t("Open Catalogs")} - - - - {process.env.GATSBY_JUMBOTRON_SUBTITLE && process.env.GATSBY_JUMBOTRON_SUBTITLE !== "" - ? process.env.GATSBY_JUMBOTRON_SUBTITLE - : t("One central place for reuse of information technology within the government")} - -
- -
-
+ , + show: + process.env.GATSBY_JUMBOTRON_SEARCHFORM && process.env.GATSBY_JUMBOTRON_SEARCHFORM !== "" + ? process.env.GATSBY_JUMBOTRON_SEARCHFORM === "true" && true + : false, + }} + image={{ + placement: + process.env.GATSBY_JUMBOTRON_IMAGE_PLACEMENT && process.env.GATSBY_JUMBOTRON_IMAGE_PLACEMENT !== "" + ? process.env.GATSBY_JUMBOTRON_IMAGE_PLACEMENT === "background" + ? "background" + : process.env.GATSBY_JUMBOTRON_IMAGE_PLACEMENT === "right" + ? "right" + : "false" + : "false", + url: + process.env.GATSBY_JUMBOTRON_IMAGE_URL && process.env.GATSBY_JUMBOTRON_IMAGE_URL !== "" + ? process.env.GATSBY_JUMBOTRON_IMAGE_URL + : "", + }} + /> )} diff --git a/pwa/src/templates/templateParts/landingDisplayTemplates/LandingDisplayTemplate.tsx b/pwa/src/templates/templateParts/landingDisplayTemplates/LandingDisplayTemplate.tsx index 52e679b35..4e1c1976f 100644 --- a/pwa/src/templates/templateParts/landingDisplayTemplates/LandingDisplayTemplate.tsx +++ b/pwa/src/templates/templateParts/landingDisplayTemplates/LandingDisplayTemplate.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { TLandingDisplayLayout } from "../../../context/filters"; +import { TLandingDisplayLayout } from "../../../context/resultDisplayLayout"; import { LayersLandingDisplayTemplate } from "./layer/LayersLandingDisplayTemplate"; import { CategoriesLandingDisplayTemplate } from "./categories/CategoriesLandingDisplayTemplate"; diff --git a/pwa/src/templates/templateParts/landingDisplayTemplates/categories/CategoriesLandingDisplayTemplate.tsx b/pwa/src/templates/templateParts/landingDisplayTemplates/categories/CategoriesLandingDisplayTemplate.tsx index 3f74260bf..e45afc1d6 100644 --- a/pwa/src/templates/templateParts/landingDisplayTemplates/categories/CategoriesLandingDisplayTemplate.tsx +++ b/pwa/src/templates/templateParts/landingDisplayTemplates/categories/CategoriesLandingDisplayTemplate.tsx @@ -1,5 +1,7 @@ import * as React from "react"; import * as styles from "./CategoriesLandingDisplayTemplate.module.css"; +import clsx from "clsx"; +import Collapsible from "react-collapsible"; import { Button, Link } from "@utrecht/component-library-react/dist/css-module"; import { Heading, Paragraph, Icon } from "@utrecht/component-library-react/dist/css-module"; import { useTranslation } from "react-i18next"; @@ -7,12 +9,9 @@ import { CategoryCard } from "../../../../components/categoryCard/CategoryCard"; import { IconArrowRight } from "@tabler/icons-react"; import { TEMPORARY_DOMAINS } from "../../../../data/domains"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faChevronRight, faTags } from "@fortawesome/free-solid-svg-icons"; +import { faArrowRight, faChevronRight, faTags } from "@fortawesome/free-solid-svg-icons"; import { TEMPORARY_PORTFOLIOS } from "../../../../data/portfolio"; -import Collapsible from "react-collapsible"; import { useGatsbyContext } from "../../../../context/gatsby"; -import clsx from "clsx"; -import { ButtonLink } from "../../../../components"; import { navigate } from "gatsby-link"; export const CategoriesLandingDisplayTemplate = (): JSX.Element => { @@ -42,6 +41,7 @@ export const CategoriesLandingDisplayTemplate = (): JSX.Element => { {categories @@ -50,7 +50,12 @@ export const CategoriesLandingDisplayTemplate = (): JSX.Element => { .map((_category, idx) => (
- navigate(`/categories/${_category.id}`)}> + { + e.preventDefault(), navigate(`/categories/${_category.id}`); + }} + href={`/categories/${_category.id}`} + > @@ -68,7 +73,12 @@ export const CategoriesLandingDisplayTemplate = (): JSX.Element => { .map((_category, idx) => (
- navigate(`/categories/${_category.id}`)}> + { + e.preventDefault(), navigate(`/categories/${_category.id}`); + }} + href={`/categories/${_category.id}`} + > @@ -87,7 +97,12 @@ export const CategoriesLandingDisplayTemplate = (): JSX.Element => { .map((_category, idx) => (
- navigate(`/categories/${_category.id}`)}> + { + e.preventDefault(), navigate(`/categories/${_category.id}`); + }} + href={`/categories/${_category.id}`} + > @@ -119,9 +134,9 @@ export const CategoriesLandingDisplayTemplate = (): JSX.Element => { ))}
- - Bekijk alle categorieën - + ); }; diff --git a/pwa/src/templates/templateParts/resultsTemplates/ComponentResultsTemplate.tsx b/pwa/src/templates/templateParts/resultsTemplates/ComponentResultsTemplate.tsx index 547902cfa..97559adbd 100644 --- a/pwa/src/templates/templateParts/resultsTemplates/ComponentResultsTemplate.tsx +++ b/pwa/src/templates/templateParts/resultsTemplates/ComponentResultsTemplate.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { TComponentResultsLayout } from "../../../context/filters"; +import { TComponentResultsLayout } from "../../../context/resultDisplayLayout"; import { TableResultTemplate } from "./table/TableResultTemplate"; import { CardsResultTemplate } from "./cards/CardsResultTemplate"; import { LayersResultTemplate } from "./layers/LayersResultTemplate"; diff --git a/pwa/src/templates/templateParts/searchComponent/SearchComponentTemplate.tsx b/pwa/src/templates/templateParts/searchComponent/SearchComponentTemplate.tsx index fdfbda0bd..9bc12dbcb 100644 --- a/pwa/src/templates/templateParts/searchComponent/SearchComponentTemplate.tsx +++ b/pwa/src/templates/templateParts/searchComponent/SearchComponentTemplate.tsx @@ -4,9 +4,7 @@ import { useTranslation } from "react-i18next"; import { useForm } from "react-hook-form"; import { IFiltersContext, useFiltersContext } from "../../../context/filters"; import { navigate } from "gatsby"; -import { Button } from "@utrecht/component-library-react"; -import { ButtonLink } from "../../../components"; -import { FormField, Textbox, ButtonGroup } from "@utrecht/component-library-react/dist/css-module"; +import { FormField, Textbox, ButtonGroup, Button } from "@utrecht/component-library-react/dist/css-module"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowRight, faSearch } from "@fortawesome/free-solid-svg-icons"; import { usePaginationContext } from "../../../context/pagination"; @@ -16,7 +14,7 @@ interface SearchComponentTemplateProps { } export const SearchComponentTemplate: React.FC = ({ layoutClassName }) => { - const { filters, setFilters } = useFiltersContext(); + const { setFilters } = useFiltersContext(); const { pagination, setPagination } = usePaginationContext(); const { t } = useTranslation(); @@ -29,9 +27,6 @@ export const SearchComponentTemplate: React.FC = ( const onSubmit = (data: any): void => { setFilters({ _search: data.name, - resultDisplayLayout: filters.resultDisplayLayout, - dependenciesDisplayLayout: filters.dependenciesDisplayLayout, - landingDisplayLayout: filters.landingDisplayLayout, } as IFiltersContext); setPagination({ ...pagination, @@ -43,11 +38,6 @@ export const SearchComponentTemplate: React.FC = ( }; const clearFilters = () => { - setFilters({ - resultDisplayLayout: filters.resultDisplayLayout, - dependenciesDisplayLayout: filters.dependenciesDisplayLayout, - landingDisplayLayout: filters.landingDisplayLayout, - } as IFiltersContext); setPagination({ ...pagination, componentsCurrentPage: pagination.componentsCurrentPage, @@ -72,10 +62,14 @@ export const SearchComponentTemplate: React.FC = ( {t("Search")} - + ); diff --git a/pwa/static/.env.development b/pwa/static/.env.development index 7605da672..ed381d97d 100644 --- a/pwa/static/.env.development +++ b/pwa/static/.env.development @@ -14,21 +14,38 @@ GATSBY_ADMIN_DASHBOARD_URL=https://admin.opencatalogi.nl # Config GATSBY_NL_DESIGN_THEME_CLASSNAME=rotterdam-theme # GATSBY_GITHUB_ORGANIZATION_URL="https://github.com/ConductionNL" +GATSBY_FAVICON_URL="https://dev.opencatalogi.nl/static/logo_OpenCatalogi-8b1b0a001c3f37dae4d3f69b5964ec72.png" +GATSBY_PAGE_TITLE= # Header GATSBY_HEADER_LOGO_URL=https://www.rotterdam.nl/images/logo-base.svg GATSBY_HEADER_SHOW_LOGIN="false" -GATSBY_HEADER_CONTENT=https://raw.githubusercontent.com/OpenCatalogi/web-app/348679b7537b20e51767dfdc6086349602afe219/pwa/src/templates/templateParts/header/HeaderContent.json -GATSBY_FAVICON_URL= +GATSBY_HEADER_CONTENT=https://raw.githubusercontent.com/OpenCatalogi/web-app/main/pwa/src/templates/templateParts/header/HeaderContent.json # Jumbotron GATSBY_JUMBOTRON_TITLE= GATSBY_JUMBOTRON_SUBTITLE= +# options: "false" | "background" | "right" +GATSBY_JUMBOTRON_IMAGE_PLACEMENT="false" +GATSBY_JUMBOTRON_IMAGE_URL= +GATSBY_JUMBOTRON_DESCRIPTION= +# options: "true" | "false" +GATSBY_JUMBOTRON_ISCARD="false" +# options: "true" | "false" +GATSBY_JUMBOTRON_SEARCHFORM="true" +# options: "true" | "false" +GATSBY_JUMBOTRON_CONTAINER="true" + # Footer GATSBY_FOOTER_SHOW_CREATOR="false" GATSBY_FOOTER_LOGO_URL="false" GATSBY_FOOTER_CONTENT="https://raw.githubusercontent.com/OpenCatalogi/web-app/25995205e1dbb043822d1c58c5c23f8e6f77ff7e/pwa/src/templates/templateParts/footer/FooterContent.json" +# options: "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" +GATSBY_FOOTER_CONTENT_HEADER="" + +# options: "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" +GATSBY_FOOTER_CONTENT_HEADER="" # Home GATSBY_OPTIONAL_START_PAGE= diff --git a/pwa/static/.env.production b/pwa/static/.env.production index 79a6cddd0..27de22829 100644 --- a/pwa/static/.env.production +++ b/pwa/static/.env.production @@ -24,11 +24,24 @@ GATSBY_FAVICON_URL= # Jumbotron GATSBY_JUMBOTRON_TITLE= GATSBY_JUMBOTRON_SUBTITLE= +# options: "false" | "background" | "rights" +GATSBY_JUMBOTRON_IMAGE_PLACEMENT= +GATSBY_JUMBOTRON_IMAGE_URL= +GATSBY_JUMBOTRON_DESCRIPTION= +# options: "true" | "false" +GATSBY_JUMBOTRON_ISCARD= +# options: "true" | "false" +GATSBY_JUMBOTRON_SEARCHFORM= # Footer GATSBY_FOOTER_SHOW_CREATOR= GATSBY_FOOTER_LOGO_URL= GATSBY_FOOTER_CONTENT= +# options: "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" +GATSBY_FOOTER_CONTENT_HEADER= + +# options: "heading-1" | "heading-2" | "heading-3" | "heading-4" | "heading-5" +GATSBY_FOOTER_CONTENT_HEADER= # Home GATSBY_OPTIONAL_START_PAGE=