Skip to content

Commit

Permalink
DIGG-482: Fixing types in entryscape blocks, small code improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Kopin1 committed Dec 1, 2024
1 parent efbfe6e commit 269ed76
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 133 deletions.
102 changes: 65 additions & 37 deletions components/custom-image/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,71 +6,99 @@ import noImage from "@/assets/logos/noImage.png";
import { ImageFragment as ImageInterface } from "@/graphql/__generated__/operations";
import { isExternalLink } from "@/utilities";

/**
* Props for the CustomImage component
* @interface CustomImageProps
*/
interface CustomImageProps {
/** The image object containing url, width, height, and alt text */
image: ImageInterface | null;
/** Responsive image sizes attribute */
sizes?: string;
/** Additional CSS classes */
className?: string;
/** Whether to prioritize image loading */
priority?: boolean;
/** Desired image width */
width?: number;
/** Image quality (1-100) */
quality?: number;
}

const isNextStatic = (url: string) =>
typeof url != "string" || !url.startsWith("/uploads");
/** Default dimensions and quality settings */
const DEFAULT_WIDTH = 384;
const DEFAULT_HEIGHT = 200;
const DEFAULT_QUALITY = 75;
const DEFAULT_SIZES =
"(max-width: 640px) 100vw, (max-width: 1200px) 50vw, 20vw";

/**
* Checks if the image URL is a Next.js static asset
* @param url - The image URL to check
* @returns boolean indicating if the URL is a Next.js static asset
*/
const isNextStatic = (url: string) => !url.startsWith("/uploads");

/**
* Generates the complete image URL with width and quality parameters
* @param imageUrl - The base image URL
* @param width - Desired image width
* @param quality - Desired image quality
* @returns The complete image URL with parameters
*/
const getImageUrl = (imageUrl: string, width: number, quality: number) => {
if (isExternalLink(imageUrl)) return imageUrl;
const baseUrl = env("MEDIA_BASE_URL") || "";
return `${baseUrl}${imageUrl}?w=${width}&q=${quality}`;
};

/**
* A custom Image component that handles various image sources and formats
* Supports external images, Next.js static assets, and dynamic images with optimization
* Falls back to a placeholder image when no image is provided
*/
export const CustomImage: FC<CustomImageProps> = ({
image,
sizes,
className,
sizes = DEFAULT_SIZES,
className = "",
priority = false,
width,
width = DEFAULT_WIDTH,
quality = DEFAULT_QUALITY,
}) => {
if (!image) {
return (
<Image
src={noImage}
width={384}
height={200}
alt={"image not found"}
width={DEFAULT_WIDTH}
height={DEFAULT_HEIGHT}
alt="image not found"
className={className}
sizes="(max-width: 640px) 100vw, (max-width: 1200px) 50vw, 20vw"
sizes={sizes}
loading="lazy"
/>
);
}

const imageProps = {
width: Number(image.width) || DEFAULT_WIDTH,
height: Number(image.height) || DEFAULT_HEIGHT,
className,
alt: image.alt || "",
sizes,
priority,
};

if (isNextStatic(image.url)) {
return (
<Image
key={image.url}
src={image.url}
width={image.width || 384}
height={image.height || 200}
className={className}
alt={image.alt || ""}
sizes={
sizes
? sizes
: "(max-width: 640px) 100vw, (max-width: 1200px) 50vw, 20vw"
}
priority={priority}
/>
);
// eslint-disable-next-line jsx-a11y/alt-text
return <Image src={image.url} {...imageProps} />;
}

const src = isExternalLink(image.url)
? image.url
: (env("MEDIA_BASE_URL") || "") + image.url;

return (
// eslint-disable-next-line jsx-a11y/alt-text
<Image
key={src}
src={`${src}?w=${width || 384}&q=${75}`}
width={Number(image.width) || 384}
height={Number(image.height) || 200}
className={className ? className : ""}
alt={image.alt || ""}
unoptimized={true}
priority={priority}
src={getImageUrl(image.url, width, quality)}
{...imageProps}
unoptimized
/>
);
};
4 changes: 2 additions & 2 deletions features/search/search-filters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const MarkAll: FC<MarkAllProps> = ({ search, toggleKey, title }) => {
: [],
});

let wildcardFacet: SearchFacetValue = {
const wildcardFacet: SearchFacetValue = {
count: -1,
facet: toggleKey,
facetType: ESType.wildcard,
Expand Down Expand Up @@ -181,7 +181,7 @@ export const SearchFilters: React.FC<SearchFilterProps> = ({
await search.toggleFacet(facetValue);

if (search.facetSelected(key, "*")) {
let wildcardFacet: SearchFacetValue = {
const wildcardFacet: SearchFacetValue = {
count: -1,
facet: key,
facetType: ESType.wildcard,
Expand Down
2 changes: 1 addition & 1 deletion features/search/search-input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const SearchInput: FC<SearchInputProps> = ({
icon={CloseIcon}
iconPosition="right"
onClick={() => {
submitSearch && submitSearch("");
submitSearch?.("");
setQuery("");
}}
aria-label={t("common|clear-search")}
Expand Down
109 changes: 50 additions & 59 deletions features/search/search-page-selector/index.tsx
Original file line number Diff line number Diff line change
@@ -1,80 +1,71 @@
/**
* @fileoverview Search page selector component that provides navigation tabs
* for different search categories (datasets, concepts, specifications, content).
*/

import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import React from "react";

import { ButtonLink } from "@/components/button";

/**
* Props for the SearchPageSelector component
* @interface
*/
interface SearchTabsProps {
/** The current search query string */
query?: string;
}

//Navigation between data & Api:s, concepts, specifications.
export const SearchPageSelector: React.FC<SearchTabsProps> = ({ query }) => {
/**
* Configuration for search tabs defining their paths and translation keys
* @constant
*/
const SEARCH_TABS = [
{ path: "/datasets", translationKey: "search$datasets" },
{ path: "/concepts", translationKey: "search$concepts" },
{ path: "/specifications", translationKey: "search$specifications" },
{ path: "/search", translationKey: "search$content" },
] as const;

/**
* Navigation component that displays tabs for different search categories.
* Highlights the currently active tab and maintains the search query across navigation.
*
* @component
* @param {SearchTabsProps} props - The component props
* @param {string} [props.query] - The current search query string
* @returns {JSX.Element} A navigation component with search category tabs
*/
export function SearchPageSelector({ query }: SearchTabsProps) {
const { t, lang } = useTranslation("pages");
const { pathname } = useRouter() || {};

return (
<nav aria-label={t("search$search-type-navigation")}>
<div
className="mb-lg flex gap-md overflow-x-scroll md:overflow-x-visible"
className="mb-lg flex gap-md overflow-x-scroll md:overflow-x-visible"
role="tablist"
aria-label={t("search$search-tabs")}
>
<ButtonLink
variant={"plain"}
href={`/datasets?q=${query ? query : ""}&f=`}
label={t("search$datasets")}
locale={lang}
className={`focus--in whitespace-nowrap ${
pathname === "/datasets"
? "bg-pink-200 font-strong text-textPrimary"
: ""
}`}
role="tab"
aria-selected={pathname === "/datasets"}
/>

<ButtonLink
variant={"plain"}
href={`/concepts?q=${query ? query : ""}&f=`}
label={t("search$concepts")}
locale={lang}
className={`focus--in whitespace-nowrap ${
pathname === "/concepts"
? "bg-pink-200 font-strong text-textPrimary"
: ""
}`}
role="tab"
aria-selected={pathname === "/concepts"}
/>

<ButtonLink
variant={"plain"}
href={`/specifications?q=${query ? query : ""}&f=`}
label={t("search$specifications")}
locale={lang}
className={`focus--in whitespace-nowrap ${
pathname === "/specifications"
? "bg-pink-200 font-strong text-textPrimary"
: ""
}`}
role="tab"
aria-selected={pathname === "/specifications"}
/>

<ButtonLink
variant={"plain"}
href={`/search?q=${query ? query : ""}&f=`}
label={t("search$content")}
locale={lang}
className={`focus--in whitespace-nowrap ${
pathname === "/search"
? "bg-pink-200 font-strong text-textPrimary"
: ""
}`}
role="tab"
aria-selected={pathname === "/search"}
/>
{SEARCH_TABS.map(({ path, translationKey }) => (
<ButtonLink
key={path}
variant="plain"
href={`${path}?q=${query || ""}&f=`}
label={t(translationKey)}
locale={lang}
className={`focus--in whitespace-nowrap ${
pathname === path
? "bg-pink-200 font-strong text-textPrimary"
: ""
}`}
role="tab"
aria-selected={pathname === path}
/>
))}
</div>
</nav>
);
};
}
6 changes: 4 additions & 2 deletions utilities/app.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Translate } from "next-translate";

import {
GoodExampleDataFragment,
ImageFragment,
NewsItemDataFragment,
SeoDataFragment,
} from "@/graphql/__generated__/operations";
import { SeoDataFragment } from "@/graphql/__generated__/operations";
import {
FormResponse,
GoodExampleListResponse,
Expand Down Expand Up @@ -47,7 +49,7 @@ type ResolvedPage = {
export const resolvePage = (
props: DataportalPageProps,
lang: string,
t: any,
t: Translate,
): ResolvedPage => {
if (props.type === "RootAggregate" && lang === "en") {
return {
Expand Down
3 changes: 2 additions & 1 deletion utilities/entryscape/blocks/apiexplore.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { customIndicators } from "./global";
import { Translate } from "next-translate";

import { customIndicators } from "./global";

export const apiexploreBlocks = (t: Translate, iconSize: number) => {
return [...customIndicators(t, iconSize)];
};
12 changes: 7 additions & 5 deletions utilities/entryscape/blocks/concept.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { getSimplifiedLocalizedValue } from "@/utilities/entrystore-utils";
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Entry } from "@entryscape/entrystore-js";
import { Translate } from "next-translate";

import { getSimplifiedLocalizedValue } from "@/utilities/entrystore-utils";

export const conceptBlocks = (t: Translate, iconSize: number, lang: string) => [
{
block: "broaderList",
Expand Down Expand Up @@ -36,19 +38,19 @@ export const conceptBlocks = (t: Translate, iconSize: number, lang: string) => [
block: "conceptLink",
run: function (node: any, a2: any, a3: any, entry: Entry) {
if (node && node.firstElementChild && entry) {
var el = document.createElement("a");
const el = document.createElement("a");

node.setAttribute("class", "entryscape");

node.firstElementChild.appendChild(el);

var ruri = entry.getResourceURI();
var label = getSimplifiedLocalizedValue(
const ruri = entry.getResourceURI();
const label = getSimplifiedLocalizedValue(
entry.getAllMetadata(),
"skos:prefLabel",
);
el.innerHTML = label;
var dpUri = getDataportalUri(ruri, lang);
const dpUri = getDataportalUri(ruri, lang);
el.setAttribute("href", dpUri);
}
},
Expand Down
3 changes: 2 additions & 1 deletion utilities/entryscape/blocks/datasets.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Translate } from "next-translate";

import {
catalog,
exploreApiLink,
keyword,
theme,
customIndicators,
} from "./global";
import { Translate } from "next-translate";

export const datasetBlocks = (
t: Translate,
Expand Down
Loading

0 comments on commit 269ed76

Please sign in to comment.