Skip to content

Commit

Permalink
feat: Added optional progress indicator to `<ShareContentByElements /…
Browse files Browse the repository at this point in the history
…>` component
  • Loading branch information
WolfyUK committed Jan 23, 2025
1 parent 317001e commit 148c6c6
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ function HorizontalBarChartInner<TData extends ChartDataSeries>(
<div style={{ height: 22 * filteredData.length + 75 }}>
<div
aria-label={chartTitle}
className="govuk-body-s govuk-!-font-size-14 full-height-width"
className="govuk-body-s govuk-!-font-size-14 full-height-width chart-wrapper"
role="img"
>
<ResponsiveContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function LineChartInner<TData extends ChartDataSeries>(
// a11y: https://github.com/recharts/recharts/issues/3816
<div
aria-label={chartTitle}
className="govuk-body-s govuk-!-font-size-14 full-height-width"
className="govuk-body-s govuk-!-font-size-14 full-height-width chart-wrapper"
role="img"
>
<ResponsiveContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function VerticalBarChartInner<TData extends ChartDataSeries>(
// a11y: https://github.com/recharts/recharts/issues/3816
<div
aria-label={chartTitle}
className="govuk-body-s govuk-!-font-size-14 full-height-width"
className="govuk-body-s govuk-!-font-size-14 full-height-width chart-wrapper"
role="img"
>
<ResponsiveContainer>
Expand Down
27 changes: 27 additions & 0 deletions front-end-components/src/components/progress/component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from "react";
import "src/components/progress/styles.css";
import { ProgressProps } from ".";
import classNames from "classnames";

// inspired by https://medium.com/@pppped/how-to-code-a-responsive-circular-percentage-chart-with-svg-and-css-3632f8cd7705
export const Progress: React.FC<ProgressProps> = ({
className,
percentage,
...props
}) => {
return (
<svg
viewBox="0 0 40 40"
className={classNames("progress-wrapper", className)}
{...props}
>
<path
className="progress-circle"
d="M20 4.0845
a 15.9155 15.9155 0 0 1 0 31.831
a 15.9155 15.9155 0 0 1 0 -31.831"
strokeDasharray={`${percentage}, 100`}
/>
</svg>
);
};
3 changes: 3 additions & 0 deletions front-end-components/src/components/progress/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* eslint-disable react-refresh/only-export-components */
export * from "src/components/progress/component";
export * from "src/components/progress/types";
24 changes: 24 additions & 0 deletions front-end-components/src/components/progress/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.progress-wrapper {
display: block;
max-width: 80%;
max-height: 250px;
}

.progress-wrapper.progress-left {
float: left;
margin-right: 10px;
}

.progress-wrapper .progress-circle {
stroke: #005EA5;
fill: none;
stroke-width: 6;
stroke-linecap: round;
animation: progress 1s ease-out forwards;
}

@keyframes progress {
0% {
stroke-dasharray: 0 100;
}
}
8 changes: 8 additions & 0 deletions front-end-components/src/components/progress/types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { SVGProps } from "react";

export type ProgressProps = Pick<
SVGProps<SVGSVGElement>,
"width" | "height" | "className"
> & {
percentage: number;
};
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { ShareContentByElementsProps } from "./types";
import { useDownloadPngImages } from "src/hooks/useDownloadImage";
import { ShareContent } from "../share-content";
import { Progress } from "../progress";

export const ShareContentByElements: React.FC<ShareContentByElementsProps> = ({
disabled,
elementsSelector,
showProgress,
showTitles,
label,
...props
}) => {
const [imagesLoading, setImagesLoading] = useState<boolean>();
const [progress, setProgress] = useState<number>();

const downloadPngs = useDownloadPngImages({
elementsSelector,
onImagesLoading: setImagesLoading,
onProgress: setProgress,
showTitles,
});

useEffect(() => {
if (!imagesLoading) {
setProgress(undefined);
}
}, [imagesLoading]);

return (
<ShareContent
disabled={imagesLoading || disabled}
onSaveClick={async () => await downloadPngs()}
{...props}
>
{label}
<>
{showProgress && progress && (
<Progress
className="progress-left"
percentage={progress}
width={18}
height={18}
/>
)}
{label}
</>
</ShareContent>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export type ShareContentByElementsProps = Omit<
> & {
elementsSelector: () => ElementAndTitle[];
label: string;
showProgress?: boolean;
showTitles?: boolean;
};
7 changes: 6 additions & 1 deletion front-end-components/src/hooks/useDownloadImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ElementAndTitle = {
export type DownloadPngImagesOptions = {
elementsSelector: () => ElementAndTitle[];
onImagesLoading?: (loading: boolean) => void;
onProgress?: (percentage: number) => void;
showTitles?: boolean;
} & Pick<ImageOptions, "filter">;

Expand Down Expand Up @@ -92,6 +93,7 @@ export function useDownloadPngImages({
elementsSelector,
filter,
onImagesLoading,
onProgress,
showTitles,
}: DownloadPngImagesOptions) {
const fileName = "download.zip";
Expand All @@ -107,6 +109,9 @@ export function useDownloadPngImages({

for (let i = 0; i < elements.length; i++) {
const { element, title } = elements[i];
if (onProgress) {
onProgress(((i + 1) / elements.length) * 100);
}

const blob = await ImageService.toBlob(
element,
Expand Down Expand Up @@ -149,7 +154,7 @@ export function useDownloadPngImages({
} else {
await download();
}
}, [elementsSelector, filter, onImagesLoading, showTitles]);
}, [elementsSelector, filter, onImagesLoading, onProgress, showTitles]);

return downloadPng;
}
Expand Down
59 changes: 31 additions & 28 deletions front-end-components/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -901,36 +901,39 @@ const shareContentByElementClassNameElements =

if (shareContentByElementClassNameElements) {
shareContentByElementClassNameElements.forEach((element) => {
const { elementClassName, elementTitleAttr, label, showTitles } =
element.dataset;
const {
elementClassName,
elementTitleAttr,
label,
showProgress,
showTitles,
} = element.dataset;
if (elementClassName && label) {
const el = document.getElementsByClassName(elementClassName);
if (el.length > 0) {
const root = ReactDOM.createRoot(element);
root.render(
<React.StrictMode>
<ShareContentByElements
elementsSelector={() => {
const results = [];
const elements =
document.getElementsByClassName(elementClassName);

for (let i = 0; i < elements.length; i++) {
const element = elements[i] as HTMLElement;
const title = elementTitleAttr
? element.getAttribute(elementTitleAttr) || undefined
: undefined;
results.push({ element, title });
}
const root = ReactDOM.createRoot(element);
root.render(
<React.StrictMode>
<ShareContentByElements
elementsSelector={() => {
const results = [];
const elements =
document.getElementsByClassName(elementClassName);

for (let i = 0; i < elements.length; i++) {
const element = elements[i] as HTMLElement;
const title = elementTitleAttr
? element.getAttribute(elementTitleAttr) || undefined
: undefined;
results.push({ element, title });
}

return results;
}}
label={label}
showTitles={showTitles === "true"}
/>
</React.StrictMode>
);
}
return results;
}}
label={label}
showProgress={showProgress === "true"}
showTitles={showTitles === "true"}
/>
</React.StrictMode>
);
}
});
}

0 comments on commit 148c6c6

Please sign in to comment.