diff --git a/app/src/components/GoBreadcrumbs/index.tsx b/app/src/components/GoBreadcrumbs/index.tsx new file mode 100644 index 0000000000..4b5f72d2e7 --- /dev/null +++ b/app/src/components/GoBreadcrumbs/index.tsx @@ -0,0 +1,46 @@ +import { useCallback } from 'react'; +import { Breadcrumbs } from '@ifrc-go/ui'; + +import Link, { type InternalLinkProps } from '../Link'; + +interface RouteData { + to: InternalLinkProps['to']; + label: React.ReactNode; + urlParams?: Record; +} + +interface GoBreadcrumbsProps { + routeData: RouteData[]; +} + +const keySelector = (datum: RouteData) => datum.to; +const labelSelector = (datum: RouteData) => datum.label; + +function GoBreadcrumbs(props: GoBreadcrumbsProps) { + const { routeData } = props; + + const rendererParams = useCallback((_: RouteData['to'], item: RouteData) + : InternalLinkProps => ( + { + to: item.to, + urlParams: item.urlParams, + } + ), []); + + return ( + + data={routeData} + keySelector={keySelector} + labelSelector={labelSelector} + renderer={Link} + rendererParams={rendererParams} + /> + ); +} + +export default GoBreadcrumbs; diff --git a/app/src/components/Navbar/CountryDropdown/styles.module.css b/app/src/components/Navbar/CountryDropdown/styles.module.css index 8e087e428e..4f583213d8 100644 --- a/app/src/components/Navbar/CountryDropdown/styles.module.css +++ b/app/src/components/Navbar/CountryDropdown/styles.module.css @@ -4,7 +4,7 @@ padding: var(--go-ui-spacing-md); max-width: 64rem; min-height: 16rem; - gap: var(--go-ui-spacing-md); + gap: var(--go-ui-spacing-sm); overflow: auto; .region-list { diff --git a/app/src/components/NavigationTab/index.tsx b/app/src/components/NavigationTab/index.tsx index e1c72e8e34..9843a7dd53 100644 --- a/app/src/components/NavigationTab/index.tsx +++ b/app/src/components/NavigationTab/index.tsx @@ -188,6 +188,9 @@ function NavigationTab(props: Props) { )}
{children} + {variant === 'primary' && ( +
+ )}
{variant === 'primary' && (
diff --git a/app/src/components/NavigationTab/styles.module.css b/app/src/components/NavigationTab/styles.module.css index 828c59680a..a6d5c866d5 100644 --- a/app/src/components/NavigationTab/styles.module.css +++ b/app/src/components/NavigationTab/styles.module.css @@ -135,14 +135,41 @@ } } + + &.secondary { + border-right: var(--border-width) solid var(--border-color); + border-top-color: transparent; + + .children-wrapper { + padding: var(--go-ui-spacing-md) var(--go-ui-spacing-lg); + } + + &.active { + color: var(--go-ui-color-primary-red); + } + + &:last-child { + border-color: transparent; + } + } + &.primary { position: relative; font-size: var(--go-ui-font-size-lg); .children-wrapper { + display:flex; + flex-direction: column; + gap: var(--go-ui-spacing-sm); border-bottom-color: var(--border-color); background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-md) var(--go-ui-spacing-lg); + padding: var(--go-ui-spacing-sm) var(--go-ui-spacing-lg) var(--go-ui-spacing-xs); + + } + + .active-children-border { + border: var(--go-ui-width-separator-small) solid transparent; + width: 100%; } &.active { @@ -152,6 +179,10 @@ border-color: var(--border-color); border-bottom-color: transparent; background-color: var(--go-ui-color-white); + + .active-children-border { + border-color: var(--go-ui-color-primary-red); + } } } @@ -162,16 +193,6 @@ } } - &.secondary { - border-radius: var(--go-ui-border-radius-full); - padding: var(--go-ui-spacing-sm) var(--go-ui-spacing-xl); - - &.active { - background-color: var(--go-ui-color-primary-red); - color: var(--go-ui-color-white); - } - } - &.tertiary { &:not(.disabled) { &:hover { diff --git a/app/src/components/domain/ActiveOperationMap/index.tsx b/app/src/components/domain/ActiveOperationMap/index.tsx index 68263837cb..e84d984fbc 100644 --- a/app/src/components/domain/ActiveOperationMap/index.tsx +++ b/app/src/components/domain/ActiveOperationMap/index.tsx @@ -425,7 +425,7 @@ function ActiveOperationMap(props: Props) { value={rawFilter.displacement} onChange={setFilterField} /> -
+
+ )} actions={!presentationMode && ( diff --git a/app/src/components/domain/ActiveOperationMap/styles.module.css b/app/src/components/domain/ActiveOperationMap/styles.module.css index be42392eeb..b9d1fdf89a 100644 --- a/app/src/components/domain/ActiveOperationMap/styles.module.css +++ b/app/src/components/domain/ActiveOperationMap/styles.module.css @@ -7,6 +7,10 @@ top: var(--go-ui-spacing-md); left: var(--go-ui-spacing-md); } + + } + .filter-actions { + align-self: end; } .map-container { diff --git a/app/src/views/Country/index.tsx b/app/src/views/Country/index.tsx index fae6891121..8c08522a52 100644 --- a/app/src/views/Country/index.tsx +++ b/app/src/views/Country/index.tsx @@ -10,7 +10,6 @@ import { } from 'react-router-dom'; import { PencilFillIcon } from '@ifrc-go/icons'; import { - Breadcrumbs, Message, NavigationTabList, } from '@ifrc-go/ui'; @@ -23,7 +22,8 @@ import { isTruthyString, } from '@togglecorp/fujs'; -import Link from '#components/Link'; +import GoBreadcrumbs from '#components/GoBreadcrumbs'; +import Link, { type InternalLinkProps } from '#components/Link'; import NavigationTab from '#components/NavigationTab'; import Page from '#components/Page'; import { adminUrl } from '#config'; @@ -43,6 +43,12 @@ import { useRequest } from '#utils/restRequest'; import i18n from './i18n.json'; import styles from './styles.module.css'; +type BreadcrumbsDataType = { + to: InternalLinkProps['to']; + label: string; + urlParams?: Record; +}; + // eslint-disable-next-line import/prefer-default-export export function Component() { const { countryId } = useParams<{ countryId: string }>(); @@ -94,6 +100,33 @@ export function Component() { { countryName: country?.name ?? strings.countryPageTitleFallbackCountry }, ); + const breadCrumbsData: BreadcrumbsDataType[] = useMemo(() => ([ + { + to: 'home', + label: strings.home, + }, + { + to: 'regionsLayout', + label: region?.region_name ?? '-', + urlParams: { + regionId: country?.region, + }, + }, + { + to: 'countriesLayout', + label: country?.name ?? '-', + urlParams: { + countryId, + }, + }, + ]), [ + strings.home, + region?.region_name, + country?.region, + countryId, + country?.name, + ]); + if (isDefined(numericCountryId) && isRegion) { const regionId = countryIdToRegionIdMap[numericCountryId]; @@ -143,29 +176,7 @@ export function Component() { title={pageTitle} heading={country?.name ?? '--'} breadCrumbs={( - - - {strings.home} - - - {region?.region_name} - - - {country?.name} - - + )} description={ isDefined(countryResponse) diff --git a/app/src/views/CountryNsOverviewActivities/Filters/index.tsx b/app/src/views/CountryNsOverviewActivities/Filters/index.tsx index b0807d8333..32481d407a 100644 --- a/app/src/views/CountryNsOverviewActivities/Filters/index.tsx +++ b/app/src/views/CountryNsOverviewActivities/Filters/index.tsx @@ -67,6 +67,7 @@ function Filters(props: Props) { labelSelector={countryNameSelector} onChange={onChange} disabled={disabled} + withSelectAll /> ); diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitValidateButton/styles.module.css b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitValidateButton/styles.module.css index 32f3f51f1f..7106d70bc0 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitValidateButton/styles.module.css +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitValidateButton/styles.module.css @@ -5,6 +5,7 @@ } .local-unit-validated-button { + align-items: center; border: none; background-color: var(--go-ui-color-gray-40); diff --git a/app/src/views/Emergency/index.tsx b/app/src/views/Emergency/index.tsx index df7e0d3dd5..d64973f7f1 100644 --- a/app/src/views/Emergency/index.tsx +++ b/app/src/views/Emergency/index.tsx @@ -13,7 +13,6 @@ import { TargetedPopulationIcon, } from '@ifrc-go/icons'; import { - Breadcrumbs, Button, KeyFigure, NavigationTabList, @@ -26,7 +25,8 @@ import { listToMap, } from '@togglecorp/fujs'; -import Link from '#components/Link'; +import GoBreadcrumbs from '#components/GoBreadcrumbs'; +import Link, { type InternalLinkProps } from '#components/Link'; import NavigationTab from '#components/NavigationTab'; import Page from '#components/Page'; import { adminUrl } from '#config'; @@ -45,6 +45,12 @@ import { import i18n from './i18n.json'; import styles from './styles.module.css'; +type BreadcrumbsDataType = { + to: InternalLinkProps['to']; + label: string; + urlParams?: Record; +}; + /* function getRouteIdFromName(text: string) { return text.toLowerCase().trim().split(' ').join('-'); @@ -209,6 +215,29 @@ export function Component() { ].filter((tabInfo) => tabInfo.snippets.length > 0); }, [emergencyResponse, emergencySnippetResponse]); + const breadCrumbsData: BreadcrumbsDataType[] = useMemo(() => ([ + { + to: 'home', + label: strings.home, + }, + { + to: 'emergencies', + label: strings.emergencies, + }, + { + to: 'emergencyDetails', + label: emergencyResponse?.name ?? '-', + urlParams: { + emergencyId, + }, + }, + ]), [ + strings.home, + strings.emergencies, + emergencyId, + emergencyResponse?.name, + ]); + const outletContext = useMemo( () => ({ emergencyResponse, @@ -225,20 +254,9 @@ export function Component() { className={styles.emergency} title={strings.emergencyPageTitle} breadCrumbs={( - - - {strings.home} - - - {strings.emergencies} - - - {emergencyResponse?.name} - - + )} actions={isAuthenticated && ( <> diff --git a/app/src/views/FieldReportDetails/index.tsx b/app/src/views/FieldReportDetails/index.tsx index 7badd83e6b..6f4a7e1eca 100644 --- a/app/src/views/FieldReportDetails/index.tsx +++ b/app/src/views/FieldReportDetails/index.tsx @@ -5,7 +5,6 @@ import { import { useParams } from 'react-router-dom'; import { CheckboxCircleLineIcon } from '@ifrc-go/icons'; import { - Breadcrumbs, Container, DateOutput, HtmlOutput, @@ -28,7 +27,8 @@ import { } from '@togglecorp/fujs'; import DetailsFailedToLoadMessage from '#components/domain/DetailsFailedToLoadMessage'; -import Link from '#components/Link'; +import GoBreadcrumbs from '#components/GoBreadcrumbs'; +import Link, { type InternalLinkProps } from '#components/Link'; import Page from '#components/Page'; import useGlobalEnums from '#hooks/domain/useGlobalEnums'; import { @@ -48,6 +48,12 @@ import EventNumericDetails from './EventNumericDetails'; import i18n from './i18n.json'; import styles from './styles.module.css'; +type BreadcrumbsDataType = { + to: InternalLinkProps['to']; + label: string; + urlParams?: Record; +}; + // eslint-disable-next-line import/prefer-default-export export function Component() { const strings = useTranslation(i18n); @@ -209,8 +215,30 @@ export function Component() { }, ].filter((plannedResponse) => isDefined(plannedResponse.value) && plannedResponse.value !== 0); + const breadCrumbsData: BreadcrumbsDataType[] = useMemo(() => ([ + { + to: 'home', + label: strings.home, + }, + { + to: 'emergencies', + label: strings.emergencies, + }, + { + to: 'fieldReportDetails', + label: fieldReportResponse?.summary ?? '-', + urlParams: { + fieldReportId, + }, + }, + ]), [ + strings.home, + strings.emergencies, + fieldReportResponse?.summary, + fieldReportId, + ]); + // FIXME: Translation Warning Banner should be shown - // FIXME: Breadcrumbs const shouldHideDetails = fetchingFieldReport || isDefined(fieldReportResponseError); @@ -221,24 +249,7 @@ export function Component() { className={styles.fieldReportDetails} heading={shouldHideDetails ? strings.fieldReportDefaultHeading : summary} breadCrumbs={( - - - {strings.home} - - - {strings.emergencies} - - - {fieldReportResponse?.summary} - - + )} actions={( ; +}; + // eslint-disable-next-line import/prefer-default-export export function Component() { const strings = useTranslation(i18n); @@ -104,6 +110,29 @@ export function Component() { [flashUpdateResponse], ); + const breadCrumbsData: BreadcrumbsDataType[] = useMemo(() => ([ + { + to: 'home', + label: strings.home, + }, + { + to: 'emergencies', + label: strings.emergencies, + }, + { + to: 'flashUpdateFormDetails', + label: flashUpdateResponse?.title ?? '-', + urlParams: { + flashUpdateId, + }, + }, + ]), [ + strings.home, + strings.emergencies, + flashUpdateId, + flashUpdateResponse?.title, + ]); + const shouldHideDetails = fetchingFlashUpdate || isDefined(flashUpdateResponseError); @@ -115,24 +144,7 @@ export function Component() { className={styles.flashUpdateDetails} heading={flashUpdateResponse?.title ?? strings.flashUpdateDetailsHeading} breadCrumbs={( - - - {strings.home} - - - {strings.emergencies} - - - {flashUpdateResponse?.title} - - + )} actions={flashUpdateResponse && ( <> diff --git a/packages/go-ui-storybook/src/stories/Alert.stories.tsx b/packages/go-ui-storybook/src/stories/Alert.stories.tsx index c5de4a7fa3..47dd09f3b8 100644 --- a/packages/go-ui-storybook/src/stories/Alert.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Alert.stories.tsx @@ -30,9 +30,9 @@ type Story = StoryObj; export const Info: Story = { args: { name: 'info', - title: 'Information', type: 'info', - description: 'This alert provides informative details to the user.', + nonDismissable: true, + title: 'This alert provides informative details to the user.', }, parameters: { design: { @@ -46,9 +46,9 @@ export const Info: Story = { export const Success: Story = { args: { name: 'success', - title: 'Success', type: 'success', - description: 'This alert indicates a successful operation or task.', + nonDismissable: true, + title: 'This alert indicates a successful operation or task.', }, parameters: { design: { @@ -62,18 +62,18 @@ export const Success: Story = { export const Warning : Story = { args: { name: 'warning', - title: 'Warning', type: 'warning', - description: 'This alert warns the user about potential issues or risks.', + nonDismissable: true, + title: 'This alert warns the user about potential issues or risks.', }, }; export const Danger : Story = { args: { name: 'danger', - title: 'Danger', type: 'danger', - description: 'This alert indicates a dangerous or potentially harmful situation.', + nonDismissable: true, + title: 'This alert indicates a dangerous or potentially harmful situation.', }, parameters: { design: { @@ -87,9 +87,7 @@ export const Danger : Story = { export const NonDismissable: Story = { args: { name: 'danger', - title: 'Danger', - type: 'danger', - description: 'This alert indicates a dangerous or potentially harmful situation.', + title: 'This alert indicates a dangerous or potentially harmful situation.', nonDismissable: true, }, }; diff --git a/packages/go-ui-storybook/src/stories/Breadcrumbs.stories.tsx b/packages/go-ui-storybook/src/stories/Breadcrumbs.stories.tsx index 9e611ebf0f..1e14cd5757 100644 --- a/packages/go-ui-storybook/src/stories/Breadcrumbs.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Breadcrumbs.stories.tsx @@ -5,6 +5,21 @@ import type { import Breadcrumbs from './Breadcrumbs'; +interface Datum { + id: number; + label: string; +} + +const data: Datum[] = [ + { id: 1, label: 'Home' }, + { id: 2, label: 'Africa' }, + { id: 3, label: 'Benin' }, +]; + +const keySelector = (datum: Datum) => datum.id; +const labelSelector = (datum: Datum) => datum.label; +const rendererParams = () => ({}); + type Story = StoryObj; const meta: Meta = { @@ -25,7 +40,15 @@ export default meta; export const Default: Story = { args: { - children: ['Home', 'Africa', 'Angola'], + data, + keySelector, + labelSelector, + rendererParams, + renderer: ({ children }) => ( +
+ {children} +
+ ), }, }; diff --git a/packages/go-ui-storybook/src/stories/Breadcrumbs.tsx b/packages/go-ui-storybook/src/stories/Breadcrumbs.tsx index 12d76cf2eb..86d6a6b5ec 100644 --- a/packages/go-ui-storybook/src/stories/Breadcrumbs.tsx +++ b/packages/go-ui-storybook/src/stories/Breadcrumbs.tsx @@ -3,7 +3,9 @@ import { BreadcrumbsProps, } from '@ifrc-go/ui'; -function Breadcrumbs(props: BreadcrumbsProps) { +function Breadcrumbs( + props: BreadcrumbsProps, +) { return ( // eslint-disable-line react/jsx-props-no-spreading ); diff --git a/packages/go-ui-storybook/src/stories/Button.stories.ts b/packages/go-ui-storybook/src/stories/Button.stories.ts index 6cfac7a631..887ec6dc67 100644 --- a/packages/go-ui-storybook/src/stories/Button.stories.ts +++ b/packages/go-ui-storybook/src/stories/Button.stories.ts @@ -21,7 +21,6 @@ const meta = { onClick: fn(), }, tags: ['autodocs'], - argTypes: {}, } satisfies Meta; export default meta; @@ -42,6 +41,22 @@ export const Primary: Story = { }, }; +export const PrimaryButtonWithIcon: Story = { + args: { + name: 'button', + variant: 'primary', + children: 'Primary Button', + // icons: , + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/k9SOqgh5jk9PxzuBKdMKsA/IFRC-GO---UI-Library?type=design&node-id=11261-189962&mode=design&t=H77btqXhNDop8ZRl-4', + allowFullscreen: false, + }, + }, +}; + export const Secondary: Story = { args: { name: 'button', @@ -57,6 +72,22 @@ export const Secondary: Story = { }, }; +export const SecondaryButtonWithIcon: Story = { + args: { + name: 'button', + variant: 'primary', + children: 'Primary Button', + // icons: , + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/k9SOqgh5jk9PxzuBKdMKsA/IFRC-GO---UI-Library?type=design&node-id=11261-189950&mode=design&t=H77btqXhNDop8ZRl-4', + allowFullscreen: false, + }, + }, +}; + export const Tertiary: Story = { args: { name: 'button', @@ -72,6 +103,21 @@ export const Tertiary: Story = { }, }; +export const TertiaryButtonWithIcon: Story = { + args: { + name: 'button', + variant: 'tertiary', + children: 'tertiary Button', + // icons: , + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/k9SOqgh5jk9PxzuBKdMKsA/IFRC-GO---UI-Library?type=design&node-id=11261-189955&mode=design&t=H77btqXhNDop8ZRl-4', + allowFullscreen: false, + }, + }, +}; export const TertiaryOnDark: Story = { args: { name: 'button', @@ -92,3 +138,21 @@ export const DropdownItem: Story = { children: 'Dropdown Item', }, }; + +export const GreyTertiaryButtonWithIcon: Story = { + args: { + name: 'button', + variant: 'grey-tertiary', + children: 'Grey-Tertiary Button', + // icons: + }, +}; + +export const ProcessButtonWithIcon: Story = { + args: { + name: 'button', + variant: 'secondary', + children: 'Process Button', + // icons: + }, +}; diff --git a/packages/go-ui-storybook/src/stories/Footer.stories.tsx b/packages/go-ui-storybook/src/stories/Footer.stories.tsx index f2fa01d320..68ab87849c 100644 --- a/packages/go-ui-storybook/src/stories/Footer.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Footer.stories.tsx @@ -1,6 +1,5 @@ import { SocialFacebookIcon, - SocialInstagramIcon, SocialTwitterIcon, SocialYoutubeIcon, } from '@ifrc-go/icons'; @@ -39,9 +38,6 @@ function FooterActions() { - - - @@ -55,16 +51,33 @@ function FooterIcons() { @@ -72,10 +85,16 @@ function FooterIcons() { } export const Default: Story = { + args: { + className: 'footer', + icons: , + }, +}; + +export const WithChildren: Story = { args: { className: 'footer', children: 'IFRC GO Component Library', icons: , - actions: , }, }; diff --git a/packages/go-ui-storybook/src/stories/Header.stories.tsx b/packages/go-ui-storybook/src/stories/Header.stories.tsx index 13e76b17cb..cb52cb167c 100644 --- a/packages/go-ui-storybook/src/stories/Header.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Header.stories.tsx @@ -31,7 +31,7 @@ export const Default: Story = { args: { heading: 'Overview of the International Federation of Red Cross and Red Crescent Societies (IFRC)', headingDescription: 'The International Federation of Red Cross and Red Crescent Societies (IFRC) is the world’s largest humanitarian network.', - headingLevel: 2, + headingLevel: 1, headingContainerClassName: 'header-children', }, }; diff --git a/packages/go-ui-storybook/src/stories/IconButton.stories.tsx b/packages/go-ui-storybook/src/stories/IconButton.stories.tsx index 3fc891131b..8fa895d0b0 100644 --- a/packages/go-ui-storybook/src/stories/IconButton.stories.tsx +++ b/packages/go-ui-storybook/src/stories/IconButton.stories.tsx @@ -36,6 +36,23 @@ export const Default: Story = { variant: 'primary', }, }; + +export const Secondary: Story = { + args: { + title: 'Add Item', + children: , + variant: 'secondary', + }, +}; + +export const Tertiary: Story = { + args: { + title: 'Add Item', + children: , + variant: 'tertiary', + }, +}; + export const Disabled: Story = { args: { title: 'Download', diff --git a/packages/go-ui-storybook/src/stories/InfoPopup.stories.tsx b/packages/go-ui-storybook/src/stories/InfoPopup.stories.tsx index 939b01d3ee..75cc2fddfc 100644 --- a/packages/go-ui-storybook/src/stories/InfoPopup.stories.tsx +++ b/packages/go-ui-storybook/src/stories/InfoPopup.stories.tsx @@ -6,7 +6,8 @@ import type { import InfoPopup from './InfoPopup'; -type Story = StoryObj; +type InfoPoppupSpecificProps = InfoPopupProps; +type Story = StoryObj; const meta: Meta = { title: 'Components/InfoPopup', diff --git a/packages/go-ui-storybook/src/stories/InfoPopup.tsx b/packages/go-ui-storybook/src/stories/InfoPopup.tsx index 26adde83e4..d1d88a03ef 100644 --- a/packages/go-ui-storybook/src/stories/InfoPopup.tsx +++ b/packages/go-ui-storybook/src/stories/InfoPopup.tsx @@ -3,7 +3,7 @@ import { InfoPopupProps, } from '@ifrc-go/ui'; -function InfoPopup(props: InfoPopupProps) { +function InfoPopup (props: InfoPopupProps) { return ( // eslint-disable-line react/jsx-props-no-spreading ); diff --git a/packages/go-ui-storybook/src/stories/LegendItem.stories.tsx b/packages/go-ui-storybook/src/stories/LegendItem.stories.tsx index 6842b3adf1..4c8ac6887b 100644 --- a/packages/go-ui-storybook/src/stories/LegendItem.stories.tsx +++ b/packages/go-ui-storybook/src/stories/LegendItem.stories.tsx @@ -1,3 +1,4 @@ +import { AlertInformationLineIcon } from '@ifrc-go/icons'; import { LegendItemProps } from '@ifrc-go/ui'; import type { Meta, @@ -36,3 +37,10 @@ export const WithDifferentColor: Story = { color: 'orange', }, }; +export const WithIcon: Story = { + args: { + label: 'Emergency appeal', + color: 'green', + icons: , + }, +}; diff --git a/packages/go-ui-storybook/src/stories/List.stories.tsx b/packages/go-ui-storybook/src/stories/List.stories.tsx index 03582e705e..9bd2fc54d0 100644 --- a/packages/go-ui-storybook/src/stories/List.stories.tsx +++ b/packages/go-ui-storybook/src/stories/List.stories.tsx @@ -89,6 +89,15 @@ export const Filtered: Story = { renderer: Option, rendererParams, filtered: true, - filteredEmptyMessage: 'Data is not available for selected filters', + }, +}; + +export const Empty: Story = { + args: { + className: 'list-story', + keySelector, + renderer: Option, + rendererParams, + errorMessage: 'Data is not available for selected filters', }, }; diff --git a/packages/go-ui-storybook/src/stories/RawFileInput.stories.tsx b/packages/go-ui-storybook/src/stories/RawFileInput.stories.tsx index a2e12ef01c..b47714ee58 100644 --- a/packages/go-ui-storybook/src/stories/RawFileInput.stories.tsx +++ b/packages/go-ui-storybook/src/stories/RawFileInput.stories.tsx @@ -1,3 +1,4 @@ +import { UploadTwoLineIcon } from '@ifrc-go/icons'; import { RawFileInputProps } from '@ifrc-go/ui'; import type { Meta, @@ -50,6 +51,7 @@ export const WithAccept: Story = { name: 'RawFileInput', accept: 'image/png,image/jpeg', children: 'Upload Image', + variant: 'secondary', multiple: false, onChange: fn(), }, @@ -59,6 +61,7 @@ export const Disabled: Story = { args: { name: 'RawFileInput', children: 'Export', + variant: 'secondary', multiple: false, onChange: fn(), disabled: true, @@ -69,8 +72,19 @@ export const ReadOnly: Story = { args: { name: 'RawFileInput', children: 'Export', + variant: 'secondary', readOnly: true, multiple: false, onChange: fn(), }, }; +export const WithIcon: Story = { + args: { + name: 'RawFileInput', + children: 'Export', + variant: 'secondary', + icons: , + multiple: false, + onChange: fn(), + }, +}; diff --git a/packages/go-ui-storybook/src/stories/Table.stories.tsx b/packages/go-ui-storybook/src/stories/Table.stories.tsx index 5b27d21f86..fb4a4ef3c5 100644 --- a/packages/go-ui-storybook/src/stories/Table.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Table.stories.tsx @@ -191,7 +191,12 @@ const columns = [ 'link', 'Link', ({ link, title }) => ( - {title} + + {title} + ), (_, item) => ({ link: item.link, title: item.name }), ), diff --git a/packages/go-ui-storybook/src/stories/Tooltip.stories.tsx b/packages/go-ui-storybook/src/stories/Tooltip.stories.tsx index 304f59ac01..910c931679 100644 --- a/packages/go-ui-storybook/src/stories/Tooltip.stories.tsx +++ b/packages/go-ui-storybook/src/stories/Tooltip.stories.tsx @@ -43,3 +43,11 @@ export const Default: Story = { preferredWidth: 20, }, }; + +export const WithoutTitle: Story = { + render: Template, + args: { + description: 'Click here to access our help documentation and support resources.', + preferredWidth: 20, + }, +}; diff --git a/packages/go-ui-storybook/src/stories/index.css b/packages/go-ui-storybook/src/stories/index.css index 6a876bbf65..fe7d01539f 100644 --- a/packages/go-ui-storybook/src/stories/index.css +++ b/packages/go-ui-storybook/src/stories/index.css @@ -102,11 +102,26 @@ .footer-items { display: flex; gap: var(--go-ui-spacing-md); + color: var(--go-ui-color-white); + font-weight: var(--go-ui-font-weight-normal); + font-size: var(--go-ui-font-size-md); +} + +.footer-items-link { + color: var(--go-ui-color-white); + font-size: var(--go-ui-font-size-md); + font-weight: var(--go-ui-font-weight-medium); + text-decoration: none; + + :hover { + color: var(--go-ui-color-primary-red); + } } .footer-link { font-size: var(--go-ui-font-size-2xl); color: var(--go-ui-color-primary-black); + color: var(--go-ui-color-white); :hover { color: var(--go-ui-color-primary-red); @@ -116,16 +131,18 @@ .footer-text { color: var(--go-ui-color-primary-black); font-size: var(--go-ui-font-size-xl); - - :hover { - color: var(--go-ui-color-primary-red); - } + text-decoration: none; + font-weight: var(--go-ui-font-weight-medium); + padding:var(--go-ui-spacing-md); } .footer { display: flex; justify-content: center; + background-color: var(--go-ui-color-primary-gray); + color: var(--go-ui-color-white); align-items: center; + padding: var(--go-ui-spacing-xl); } .image-container { @@ -170,3 +187,11 @@ padding-top: var(--go-ui-spacing-md); padding-bottom: var(--go-ui-spacing-md); } +/*NOTE:*/ +.table-link{ + color: var(--go-ui-color-text); +} +.table-link:hover { + color: var(--go-ui-color-primary-red); +} + diff --git a/packages/ui/src/components/Alert/index.tsx b/packages/ui/src/components/Alert/index.tsx index 50fa120ace..e97f13dfb9 100644 --- a/packages/ui/src/components/Alert/index.tsx +++ b/packages/ui/src/components/Alert/index.tsx @@ -1,8 +1,8 @@ import { useCallback } from 'react'; import { + AlertLineIcon, CheckboxCircleLineIcon, CloseLineIcon, - ErrorWarningLineIcon, InformationLineIcon, QuestionLineIcon, } from '@ifrc-go/icons'; @@ -40,7 +40,7 @@ const icon: { [key in AlertType]: React.ReactNode; } = { success: , - danger: , + danger: , info: , warning: , }; diff --git a/packages/ui/src/components/Alert/styles.module.css b/packages/ui/src/components/Alert/styles.module.css index 19d3921549..a6e539b212 100644 --- a/packages/ui/src/components/Alert/styles.module.css +++ b/packages/ui/src/components/Alert/styles.module.css @@ -1,7 +1,7 @@ .alert { display: flex; border-radius: var(--go-ui-border-radius-md); - box-shadow: var(--go-ui-box-shadow-2xl); + box-shadow: var(--go-ui-box-shadow-alert); width: calc(14rem + 16vw); color: var(--go-ui-color-white); @@ -14,7 +14,7 @@ } &.info { - background-color: var(--go-ui-color-gray-80); + background-color: var(--go-ui-color-gray-50); } &.success { diff --git a/packages/ui/src/components/BarChart/styles.module.css b/packages/ui/src/components/BarChart/styles.module.css index f2359de31c..1998da8cd8 100644 --- a/packages/ui/src/components/BarChart/styles.module.css +++ b/packages/ui/src/components/BarChart/styles.module.css @@ -20,13 +20,13 @@ } .bar-track { - border-radius: 0.3rem; + border-radius: 0 var(--go-ui-border-radius-md) var(--go-ui-border-radius-md) 0; background-color: var(--go-ui-color-gray-30); width: 60%; height: 0.6rem; .bar { - border-radius: 0.3rem; + border-radius: 0 var(--go-ui-border-radius-md) var(--go-ui-border-radius-md) 0; background-color: var(--go-ui-color-primary-red); height: 100%; } diff --git a/packages/ui/src/components/Breadcrumbs/index.tsx b/packages/ui/src/components/Breadcrumbs/index.tsx index cbba6d48bd..7da9d7b966 100644 --- a/packages/ui/src/components/Breadcrumbs/index.tsx +++ b/packages/ui/src/components/Breadcrumbs/index.tsx @@ -1,59 +1,82 @@ -import { Children } from 'react'; -import { ChevronRightLineIcon } from '@ifrc-go/icons'; -import { _cs } from '@togglecorp/fujs'; +import { Fragment } from 'react/jsx-runtime'; +import { ArrowDropRightLineIcon } from '@ifrc-go/icons'; +import { + _cs, + isNotDefined, +} from '@togglecorp/fujs'; import styles from './styles.module.css'; -export interface BreadcrumbsProps { +interface RendererProps { + children: React.ReactNode; +} + +export interface BreadcrumbsProps< + KEY, + DATUM, + RENDERER_PROPS extends RendererProps +> { className?: string; - itemClassName?: string; separator?: React.ReactNode; - children: React.ReactNode; + data: DATUM[] | undefined | null; + keySelector(datum: DATUM, index: number): KEY; + labelSelector(datum: DATUM, index: number): React.ReactNode; + rendererParams(key: KEY, datum: DATUM, index: number, data: DATUM[]): Omit; + renderer: React.ComponentType; } -function Breadcrumbs(props: BreadcrumbsProps) { +function Breadcrumbs( + props: BreadcrumbsProps, +) { const { + data, className, - children, - separator = , - itemClassName, + separator = , + renderer: Renderer, + rendererParams, + keySelector, + labelSelector, } = props; - const items = Children.toArray(children).reduce( - (acc, child, index, array) => { - const item = ( -
- {child} -
- ); - - acc.push(item); - - if (index !== array.length - 1) { - acc.push( - - {separator} - , - ); - } - - return acc; - }, - [], - ); + if (isNotDefined(data)) { + return null; + } return ( ); } diff --git a/packages/ui/src/components/Breadcrumbs/styles.module.css b/packages/ui/src/components/Breadcrumbs/styles.module.css index d4cd002ba9..f32022966f 100644 --- a/packages/ui/src/components/Breadcrumbs/styles.module.css +++ b/packages/ui/src/components/Breadcrumbs/styles.module.css @@ -6,19 +6,25 @@ .item { display: flex; - &:not(:last-child) { - color: var(--go-ui-color-gray-70); - } + &:not(:last-child) { + .label { + color: var(--go-ui-color-gray-70); + font-weight: var(--go-ui-font-weight-light); + } + } - &:last-child { - color: var(--go-ui-color-black); - } + &:last-child { + .label { + color: var(--go-ui-color-black); + } + } } .separator { display: flex; justify-content: center; - color: var(--go-ui-color-gray-70); - font-size: var(--go-ui-font-size-xl); + color: var(--go-ui-color-gray-90); + font-size: var(--go-ui-font-size-3xl); + font-weight: var(--go-ui-font-weight-medium); } } diff --git a/packages/ui/src/components/Button/index.tsx b/packages/ui/src/components/Button/index.tsx index a4344f8c4e..44f3f1808a 100644 --- a/packages/ui/src/components/Button/index.tsx +++ b/packages/ui/src/components/Button/index.tsx @@ -14,7 +14,7 @@ import useBasicLayout from '#hooks/useBasicLayout'; import styles from './styles.module.css'; // NOTE: Adding a 'tertiary-on-dark' to use 'tertiary' button on darker backgrounds -export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'tertiary-on-dark' | 'dropdown-item'; +export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'tertiary-on-dark' | 'dropdown-item' | 'grey-tertiary'; const buttonVariantToClassNameMap: Record = { primary: styles.primary, @@ -22,6 +22,7 @@ const buttonVariantToClassNameMap: Record = { tertiary: styles.tertiary, 'tertiary-on-dark': styles.tertiaryOnDark, 'dropdown-item': styles.dropdownItem, + 'grey-tertiary': styles.greyTertiary, }; const spacingTypeToClassNameMap: Record = { diff --git a/packages/ui/src/components/Button/styles.module.css b/packages/ui/src/components/Button/styles.module.css index 4677d4eac0..67486f1e12 100644 --- a/packages/ui/src/components/Button/styles.module.css +++ b/packages/ui/src/components/Button/styles.module.css @@ -20,7 +20,7 @@ max-width: 100%; overflow: hidden; text-transform: var(--text-transform); - line-height: var(--go-ui-line-height-xs); + line-height: var(--go-ui-line-height-md); color: var(--color-text); font-family: inherit; font-size: var(--font-size); @@ -43,6 +43,7 @@ &.primary, &.secondary { + min-width: calc(var(--base-spacing) * 6.5); .children { text-align: center; } @@ -64,7 +65,7 @@ } &.default-spacing { - --padding: var(--go-ui-spacing-3xs) var(--go-ui-spacing-md); + --padding: var(--go-ui-spacing-3xs) var(--go-ui-spacing-lg); } &.comfortable-spacing { @@ -86,7 +87,9 @@ --color-text: var(--go-ui-color-white); &.disabled { - filter: saturate(50%); + border-color: var(--go-ui-color-gray-40); + background-color: var(--go-ui-color-gray-40); + color: var(--go-ui-color-black); } &:not(.disabled) { @@ -153,6 +156,12 @@ } } + &.grey-tertiary { + --border-radius: unset; + --padding: var(--go-ui-spacing-sm) var(--go-ui-spacing-lg); + background-color: var(--go-ui-color-background); + } + &.disabled { opacity: var(--go-ui-opacity-disabled-element); --cursor: not-allowed; diff --git a/packages/ui/src/components/Checkbox/Checkmark/index.tsx b/packages/ui/src/components/Checkbox/Checkmark/index.tsx index 884925fbcb..bdb8955b83 100644 --- a/packages/ui/src/components/Checkbox/Checkmark/index.tsx +++ b/packages/ui/src/components/Checkbox/Checkmark/index.tsx @@ -1,7 +1,7 @@ import { CheckboxBlankLineIcon, + CheckboxFillIcon, CheckboxIndeterminateLineIcon, - CheckboxLineIcon, } from '@ifrc-go/icons'; export interface CheckmarkProps { @@ -25,7 +25,7 @@ function Checkmark(props: CheckmarkProps) { /> )} {value && !indeterminate && ( - )} diff --git a/packages/ui/src/components/Checkbox/styles.module.css b/packages/ui/src/components/Checkbox/styles.module.css index 2b84edf416..f8ad9db940 100644 --- a/packages/ui/src/components/Checkbox/styles.module.css +++ b/packages/ui/src/components/Checkbox/styles.module.css @@ -22,6 +22,10 @@ outline: var(--go-ui-width-separator-thin) dashed var(--go-ui-color-gray-40); } } + + .checkmark { + color: var(--go-ui-color-gray-40); + } } .content { diff --git a/packages/ui/src/components/ConfirmButton/index.tsx b/packages/ui/src/components/ConfirmButton/index.tsx index 1028da4510..4e0934fd8a 100644 --- a/packages/ui/src/components/ConfirmButton/index.tsx +++ b/packages/ui/src/components/ConfirmButton/index.tsx @@ -2,6 +2,7 @@ import { useCallback, useState, } from 'react'; +import { _cs } from '@togglecorp/fujs'; import Button, { Props as ButtonProps } from '#components/Button'; import Modal from '#components/Modal'; @@ -14,6 +15,8 @@ export interface Props extends ButtonProps { confirmHeading?: React.ReactNode; onClick?: (name: NAME, e: React.MouseEvent) => void; onConfirm: (name: NAME) => void; + disabled?: boolean; + className?: string; } function ConfirmButton(props: Props) { @@ -25,6 +28,8 @@ function ConfirmButton(props: Props) { name, onConfirm, onClick, + disabled, + className, ...buttonProps } = props; @@ -53,8 +58,10 @@ function ConfirmButton(props: Props) { diff --git a/packages/ui/src/components/DefaultMessage/index.tsx b/packages/ui/src/components/DefaultMessage/index.tsx index 76b07e6835..2334b72fd6 100644 --- a/packages/ui/src/components/DefaultMessage/index.tsx +++ b/packages/ui/src/components/DefaultMessage/index.tsx @@ -83,9 +83,10 @@ function DefaultMessage(props: Props) { className={_cs( styles.defaultMessage, pending && overlayPending && styles.overlay, + empty && styles.emptyMessage, className, )} - icon={} + icon={(!empty || filtered || errored) && } compact={compact} title={messageTitle} pending={pending} diff --git a/packages/ui/src/components/DefaultMessage/styles.module.css b/packages/ui/src/components/DefaultMessage/styles.module.css index 4030c4e012..6535563c82 100644 --- a/packages/ui/src/components/DefaultMessage/styles.module.css +++ b/packages/ui/src/components/DefaultMessage/styles.module.css @@ -6,4 +6,8 @@ width: 100%; height: 100%; } + &.empty-message { + padding-top: var(--go-ui-spacing-xxl); + height:12.5rem; + } } diff --git a/packages/ui/src/components/DropdownMenu/index.tsx b/packages/ui/src/components/DropdownMenu/index.tsx index fd6d835827..f68b9d9481 100644 --- a/packages/ui/src/components/DropdownMenu/index.tsx +++ b/packages/ui/src/components/DropdownMenu/index.tsx @@ -138,6 +138,7 @@ function DropdownMenu(props: Props) { className={_cs(styles.dropdownContent, popupClassName)} parentRef={buttonRef} preferredWidth={preferredPopupWidth} + overrideVerticalOrientation > {children} diff --git a/packages/ui/src/components/DropdownMenu/styles.module.css b/packages/ui/src/components/DropdownMenu/styles.module.css index 7da9428fb0..0d13bb15f6 100644 --- a/packages/ui/src/components/DropdownMenu/styles.module.css +++ b/packages/ui/src/components/DropdownMenu/styles.module.css @@ -1,5 +1,6 @@ .dropdown-menu { align-items: center; + height: var(--go-ui-height-compact-status-icon); .icons, .content, diff --git a/packages/ui/src/components/Heading/styles.module.css b/packages/ui/src/components/Heading/styles.module.css index bf32ace918..03dd678999 100644 --- a/packages/ui/src/components/Heading/styles.module.css +++ b/packages/ui/src/components/Heading/styles.module.css @@ -4,7 +4,6 @@ margin: 0; line-height: var(--line-height); font-size: var(--font-size); - font-weight: var(--go-ui-font-weight-semibold); &.level-one { --font-size: var(--go-ui-font-size-4xl); diff --git a/packages/ui/src/components/InfoPopup/i18n.json b/packages/ui/src/components/InfoPopup/i18n.json new file mode 100644 index 0000000000..a82d630224 --- /dev/null +++ b/packages/ui/src/components/InfoPopup/i18n.json @@ -0,0 +1,7 @@ + +{ + "namespace": "common", + "strings": { + "closeButtonLabel": "Close" + } +} diff --git a/packages/ui/src/components/InfoPopup/index.tsx b/packages/ui/src/components/InfoPopup/index.tsx index b0f1e69f0e..b8e2e23b1f 100644 --- a/packages/ui/src/components/InfoPopup/index.tsx +++ b/packages/ui/src/components/InfoPopup/index.tsx @@ -1,9 +1,16 @@ -import { InformationLineIcon } from '@ifrc-go/icons'; +import { useCallback } from 'react'; +import { + CloseLineIcon, + InformationLineIcon, +} from '@ifrc-go/icons'; import { _cs } from '@togglecorp/fujs'; +import Button from '#components/Button'; import Container from '#components/Container'; import DropdownMenu from '#components/DropdownMenu'; +import useTranslation from '#hooks/useTranslation'; +import i18n from './i18n.json'; import styles from './styles.module.css'; export interface Props { @@ -15,6 +22,7 @@ export interface Props { descriptionClassName?: string; popupClassName?: string; className?: string; + onCloseButtonClick?: () => void; } function InfoPopup(props: Props) { @@ -25,10 +33,21 @@ function InfoPopup(props: Props) { title, description, withoutIcon, + onCloseButtonClick, popupClassName, descriptionClassName, } = props; + const strings = useTranslation(i18n); + const handleCloseButtonClick = useCallback( + () => { + if (onCloseButtonClick) { + onCloseButtonClick(); + } + }, + [onCloseButtonClick], + ); + return ( + + + )} > {description} diff --git a/packages/ui/src/components/InfoPopup/styles.module.css b/packages/ui/src/components/InfoPopup/styles.module.css index e694ea3f1a..c32c3569dd 100644 --- a/packages/ui/src/components/InfoPopup/styles.module.css +++ b/packages/ui/src/components/InfoPopup/styles.module.css @@ -23,5 +23,10 @@ white-space: pre-wrap; gap: var(--go-ui-spacing-xs); font-size: var(--go-ui-font-size-sm); + + } + .close-icon { + font-size: var(--go-ui-font-size-2xl); } + } diff --git a/packages/ui/src/components/InputContainer/styles.module.css b/packages/ui/src/components/InputContainer/styles.module.css index 8d2f9a2fe3..392dcf4a8c 100644 --- a/packages/ui/src/components/InputContainer/styles.module.css +++ b/packages/ui/src/components/InputContainer/styles.module.css @@ -10,7 +10,7 @@ padding: 0 var(--go-ui-spacing-sm); .input { - padding: var(--go-ui-spacing-xs) 0; + height: var(--go-ui-height-compact-status-icon); } } diff --git a/packages/ui/src/components/InputLabel/styles.module.css b/packages/ui/src/components/InputLabel/styles.module.css index 21a5c9444c..7cd2d707e4 100644 --- a/packages/ui/src/components/InputLabel/styles.module.css +++ b/packages/ui/src/components/InputLabel/styles.module.css @@ -1,8 +1,8 @@ .input-label { display: flex; - padding: 0 var(--go-ui-spacing-2xs); color: var(--go-ui-color-gray-70); gap: var(--go-ui-spacing-xs); + padding-left: 12px; &.disabled { color: var(--go-ui-color-gray-40); diff --git a/packages/ui/src/components/InputSection/index.tsx b/packages/ui/src/components/InputSection/index.tsx index 6b264a4de0..0dcb91ffba 100644 --- a/packages/ui/src/components/InputSection/index.tsx +++ b/packages/ui/src/components/InputSection/index.tsx @@ -56,7 +56,12 @@ function InputSection(props: Props) { headerClassName={styles.header} headingClassName={styles.heading} headingContainerClassName={styles.headingContainer} - actions={tooltip && } + actions={tooltip + && ( + + )} childrenContainerClassName={styles.description} headingLevel={withCompactTitleSection ? 5 : 4} spacing="cozy" diff --git a/packages/ui/src/components/LegendItem/index.tsx b/packages/ui/src/components/LegendItem/index.tsx index e08aef60a1..5aff3a7daa 100644 --- a/packages/ui/src/components/LegendItem/index.tsx +++ b/packages/ui/src/components/LegendItem/index.tsx @@ -6,6 +6,7 @@ export interface Props { className?: string; colorClassName?: string; label?: React.ReactNode; + icons?:React.ReactNode iconSrc?: string; color?: string; iconClassName?: string; @@ -18,6 +19,7 @@ function LegendItem(props: Props) { iconClassName, color, label, + icons, iconSrc, } = props; @@ -42,6 +44,11 @@ function LegendItem(props: Props) { className={_cs(styles.color, colorClassName)} /> )} + {icons && ( +
+ {icons} +
+ )}
{label}
diff --git a/packages/ui/src/components/Modal/styles.module.css b/packages/ui/src/components/Modal/styles.module.css index c1acfacb16..fdf9d29428 100644 --- a/packages/ui/src/components/Modal/styles.module.css +++ b/packages/ui/src/components/Modal/styles.module.css @@ -44,7 +44,6 @@ border-radius: var(--go-ui-border-radius-lg); box-shadow: var(--go-ui-box-shadow-2xl); background-color: var(--go-ui-color-white); - width: 100%; min-width: var(--go-ui-width-min-modal); height: 100%; min-height: var(--go-ui-height-min-modal); diff --git a/packages/ui/src/components/NavigationTabList/styles.module.css b/packages/ui/src/components/NavigationTabList/styles.module.css index 8d62123a7a..309a767e32 100644 --- a/packages/ui/src/components/NavigationTabList/styles.module.css +++ b/packages/ui/src/components/NavigationTabList/styles.module.css @@ -23,8 +23,8 @@ .content { display: flex; - border-radius: var(--go-ui-border-radius-full); - background-color: var(--go-ui-color-element-background); + border-bottom: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); + padding: 0 0 var(--go-ui-spacing-3xs) 0; } .start-dummy-content, diff --git a/packages/ui/src/components/PieChart/styles.module.css b/packages/ui/src/components/PieChart/styles.module.css index 22e7a91b16..151da0e503 100644 --- a/packages/ui/src/components/PieChart/styles.module.css +++ b/packages/ui/src/components/PieChart/styles.module.css @@ -4,13 +4,19 @@ flex-wrap: wrap; gap: var(--go-ui-spacing-md); + .path { + stroke: var(--go-ui-color-white); + } + .legend { display: flex; flex-direction: column; flex-grow: 1; justify-content: center; + gap: var(--go-ui-width-separator-lg); .legend-item { + text-transform: uppercase; font-size: var(--go-ui-font-size-xs); } } diff --git a/packages/ui/src/components/Popup/index.tsx b/packages/ui/src/components/Popup/index.tsx index 8874749507..d9bea0038b 100644 --- a/packages/ui/src/components/Popup/index.tsx +++ b/packages/ui/src/components/Popup/index.tsx @@ -12,6 +12,7 @@ export interface Props { parentRef: React.RefObject; children?: React.ReactNode; preferredWidth?: number; + overrideVerticalOrientation?: boolean; } function Popup(props: Props) { @@ -22,6 +23,7 @@ function Popup(props: Props) { className, pointerClassName, preferredWidth, + overrideVerticalOrientation = false, } = props; const { @@ -29,7 +31,11 @@ function Popup(props: Props) { pointer, width, orientation, - } = useFloatPlacement(parentRef, preferredWidth); + } = useFloatPlacement( + parentRef, + preferredWidth, + overrideVerticalOrientation ? 'top' : undefined, + ); return ( @@ -41,7 +47,6 @@ function Popup(props: Props) { }} className={_cs( styles.popup, - orientation.vertical === 'bottom' && styles.topOrientation, className, )} > diff --git a/packages/ui/src/components/Popup/styles.module.css b/packages/ui/src/components/Popup/styles.module.css index 5730905097..34ca9e6492 100644 --- a/packages/ui/src/components/Popup/styles.module.css +++ b/packages/ui/src/components/Popup/styles.module.css @@ -1,15 +1,10 @@ .popup { position: fixed; - border-radius: var(--go-ui-spacing-xs); - box-shadow: var(--go-ui-box-shadow-2xl); + border-radius: 4px; + box-shadow: var(--go-ui-box-shadow-popup); background-color: var(--go-ui-color-white); max-height: 40vh; overflow: auto; - - &.top-orientation { - /* FIXME: add variable */ - box-shadow: 0 -8pt 20pt -5pt rgb(0 0 0 / 0.5); - } } .pointer { diff --git a/packages/ui/src/components/ProgressBar/styles.module.css b/packages/ui/src/components/ProgressBar/styles.module.css index 08d33735de..aa35289762 100644 --- a/packages/ui/src/components/ProgressBar/styles.module.css +++ b/packages/ui/src/components/ProgressBar/styles.module.css @@ -11,13 +11,13 @@ .total { display: flex; flex-shrink: 0; - border-radius: var(--go-ui-border-radius-md); + border-radius: 0 var(--go-ui-border-radius-md) var(--go-ui-border-radius-md) 0; background-color: var(--go-ui-color-separator); height: 0.5rem; .progress { transition: var(--go-ui-duration-transition-medium) width ease-in-out; - border-radius: var(--go-ui-border-radius-md); + border-radius: 0 var(--go-ui-border-radius-md) var(--go-ui-border-radius-md) 0; background-color: currentColor; } } diff --git a/packages/ui/src/components/RadioInput/Radio/styles.module.css b/packages/ui/src/components/RadioInput/Radio/styles.module.css index 8d5b3770fd..d35a629922 100644 --- a/packages/ui/src/components/RadioInput/Radio/styles.module.css +++ b/packages/ui/src/components/RadioInput/Radio/styles.module.css @@ -4,6 +4,7 @@ .icon { transition: var(--go-ui-duration-transition-medium) color ease-in-out; + color: var(--go-ui-color-gray-40); font-size: var(--go-ui-height-icon-multiplier); } @@ -11,6 +12,7 @@ flex-direction: column; gap: 0; line-height: var(--go-ui-line-height-sm); + color: var(--go-ui-color-black); } .description { diff --git a/packages/ui/src/components/SearchMultiSelectInput/Option/index.tsx b/packages/ui/src/components/SearchMultiSelectInput/Option/index.tsx index 82e85b3e8b..c649b5d7e0 100644 --- a/packages/ui/src/components/SearchMultiSelectInput/Option/index.tsx +++ b/packages/ui/src/components/SearchMultiSelectInput/Option/index.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; import { CheckboxBlankLineIcon, - CheckboxLineIcon, + CheckboxFillIcon, } from '@ifrc-go/icons'; interface OptionProps { @@ -21,7 +21,7 @@ function Option(props: OptionProps) { return ( <>
- { isActive ? : } + { isActive ? : }
{ children } diff --git a/packages/ui/src/components/SearchMultiSelectInput/index.tsx b/packages/ui/src/components/SearchMultiSelectInput/index.tsx index 5deae0e707..55b57bc879 100644 --- a/packages/ui/src/components/SearchMultiSelectInput/index.tsx +++ b/packages/ui/src/components/SearchMultiSelectInput/index.tsx @@ -53,6 +53,7 @@ export type SearchMultiSelectInputProps< ) => OPTION[]; onSearchValueChange?: (value: string | undefined) => void; onShowDropdownChange?: (value: boolean) => void; + onSelectAllButtonClick?: () => void; selectedOnTop: boolean; }, OMISSION> @@ -108,6 +109,7 @@ function SearchMultiSelectInput< onShowDropdownChange, hideOptionFilter, selectedOnTop, + onSelectAllButtonClick, ...otherProps } = props; @@ -296,6 +298,7 @@ function SearchMultiSelectInput< name={name} options={realOptions} optionsPending={optionsPending} + selectedOptions={selectedOptions} optionsFiltered={isTruthyString(searchInputValue) && searchInputValue.length > 0} optionsErrored={optionsErrored} optionKeySelector={keySelector} @@ -315,6 +318,7 @@ function SearchMultiSelectInput< onFocusedKeyChange={setFocusedKey} persistentOptionPopup nonClearable={false} + onSelectAllButtonClick={onSelectAllButtonClick} hasValue={isDefined(value) && value.length > 0} /> ); diff --git a/packages/ui/src/components/SegmentInput/styles.module.css b/packages/ui/src/components/SegmentInput/styles.module.css index f106817bdb..904cb73f33 100644 --- a/packages/ui/src/components/SegmentInput/styles.module.css +++ b/packages/ui/src/components/SegmentInput/styles.module.css @@ -3,8 +3,6 @@ .segment-list { flex-wrap: nowrap; - border: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); - border-radius: var(--go-ui-border-radius-full); background-color: var(--go-ui-color-background); padding: 0; width: fit-content; diff --git a/packages/ui/src/components/SelectInputContainer/i18n.json b/packages/ui/src/components/SelectInputContainer/i18n.json index b44529b171..a769bfe366 100644 --- a/packages/ui/src/components/SelectInputContainer/i18n.json +++ b/packages/ui/src/components/SelectInputContainer/i18n.json @@ -4,7 +4,7 @@ "infoMessageAnd":"and", "infoMessageMore":"more", "buttonTitleSelect":"Select all", - "buttonTitleClear":"Clear", + "buttonClearAll":"Clear All", "buttonTitleClose":"Close", "buttonTitleOpen":"Open", "selectInputPendingMessage":"Fetching options...", diff --git a/packages/ui/src/components/SelectInputContainer/index.tsx b/packages/ui/src/components/SelectInputContainer/index.tsx index 9ff424d106..6c93060eab 100644 --- a/packages/ui/src/components/SelectInputContainer/index.tsx +++ b/packages/ui/src/components/SelectInputContainer/index.tsx @@ -3,15 +3,10 @@ import React, { useRef, } from 'react'; import { - ArrowDownSmallFillIcon, - ArrowUpSmallFillIcon, - CheckDoubleFillIcon, - CloseLineIcon, + ChevronDownLineIcon, + ChevronUpLineIcon, } from '@ifrc-go/icons'; -import { - _cs, - isTruthyString, -} from '@togglecorp/fujs'; +import { _cs } from '@togglecorp/fujs'; import Button, { Props as ButtonProps } from '#components/Button'; import InputContainer, { Props as InputContainerProps } from '#components/InputContainer'; @@ -67,6 +62,7 @@ export type SelectInputContainerProps< autoFocus?: boolean; hasValue: boolean; nonClearable?: boolean; + selectedOptions?: Record[OPTION_KEY][]; onClearButtonClick: () => void; onSelectAllButtonClick?: () => void; onEnterWithoutOption?: () => void; @@ -135,6 +131,7 @@ function SelectInputContainer< variant, errorOnTooltip, dropdownHidden, + selectedOptions, } = props; const options = optionsFromProps ?? (emptyList as OPTION[]); @@ -196,7 +193,6 @@ function SelectInputContainer< }, [readOnly, handleShowDropdown], ); - const handlePopupBlur = useCallback( (clickedInside: boolean, clickedInParent: boolean) => { const isClickedWithin = clickedInside || clickedInParent; @@ -216,7 +212,7 @@ function SelectInputContainer< handleHideDropdown(); } }, - [onOptionClick, handleHideDropdown, persistentOptionPopup, name], + [onOptionClick, name, persistentOptionPopup, handleHideDropdown], ); const optionListRendererParams = useCallback( @@ -268,6 +264,15 @@ function SelectInputContainer< const dropdownShownActual = dropdownShown && !dropdownHidden; + const availableOptions = options.filter( + (option) => !selectedOptions?.some( + (selectedOption) => optionKeySelector( + selectedOption, + 0, + ) === optionKeySelector(option, 0), + ), + ); + return ( <> {actions} - {!readOnly && onSelectAllButtonClick && ( - - )} - {!readOnly && !nonClearable && hasValue && ( - - )} {!readOnly && ( )} @@ -342,7 +325,7 @@ function SelectInputContainer< onClick={handleSearchInputClick} onFocus={() => onFocusedChange(true)} onBlur={() => onFocusedChange(false)} - placeholder={isTruthyString(valueDisplay) ? valueDisplay : placeholder} + placeholder={placeholder} autoComplete="off" onKeyDown={handleKeyDown} autoFocus={autoFocus} @@ -355,9 +338,61 @@ function SelectInputContainer< parentRef={inputSectionRef} className={_cs(optionsPopupClassName, styles.popup)} > +
+ {!readOnly + && !nonClearable + && hasValue + && !disabled + && ( + + )} + {!readOnly && !disabled && onSelectAllButtonClick && ( + + )} + {selectedOptions && selectedOptions.length > 0 && ( +
+ + > + className={styles.list} + data={selectedOptions} + keySelector={optionKeySelector} + renderer={GenericOption} + rendererParams={optionListRendererParams} + compact + pending={false} + errored={false} + filtered={false} + /> +
+ )} + {!readOnly && onSelectAllButtonClick && ( +
+ )} +
> className={styles.list} - data={options} + data={availableOptions} keySelector={optionKeySelector} renderer={GenericOption} rendererParams={optionListRendererParams} diff --git a/packages/ui/src/components/SelectInputContainer/styles.module.css b/packages/ui/src/components/SelectInputContainer/styles.module.css index 56fd3dc2b5..3cab02c810 100644 --- a/packages/ui/src/components/SelectInputContainer/styles.module.css +++ b/packages/ui/src/components/SelectInputContainer/styles.module.css @@ -1,5 +1,19 @@ .popup { - padding: var(--go-ui-spacing-sm) 0; + padding: var(--go-ui-spacing-sm); + + .dropdown-container-buttons { + display: flex; + flex-direction: column; + gap: var(--go-ui-spacing-xs); + + .clear-button { + align-self: end; + } + + .clear-all-separator { + border: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); + } + } .list { display: flex; diff --git a/packages/ui/src/components/Switch/SwitchIcon/styles.module.css b/packages/ui/src/components/Switch/SwitchIcon/styles.module.css index 2b93ba2ad3..5fe030ce28 100644 --- a/packages/ui/src/components/Switch/SwitchIcon/styles.module.css +++ b/packages/ui/src/components/Switch/SwitchIcon/styles.module.css @@ -10,7 +10,7 @@ align-items: center; transition: var(--go-ui-duration-transition-medium) background-color ease-in-out; border: var(--border-width) solid var(--border-color); - border-radius: .5em; + border-radius: 1em; background-color: var(--background-color); padding: var(--gap); width: calc(1em + var(--knob-diameter)); diff --git a/packages/ui/src/components/Table/TableBodyContent/styles.module.css b/packages/ui/src/components/Table/TableBodyContent/styles.module.css index 6191ae0c92..2503bf6fec 100644 --- a/packages/ui/src/components/Table/TableBodyContent/styles.module.css +++ b/packages/ui/src/components/Table/TableBodyContent/styles.module.css @@ -1,6 +1,6 @@ .row { .cell { - padding: var(--go-ui-spacing-sm); + padding: var(--go-ui-spacing-ssm); overflow: hidden; word-break: break-word; } diff --git a/packages/ui/src/components/Table/styles.module.css b/packages/ui/src/components/Table/styles.module.css index e6c7a88f77..dd890e1b51 100644 --- a/packages/ui/src/components/Table/styles.module.css +++ b/packages/ui/src/components/Table/styles.module.css @@ -21,6 +21,7 @@ font-size: inherit; .header-row { + background:var(--go-ui-color-primary-gray-10); .header-element { position: sticky; top: 0; diff --git a/packages/ui/src/components/Tabs/Tab/styles.module.css b/packages/ui/src/components/Tabs/Tab/styles.module.css index b776eb2055..f7aa94e2ed 100644 --- a/packages/ui/src/components/Tabs/Tab/styles.module.css +++ b/packages/ui/src/components/Tabs/Tab/styles.module.css @@ -88,11 +88,13 @@ align-self: stretch; .step-circle { + position: absolute; + left: 45%; flex-shrink: 0; transition: var(--go-ui-duration-transition-slow) border-color ease-in-out; border: var(--border-width) solid transparent; border-radius: 50%; - background-color: var(--go-ui-color-background); + background-color: transparent; padding: var(--go-ui-spacing-2xs); .inner-circle { @@ -116,7 +118,7 @@ .progress-bar-start { flex-grow: 1; background-color: var(--go-ui-color-separator); - height: var(--go-ui-width-separator-thin);; + height: var(--go-ui-width-separator-small); } } @@ -181,12 +183,20 @@ } &.secondary { - border-radius: var(--go-ui-border-radius-full); - padding: var(--go-ui-spacing-md) var(--go-ui-spacing-xl); - + border-right: var(--border-width) solid var(--border-color); + border-top-color: transparent; + + /* stylelint-disable-next-line no-descending-specificity */ + .children-wrapper { + padding: var(--go-ui-spacing-md) var(--go-ui-spacing-lg); + } + &.active { - background-color: var(--go-ui-color-primary-red); - color: var(--go-ui-color-white); + color: var(--go-ui-color-primary-red); + } + + &:last-child { + border-color: transparent; } } diff --git a/packages/ui/src/components/Tabs/TabList/styles.module.css b/packages/ui/src/components/Tabs/TabList/styles.module.css index c52164aafa..561c98f429 100644 --- a/packages/ui/src/components/Tabs/TabList/styles.module.css +++ b/packages/ui/src/components/Tabs/TabList/styles.module.css @@ -16,17 +16,10 @@ border-bottom: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); } } - &.secondary { display: flex; overflow-x: auto; - .content { - display: flex; - border-radius: var(--go-ui-border-radius-full); - background-color: var(--go-ui-color-element-background); - } - .start-dummy-content, .end-dummy-content { flex-grow: 1; diff --git a/packages/ui/src/components/Tooltip/index.tsx b/packages/ui/src/components/Tooltip/index.tsx index f7912e356b..44efecdeba 100644 --- a/packages/ui/src/components/Tooltip/index.tsx +++ b/packages/ui/src/components/Tooltip/index.tsx @@ -89,6 +89,7 @@ function Tooltip(props: Props) { {description} diff --git a/packages/ui/src/hooks/useBasicLayout/styles.module.css b/packages/ui/src/hooks/useBasicLayout/styles.module.css index 7e3ced3e6b..d55802070b 100644 --- a/packages/ui/src/hooks/useBasicLayout/styles.module.css +++ b/packages/ui/src/hooks/useBasicLayout/styles.module.css @@ -1,6 +1,5 @@ .basic-layout { display: flex; - align-items: flex-start; &.with-wrap { flex-wrap: wrap; diff --git a/packages/ui/src/hooks/useFloatPlacement.ts b/packages/ui/src/hooks/useFloatPlacement.ts index e3d9db01cf..c2fcd1ca90 100644 --- a/packages/ui/src/hooks/useFloatPlacement.ts +++ b/packages/ui/src/hooks/useFloatPlacement.ts @@ -54,6 +54,7 @@ const defaultPlacement: Placement = { function useFloatPlacement( parentRef: React.RefObject, preferredWidth?: number, + perferredVerticalOrientation?: 'top' | 'bottom', ) { const [placements, setPlacements] = useState<{ content: Placement, @@ -86,6 +87,10 @@ function useFloatPlacement( const maxWidth = window.innerWidth - 2 * horizontalPadding; const orientation = getPreferredOrientation(parentBCR); + + if (perferredVerticalOrientation) { + orientation.vertical = perferredVerticalOrientation; + } const parentCenterX = parentX + parentWidth / 2; const width = bound( diff --git a/packages/ui/src/index.css b/packages/ui/src/index.css index 5e703962dd..ea54598c92 100644 --- a/packages/ui/src/index.css +++ b/packages/ui/src/index.css @@ -61,9 +61,11 @@ --go-ui-spacing-2xs: calc(var(--base-spacing) * 0.25); --go-ui-spacing-xs: calc(var(--base-spacing) * 0.4); --go-ui-spacing-sm: calc(var(--base-spacing) * 0.625); + --go-ui-spacing-ssm: calc(var(--base-spacing) * 0.750); --go-ui-spacing-md: calc(var(--base-spacing) * 1); --go-ui-spacing-lg: calc(var(--base-spacing) * 1.5); --go-ui-spacing-xl: calc(var(--base-spacing) * 2.25); + --go-ui-spacing-xxl: calc(var(--base-spacing) * 2.5); --go-ui-spacing-2xl: calc(var(--base-spacing) * 3.5); --go-ui-spacing-3xl: calc(var(--base-spacing) * 4.75); --go-ui-spacing-4xl: calc(var(--base-spacing) * 6); @@ -108,11 +110,14 @@ --go-ui-box-shadow-xs: 0 1pt 2pt rgb(0 0 0 / 0.2); --go-ui-box-shadow-sm: 0 1pt 4pt rgb(0 0 0 / 0.2); + --go-ui-box-shadow-ssm: 0 0 10px rgb(0 0 0 / 0.08); --go-ui-box-shadow-md: 0 1pt 5pt -2pt rgb(0 0 0 / 0.375); --go-ui-box-shadow-lg: 0 2pt 8pt -4pt rgb(0 0 0 / 0.5); --go-ui-box-shadow-xl: 0 3pt 16pt -6pt rgb(0 0 0 / 0.5); --go-ui-box-shadow-2xl: 0 4pt 16pt -6pt rgb(0 0 0 / 1); --go-ui-box-shadow-inner: inset 0 2pt 4pt 0 rgb(0 0 0 / 0.375); + --go-ui-box-shadow-alert: 0 3px 8px 8px rgb(0 0 0 / 0.2); + --go-ui-box-shadow-popup: 0 0 10px rgb(0 0 0 / 0.08); --go-ui-box-shadow-none: 0 0 #0000; --go-ui-duration-transition-fast: .1s; @@ -199,16 +204,16 @@ --go-ui-width-min-modal: 18rem; --go-ui-height-min-modal: 11rem; - --go-ui-width-modal-sm: 32rem; + --go-ui-width-modal-sm: 20rem; --go-ui-height-modal-sm: 100%; - --go-ui-width-modal-md: 42rem; + --go-ui-width-modal-md: 26.25rem; --go-ui-height-modal-md: 100%; - --go-ui-width-modal-lg: 64rem; + --go-ui-width-modal-lg: 40rem; --go-ui-height-modal-lg: 100%; - --go-ui-width-modal-xl: 92rem; + --go-ui-width-modal-xl: 57.5rem; --go-ui-height-modal-xl: 100%; --go-ui-saturate-0: 0;