From 9c87b069e24ec87276bfd73f99b9035ba2606e3f Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Fri, 5 Dec 2025 12:30:45 +0800 Subject: [PATCH 1/2] feat: add support for custom spinners --- frontend/src/components/Spinner/Spinner.tsx | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Spinner/Spinner.tsx b/frontend/src/components/Spinner/Spinner.tsx index f1cc44a1a3..ca59991dcc 100644 --- a/frontend/src/components/Spinner/Spinner.tsx +++ b/frontend/src/components/Spinner/Spinner.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { BiLoader } from 'react-icons/bi' import { + Box, Flex, FlexProps, Icon, @@ -30,6 +31,11 @@ interface SpinnerProps extends FlexProps { */ label?: string + /** + * Custom spinner element. If not provided, a default spinner icon will be used. + */ + element?: JSX.Element + /** * Font size of the spinner. */ @@ -50,6 +56,7 @@ export const Spinner = ({ color = 'inherit', label: userSpecifiedLabel, fontSize = '1rem', + element, ...flexProps }: SpinnerProps): JSX.Element => { const { t } = useTranslation() @@ -66,12 +73,16 @@ export const Spinner = ({ return ( {label && {label}} - + {element ? ( + {element} + ) : ( + + )} ) } From ee205ab86a6fcc3e3371de46228d545a99b52149 Mon Sep 17 00:00:00 2001 From: Eliot Lim Date: Fri, 5 Dec 2025 12:31:54 +0800 Subject: [PATCH 2/2] feat: add button ogp-spinner --- frontend/src/assets/svgrs/brand/OgpLogo.tsx | 33 +++++++++++++++++++++ frontend/src/components/Button/Button.tsx | 25 +++++++++++++++- shared/constants/feature-flags.ts | 1 + 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 frontend/src/assets/svgrs/brand/OgpLogo.tsx diff --git a/frontend/src/assets/svgrs/brand/OgpLogo.tsx b/frontend/src/assets/svgrs/brand/OgpLogo.tsx new file mode 100644 index 0000000000..bf4c91c2c5 --- /dev/null +++ b/frontend/src/assets/svgrs/brand/OgpLogo.tsx @@ -0,0 +1,33 @@ +import { SVGProps } from 'react' + +export const OgpLogo = (props: SVGProps) => { + return ( + + + + + + + + + + ) +} diff --git a/frontend/src/components/Button/Button.tsx b/frontend/src/components/Button/Button.tsx index f1d4aedd4b..b2de025df4 100644 --- a/frontend/src/components/Button/Button.tsx +++ b/frontend/src/components/Button/Button.tsx @@ -4,6 +4,11 @@ import { forwardRef, IconProps, } from '@chakra-ui/react' +import { useGrowthBook } from '@growthbook/growthbook-react' + +import { featureFlags } from '~shared/constants' + +import { OgpLogo } from '~assets/svgrs/brand/OgpLogo' import Spinner from '../Spinner' @@ -30,10 +35,28 @@ export const Button = forwardRef( { children, spinnerFontSize, isFullWidth, isHighContrast, ...props }, ref, ) => { + const gb = useGrowthBook() + + // Ensures compatibility between Chakra size definitions and those supported by the SVG logo + const spinnerSize = + typeof spinnerFontSize === 'string' || typeof spinnerFontSize === 'number' + ? spinnerFontSize + : '1.5rem' + + const spinner = gb?.isOn(featureFlags.ogpSpinner) ? ( + } + /> + ) : ( + + ) + return ( } + spinner={spinner} width={isFullWidth ? '100%' : undefined} {...props} {...(isFullWidth ? { minH: '3.5rem' } : {})} diff --git a/shared/constants/feature-flags.ts b/shared/constants/feature-flags.ts index 732ab38d10..6cb5f0b007 100644 --- a/shared/constants/feature-flags.ts +++ b/shared/constants/feature-flags.ts @@ -28,4 +28,5 @@ export const featureFlags = { singpassMrf: 'singpass-mrf' as const, enableSaveDraftButtonFloating: 'enable-save-draft-button-floating' as const, enableSaveDraftButtonHeader: 'enable-save-draft-button-header' as const, + ogpSpinner: 'ogp-spinner' as const, }