From 1a7b7a380163175589007d83cd8fc3395c08105c Mon Sep 17 00:00:00 2001 From: mcoker Date: Thu, 28 Sep 2023 10:51:18 -0500 Subject: [PATCH 01/11] fix(RTL): added right-to-left page demo --- packages/react-core/src/demos/RTL/RTL.md | 44 ++ .../RTL/examples/TableColumnManagement.jsx | 484 ++++++++++++++++++ .../demos/RTL/examples/translations.en.json | 22 + .../demos/RTL/examples/translations.he.json | 22 + 4 files changed, 572 insertions(+) create mode 100644 packages/react-core/src/demos/RTL/RTL.md create mode 100644 packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx create mode 100644 packages/react-core/src/demos/RTL/examples/translations.en.json create mode 100644 packages/react-core/src/demos/RTL/examples/translations.he.json diff --git a/packages/react-core/src/demos/RTL/RTL.md b/packages/react-core/src/demos/RTL/RTL.md new file mode 100644 index 00000000000..d400af3117c --- /dev/null +++ b/packages/react-core/src/demos/RTL/RTL.md @@ -0,0 +1,44 @@ +--- +id: RTL +section: patterns +--- +import { + Checkbox, + Label, + PageSection, + ToolbarExpandIconWrapper, + ToolbarContent, + Toolbar, + ToolbarItem, + SearchInput, + Masthead, + MastheadToggle, + MastheadMain, + MastheadContent, + SkipToContent, + Breadcrumb, + BreadcrumbItem, + Page, + PageSectionVariants, + TextContent, + Text, + Divider +} from '@patternfly/react-core'; + +import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; +import { rows, columns } from '@patternfly/react-table/src/docs/demos/table-demos/sampleData'; +import translationsEn from "./examples/translations.en.json"; +import translationsHe from "./examples/translations.he.json"; +import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; +import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; +import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon'; +import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; + +## Demos + +This demonstrates how the UI adapts to the writing mode of the page. + +### Table column management + +```js file="./examples/TableColumnManagement.jsx" isFullscreen +``` diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx new file mode 100644 index 00000000000..7732e899832 --- /dev/null +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -0,0 +1,484 @@ +export const ColumnManagementAction = () => { + const defaultColumns = columns; + const defaultRows = rows; + const [filters, setFilters] = React.useState([]); + const [filteredColumns, setFilteredColumns] = React.useState([]); + const [filteredRows, setFilteredRows] = React.useState([]); + const [managedColumns, setManagedColumns] = React.useState(defaultColumns); + const [managedRows, setManagedRows] = React.useState(defaultRows); + const [isModalOpen, setIsModalOpen] = React.useState(false); + const [checkedState, setCheckedState] = React.useState(Array(columns.length).fill(true)); + const [page, setPage] = React.useState(1); + const [perPage, setPerPage] = React.useState(10); + const [paginatedRows, setPaginatedRows] = React.useState(rows); + + //const [isRTL, setIsRTL] = React.useState(false); + const [t, setT] = React.useState(translationsEn); + //const isRTL = React.useContext(RtlContext); + + const switchRTL = () => { + const html = document.querySelector('html'); + const curRTL = (html.dir !== 'rtl') ? false : true; + setT(curRTL ? translationsEn : translationsHe); + html.dir = curRTL ? 'ltr' : 'rtl'; + }; + + const matchCheckboxNameToColumn = (name) => { + switch (name) { + case 'check1': + return 'Servers'; + case 'check2': + return 'Threads'; + case 'check3': + return 'Applications'; + case 'check4': + return 'Workspaces'; + case 'check5': + return 'Status'; + case 'check6': + return 'Location'; + case 'check7': + return 'Last Modified'; + case 'check8': + return 'URL'; + } + }; + const matchSelectedColumnNameToAttr = (name) => { + switch (name) { + case 'Servers': + return 'name'; + case 'Threads': + return 'threads'; + case 'Applications': + return 'applications'; + case 'Workspaces': + return 'workspaces'; + case 'Status': + return 'status'; + case 'Location': + return 'location'; + case 'Last Modified': + return 'lastModified'; + case 'URL': + return 'url'; + } + }; + + // Pagination logic + const handleSetPage = (_evt, newPage) => { + setPage(newPage); + }; + + const handlePerPageSelect = (_evt, newPerPage) => { + setPerPage(newPerPage); + }; + + const renderPagination = (variant, isCompact) => ( + + ); + + React.useEffect(() => { + setPaginatedRows(managedRows.slice((page - 1) * perPage, page * perPage - 1)); + }, [managedRows, page, perPage]); + + // Removes attribute from each node object in Data.jsx + const removePropFromObject = (object, keys) => + keys.reduce((obj, prop) => { + const { [prop]: _, ...keep } = obj; + return keep; + }, object); + + // Filters columns out of table that are not selected in the column management modal + const filterData = (checked, name) => { + const selectedColumn = matchSelectedColumnNameToAttr(name); + + const filteredRows = []; + if (checked) { + const updatedFilters = filters.filter((item) => item !== selectedColumn); + + // Only show the names of columns that were selected in the modal + const filteredColumns = defaultColumns.filter( + (column) => !updatedFilters.includes(matchSelectedColumnNameToAttr(column)) + ); + + // Remove the attributes (i.e. "columns") that were not selected + defaultRows.forEach((item) => filteredRows.push(removePropFromObject(item, updatedFilters))); + + setFilters(updatedFilters); + setFilteredColumns(filteredColumns); + setFilteredRows(filteredRows); + } else { + let updatedFilters = filters; + updatedFilters.push(selectedColumn); + + // Only show the names of columns that were selected in the modal + const filteredColumns = managedColumns.filter( + (column) => !filters.includes(matchSelectedColumnNameToAttr(column)) + ); + + // Remove the attributes (i.e. "columns") that were not selected + managedRows.forEach((item) => filteredRows.push(removePropFromObject(item, updatedFilters))); + + setFilters(updatedFilters); + setFilteredColumns(filteredColumns); + setFilteredRows(filteredRows); + } + }; + const unfilterAllData = () => { + setFilters([]); + setFilteredColumns(defaultColumns); + setFilteredRows(defaultRows); + }; + + const handleChange = (event, checked) => { + const target = event.target; + const value = target.type === 'checkbox' ? target.checked : target.value; + + // Remove any columns from the table that aren't checked + filterData(checked, matchCheckboxNameToColumn(target.name)); + const checkedIndex = columns.findIndex((element) => element === matchCheckboxNameToColumn(target.name)); + + const updatedCheckedState = [...checkedState]; + updatedCheckedState[checkedIndex] = value; + setCheckedState(updatedCheckedState); + }; + + const handleModalToggle = (_event) => { + setIsModalOpen(!isModalOpen); + }; + + const onSave = () => { + setManagedColumns(filteredColumns); + setManagedRows(filteredRows); + setPaginatedRows(filteredRows); + setIsModalOpen(!isModalOpen); + }; + + const selectAllColumns = () => { + unfilterAllData(); + setCheckedState(Array(columns.length).fill(true)); + }; + + const renderModal = () => { + return ( + + Selected categories will be displayed in the table. + + + } + onClose={handleModalToggle} + actions={[ + , + + ]} + > + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + ); + }; + + const renderLabel = (labelText) => { + switch (labelText) { + case 'Running': + return ; + case 'Stopped': + return ; + case 'Needs Maintenance': + return ; + case 'Down': + return ; + } + }; + + const toolbarItems = ( + + + + + + + + + + + + + + + + + {renderPagination(PaginationVariant.top)} + + + + ); + + const pageNav = ( + + ); + + const sidebar = ( + + {pageNav} + + ); + + return ( + + + + + {t.breadcrumbs.home} + {t.breadcrumbs.category} + + {t.breadcrumbs.subCategory} + + + + + + {t.title} + + {t.body} + + + + + + {toolbarItems} + + + + {managedColumns.map((column, columnIndex) => ( + + ))} + + + + {paginatedRows.map((row, rowIndex) => ( + + <> + {Object.entries(row).map(([key, value]) => + key === 'status' ? ( + + ) : key === 'url' ? ( + + ) : ( + + ) + )} + + + ))} + +
{column}
+ {renderLabel(value)} + + + {row.url} + + + {value} +
+ {renderPagination(PaginationVariant.bottom)} + {renderModal()} +
+
+
+
+ ); +}; diff --git a/packages/react-core/src/demos/RTL/examples/translations.en.json b/packages/react-core/src/demos/RTL/examples/translations.en.json new file mode 100644 index 00000000000..4ad6226e2f2 --- /dev/null +++ b/packages/react-core/src/demos/RTL/examples/translations.en.json @@ -0,0 +1,22 @@ +{ + "title": "Main title", + "body": "This is a full page demo.", + "breadcrumbs": { + "home": "Home", + "category": "Category", + "subCategory": "Sub category" + }, + "switchBtn": "Switch to Hebrew", + "table": { + "thead": { + "servers": "Servers", + "threads": "CPUs", + "applications": "Applications", + "workspaces": "Workspaces", + "status": "Status", + "location": "Location", + "modified": "Last modified", + "url": "URL" + } + } +} \ No newline at end of file diff --git a/packages/react-core/src/demos/RTL/examples/translations.he.json b/packages/react-core/src/demos/RTL/examples/translations.he.json new file mode 100644 index 00000000000..a4b2f32cee0 --- /dev/null +++ b/packages/react-core/src/demos/RTL/examples/translations.he.json @@ -0,0 +1,22 @@ +{ + "title": "כותרת ראשית", + "body": "זוהי הדגמה של עמוד שלם.", + "breadcrumbs": { + "home": "בית", + "category": "קטגוריה", + "subCategory": "קטגוריית משנה" + }, + "switchBtn": "Switch to English", + "table": { + "thead": { + "servers": "שרתים", + "threads": "מעבדים", + "applications": "יישומים", + "workspaces": "חללי עבודה", + "status": "סטָטוּס", + "location": "מקום", + "modified": "עודכן לאחרונה", + "url": "כתובת אתר" + } + } +} \ No newline at end of file From 55a1241db0f748ee2e01f1bdc91adc6bd89dfd23 Mon Sep 17 00:00:00 2001 From: mcoker Date: Thu, 28 Sep 2023 11:22:13 -0500 Subject: [PATCH 02/11] chore(rtl): demo lint --- packages/react-core/src/demos/RTL/RTL.md | 24 - .../RTL/examples/TableColumnManagement.jsx | 431 ++++++++++-------- 2 files changed, 246 insertions(+), 209 deletions(-) diff --git a/packages/react-core/src/demos/RTL/RTL.md b/packages/react-core/src/demos/RTL/RTL.md index d400af3117c..1fb059c2201 100644 --- a/packages/react-core/src/demos/RTL/RTL.md +++ b/packages/react-core/src/demos/RTL/RTL.md @@ -2,36 +2,12 @@ id: RTL section: patterns --- -import { - Checkbox, - Label, - PageSection, - ToolbarExpandIconWrapper, - ToolbarContent, - Toolbar, - ToolbarItem, - SearchInput, - Masthead, - MastheadToggle, - MastheadMain, - MastheadContent, - SkipToContent, - Breadcrumb, - BreadcrumbItem, - Page, - PageSectionVariants, - TextContent, - Text, - Divider -} from '@patternfly/react-core'; - import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; import { rows, columns } from '@patternfly/react-table/src/docs/demos/table-demos/sampleData'; import translationsEn from "./examples/translations.en.json"; import translationsHe from "./examples/translations.he.json"; import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; -import FilterIcon from '@patternfly/react-icons/dist/esm/icons/filter-icon'; import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; ## Demos diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx index 7732e899832..c3f270f7dfc 100644 --- a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -1,3 +1,47 @@ +import * as React from 'react'; + +import { + Breadcrumb, + BreadcrumbItem, + Button, + Card, + DataList, + DataListCell, + DataListCheck, + DataListItem, + DataListItemCells, + DataListItemRow, + Icon, + Label, + Modal, + Nav, + NavItem, + NavList, + Page, + PageBreadcrumb, + PageSection, + PageSidebar, + PageSidebarBody, + Pagination, + PaginationVariant, + Text, + TextContent, + TextVariants, + Toolbar, + ToolbarContent, + ToolbarGroup, + ToolbarItem +} from '@patternfly/react-core'; + +import { Table, TableText, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table'; +import { capitalize } from '../../../helpers'; +import { rows, columns } from '@patternfly/react-table/src/docs/demos/table-demos/sampleData'; +import translationsEn from './examples/translations.en.json'; +import translationsHe from './examples/translations.he.json'; +import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; +import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; +import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; + export const ColumnManagementAction = () => { const defaultColumns = columns; const defaultRows = rows; @@ -12,13 +56,13 @@ export const ColumnManagementAction = () => { const [perPage, setPerPage] = React.useState(10); const [paginatedRows, setPaginatedRows] = React.useState(rows); - //const [isRTL, setIsRTL] = React.useState(false); + // const [isRTL, setIsRTL] = React.useState(false); const [t, setT] = React.useState(translationsEn); - //const isRTL = React.useContext(RtlContext); + // const isRTL = React.useContext(RtlContext); const switchRTL = () => { const html = document.querySelector('html'); - const curRTL = (html.dir !== 'rtl') ? false : true; + const curRTL = html.dir !== 'rtl' ? false : true; setT(curRTL ? translationsEn : translationsHe); html.dir = curRTL ? 'ltr' : 'rtl'; }; @@ -119,7 +163,7 @@ export const ColumnManagementAction = () => { setFilteredColumns(filteredColumns); setFilteredRows(filteredRows); } else { - let updatedFilters = filters; + const updatedFilters = filters; updatedFilters.push(selectedColumn); // Only show the names of columns that were selected in the modal @@ -170,184 +214,193 @@ export const ColumnManagementAction = () => { setCheckedState(Array(columns.length).fill(true)); }; - const renderModal = () => { - return ( - - Selected categories will be displayed in the table. - - - } - onClose={handleModalToggle} - actions={[ - , - - ]} - > - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - ); - }; + + } + onClose={handleModalToggle} + actions={[ + , + + ]} + > + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + + + + + ]} + /> + + + + + ); const renderLabel = (labelText) => { switch (labelText) { case 'Running': - return ; + return ( + + ); case 'Stopped': return ; case 'Needs Maintenance': @@ -363,11 +416,19 @@ export const ColumnManagementAction = () => { - - - + @@ -416,7 +477,9 @@ export const ColumnManagementAction = () => { return ( - + {t.breadcrumbs.home} @@ -429,9 +492,7 @@ export const ColumnManagementAction = () => { {t.title} - - {t.body} - + {t.body} @@ -478,7 +539,7 @@ export const ColumnManagementAction = () => { {renderModal()} - + ); }; From 8f28671c4f41d0930100eaf9239a9a99d0556004 Mon Sep 17 00:00:00 2001 From: mcoker Date: Thu, 28 Sep 2023 18:26:31 -0500 Subject: [PATCH 03/11] chore(rtl): demo cleanup --- .../RTL/examples/TableColumnManagement.jsx | 364 ++---------------- 1 file changed, 33 insertions(+), 331 deletions(-) diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx index c3f270f7dfc..40fdf04013f 100644 --- a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -5,15 +5,8 @@ import { BreadcrumbItem, Button, Card, - DataList, - DataListCell, - DataListCheck, - DataListItem, - DataListItemCells, - DataListItemRow, Icon, Label, - Modal, Nav, NavItem, NavList, @@ -43,15 +36,6 @@ import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; export const ColumnManagementAction = () => { - const defaultColumns = columns; - const defaultRows = rows; - const [filters, setFilters] = React.useState([]); - const [filteredColumns, setFilteredColumns] = React.useState([]); - const [filteredRows, setFilteredRows] = React.useState([]); - const [managedColumns, setManagedColumns] = React.useState(defaultColumns); - const [managedRows, setManagedRows] = React.useState(defaultRows); - const [isModalOpen, setIsModalOpen] = React.useState(false); - const [checkedState, setCheckedState] = React.useState(Array(columns.length).fill(true)); const [page, setPage] = React.useState(1); const [perPage, setPerPage] = React.useState(10); const [paginatedRows, setPaginatedRows] = React.useState(rows); @@ -67,47 +51,6 @@ export const ColumnManagementAction = () => { html.dir = curRTL ? 'ltr' : 'rtl'; }; - const matchCheckboxNameToColumn = (name) => { - switch (name) { - case 'check1': - return 'Servers'; - case 'check2': - return 'Threads'; - case 'check3': - return 'Applications'; - case 'check4': - return 'Workspaces'; - case 'check5': - return 'Status'; - case 'check6': - return 'Location'; - case 'check7': - return 'Last Modified'; - case 'check8': - return 'URL'; - } - }; - const matchSelectedColumnNameToAttr = (name) => { - switch (name) { - case 'Servers': - return 'name'; - case 'Threads': - return 'threads'; - case 'Applications': - return 'applications'; - case 'Workspaces': - return 'workspaces'; - case 'Status': - return 'status'; - case 'Location': - return 'location'; - case 'Last Modified': - return 'lastModified'; - case 'URL': - return 'url'; - } - }; - // Pagination logic const handleSetPage = (_evt, newPage) => { setPage(newPage); @@ -132,259 +75,21 @@ export const ColumnManagementAction = () => { /> ); - React.useEffect(() => { - setPaginatedRows(managedRows.slice((page - 1) * perPage, page * perPage - 1)); - }, [managedRows, page, perPage]); - - // Removes attribute from each node object in Data.jsx - const removePropFromObject = (object, keys) => - keys.reduce((obj, prop) => { - const { [prop]: _, ...keep } = obj; - return keep; - }, object); - - // Filters columns out of table that are not selected in the column management modal - const filterData = (checked, name) => { - const selectedColumn = matchSelectedColumnNameToAttr(name); - - const filteredRows = []; - if (checked) { - const updatedFilters = filters.filter((item) => item !== selectedColumn); - - // Only show the names of columns that were selected in the modal - const filteredColumns = defaultColumns.filter( - (column) => !updatedFilters.includes(matchSelectedColumnNameToAttr(column)) - ); - - // Remove the attributes (i.e. "columns") that were not selected - defaultRows.forEach((item) => filteredRows.push(removePropFromObject(item, updatedFilters))); - - setFilters(updatedFilters); - setFilteredColumns(filteredColumns); - setFilteredRows(filteredRows); - } else { - const updatedFilters = filters; - updatedFilters.push(selectedColumn); - - // Only show the names of columns that were selected in the modal - const filteredColumns = managedColumns.filter( - (column) => !filters.includes(matchSelectedColumnNameToAttr(column)) - ); - - // Remove the attributes (i.e. "columns") that were not selected - managedRows.forEach((item) => filteredRows.push(removePropFromObject(item, updatedFilters))); - - setFilters(updatedFilters); - setFilteredColumns(filteredColumns); - setFilteredRows(filteredRows); + const breadcrumbItems = { + home: { + url: '#home' + }, + category: { + url: '#category' + }, + subCategory: { + url: 'sub-category' } }; - const unfilterAllData = () => { - setFilters([]); - setFilteredColumns(defaultColumns); - setFilteredRows(defaultRows); - }; - - const handleChange = (event, checked) => { - const target = event.target; - const value = target.type === 'checkbox' ? target.checked : target.value; - - // Remove any columns from the table that aren't checked - filterData(checked, matchCheckboxNameToColumn(target.name)); - const checkedIndex = columns.findIndex((element) => element === matchCheckboxNameToColumn(target.name)); - - const updatedCheckedState = [...checkedState]; - updatedCheckedState[checkedIndex] = value; - setCheckedState(updatedCheckedState); - }; - - const handleModalToggle = (_event) => { - setIsModalOpen(!isModalOpen); - }; - const onSave = () => { - setManagedColumns(filteredColumns); - setManagedRows(filteredRows); - setPaginatedRows(filteredRows); - setIsModalOpen(!isModalOpen); - }; - - const selectAllColumns = () => { - unfilterAllData(); - setCheckedState(Array(columns.length).fill(true)); - }; - - const renderModal = () => ( - - Selected categories will be displayed in the table. - - - } - onClose={handleModalToggle} - actions={[ - , - - ]} - > - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - - - - - ]} - /> - - - - - ); + React.useEffect(() => { + setPaginatedRows(rows.slice((page - 1) * perPage, page * perPage - 1)); + }, [rows, page, perPage]); const renderLabel = (labelText) => { switch (labelText) { @@ -429,9 +134,7 @@ export const ColumnManagementAction = () => { {t.switchBtn} - + @@ -477,16 +180,15 @@ export const ColumnManagementAction = () => { return ( - + - {t.breadcrumbs.home} - {t.breadcrumbs.category} - - {t.breadcrumbs.subCategory} - + {Object.keys(breadcrumbItems).map((key, idx, arr) => ( + + {t.breadcrumbs[key]} + {breadcrumbItems.length} + + ))} @@ -501,7 +203,7 @@ export const ColumnManagementAction = () => { - {managedColumns.map((column, columnIndex) => ( + {columns.map((column, columnIndex) => ( ))} @@ -510,33 +212,33 @@ export const ColumnManagementAction = () => { {paginatedRows.map((row, rowIndex) => ( <> - {Object.entries(row).map(([key, value]) => - key === 'status' ? ( - - ) : key === 'url' ? ( - ; + } else if (key === 'url') { + - ) : ( + ; + } else { - ) - )} + ; + } + })} ))}
{column}
+ {Object.entries(row).map(([key, value]) => { + if (key === 'status') { + {renderLabel(value)} - + {row.url} - {value} -
{renderPagination(PaginationVariant.bottom)} - {renderModal()}
From aa00511810c43bc5ef2a9089d602626753a33888 Mon Sep 17 00:00:00 2001 From: mcoker Date: Tue, 10 Oct 2023 11:24:55 -0500 Subject: [PATCH 04/11] chore(rtl): updates --- packages/react-core/src/demos/RTL/RTL.md | 3 +- .../RTL/examples/TableColumnManagement.jsx | 131 +++++++++++++----- .../demos/RTL/examples/translations.en.json | 38 ++++- .../demos/RTL/examples/translations.he.json | 38 ++++- 4 files changed, 161 insertions(+), 49 deletions(-) diff --git a/packages/react-core/src/demos/RTL/RTL.md b/packages/react-core/src/demos/RTL/RTL.md index 1fb059c2201..8f1cd9af564 100644 --- a/packages/react-core/src/demos/RTL/RTL.md +++ b/packages/react-core/src/demos/RTL/RTL.md @@ -3,10 +3,11 @@ id: RTL section: patterns --- import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; -import { rows, columns } from '@patternfly/react-table/src/docs/demos/table-demos/sampleData'; import translationsEn from "./examples/translations.en.json"; import translationsHe from "./examples/translations.he.json"; import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; +import ToolsIcon from '@patternfly/react-icons/dist/esm/icons/tools-icon'; +import ClockIcon from '@patternfly/react-icons/dist/esm/icons/clock-icon'; import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx index 40fdf04013f..445d2cc19b4 100644 --- a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -28,29 +28,61 @@ import { import { Table, TableText, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table'; import { capitalize } from '../../../helpers'; -import { rows, columns } from '@patternfly/react-table/src/docs/demos/table-demos/sampleData'; import translationsEn from './examples/translations.en.json'; import translationsHe from './examples/translations.he.json'; import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; +import ToolsIcon from '@patternfly/react-icons/dist/esm/icons/tools-icon'; +import ClockIcon from '@patternfly/react-icons/dist/esm/icons/clock-icon'; import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; export const ColumnManagementAction = () => { + const [t, setT] = React.useState(translationsEn); + + const columns = [ + t.table.columns.servers, + t.table.columns.status, + t.table.columns.location, + t.table.columns.modified, + t.table.columns.url, + ]; + const numRows = 25; + const getRandomInteger = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; + + const tableRows = () => { + const rows = []; + for (let i = 0; i < numRows; i++) { + const num = (i + 1); + rowObj = { + name: t.table.rows.node + num, + status: [t.table.rows.status.stopped, t.table.rows.status.running, t.table.rows.status.down, t.table.rows.status.needsMaintenance][getRandomInteger(0, 3)], + location: [t.table.rows.locations.raleigh, t.table.rows.locations.boston, t.table.rows.locations.atlanta, t.table.rows.locations.sanFrancisco][getRandomInteger(0, 3)], + lastModified: [t.table.rows.lastModified.oneHr, t.table.rows.lastModified.threeHrs, t.table.rows.lastModified.fiveHrs, t.table.rows.lastModified.sevenMins, t.table.rows.lastModified.fortyTwoMins, t.table.rows.lastModified.twoDays, t.table.rows.lastModified.oneMonth][getRandomInteger(0, 6)], + url: 'http://www.redhat.com/en/office-locations/node' + num + }; + rows.push(rowObj); + } + return rows; + } + + const defaultRows = tableRows(); + const [managedRows, setManagedRows] = React.useState(defaultRows); const [page, setPage] = React.useState(1); const [perPage, setPerPage] = React.useState(10); - const [paginatedRows, setPaginatedRows] = React.useState(rows); - - // const [isRTL, setIsRTL] = React.useState(false); - const [t, setT] = React.useState(translationsEn); - // const isRTL = React.useContext(RtlContext); + const [paginatedRows, setPaginatedRows] = React.useState(tableRows()); + const [isDirRTL, setDirRTL] = React.useState(false); const switchRTL = () => { - const html = document.querySelector('html'); - const curRTL = html.dir !== 'rtl' ? false : true; - setT(curRTL ? translationsEn : translationsHe); - html.dir = curRTL ? 'ltr' : 'rtl'; + setDirRTL((prevState) => !prevState); + setManagedRows(tableRows()); }; + React.useEffect(() => { + const html = document.querySelector('html'); + setT(isDirRTL ? translationsHe : translationsEn); + html.dir = isDirRTL ? 'rtl' : 'ltr'; + }, [isDirRTL]); + // Pagination logic const handleSetPage = (_evt, newPage) => { setPage(newPage); @@ -63,7 +95,7 @@ export const ColumnManagementAction = () => { const renderPagination = (variant, isCompact) => ( { } }; + const navItems = { + systemPanel: { + url: '#system-panel' + }, + policy: { + url: '#policy' + }, + authentication: { + url: '#authentication' + }, + networkServices: { + url: '#network-services' + }, + server: { + url: 'sub-category' + } + }; + React.useEffect(() => { - setPaginatedRows(rows.slice((page - 1) * perPage, page * perPage - 1)); - }, [rows, page, perPage]); + setPaginatedRows(managedRows.slice((page - 1) * perPage, page * perPage - 1)); + }, [managedRows, page, perPage]); const renderLabel = (labelText) => { switch (labelText) { @@ -103,15 +153,15 @@ export const ColumnManagementAction = () => { } > - {labelText} + {t.table.rows.status.running} ); case 'Stopped': - return ; - case 'Needs Maintenance': - return ; + return ; + case 'Needs maintenance': + return ; case 'Down': - return ; + return ; } }; @@ -154,19 +204,19 @@ export const ColumnManagementAction = () => { @@ -214,23 +264,28 @@ export const ColumnManagementAction = () => { <> {Object.entries(row).map(([key, value]) => { if (key === 'status') { - - {renderLabel(value)} - ; + return ( + + {renderLabel(value)} + + ) } else if (key === 'url') { - - - {row.url} - - ; + return ( + + + {row.url} + + + ) } else { - - {value} - ; + return ( + + {value} + + ) } })} diff --git a/packages/react-core/src/demos/RTL/examples/translations.en.json b/packages/react-core/src/demos/RTL/examples/translations.en.json index 4ad6226e2f2..b8fff6985b3 100644 --- a/packages/react-core/src/demos/RTL/examples/translations.en.json +++ b/packages/react-core/src/demos/RTL/examples/translations.en.json @@ -6,17 +6,45 @@ "category": "Category", "subCategory": "Sub category" }, + "nav": { + "systemPanel": "System panel", + "policy": "Policy", + "authentication": "Authentication", + "networkServices": "Network services", + "server": "Server" + }, "switchBtn": "Switch to Hebrew", "table": { - "thead": { + "columns": { "servers": "Servers", - "threads": "CPUs", - "applications": "Applications", - "workspaces": "Workspaces", "status": "Status", "location": "Location", "modified": "Last modified", "url": "URL" + }, + "rows": { + "node": "Node", + "status": { + "stopped": "Stopped", + "running": "Running", + "down": "Down", + "needsMaintenance": "Needs maintenance" + }, + "locations": { + "raleigh": "Raleigh", + "boston": "Boston", + "atlanta": "Atlanta", + "sanFrancisco": "San Francisco" + }, + "lastModified": { + "oneHr": "1 hour ago", + "threeHrs": "3 hours ago", + "fiveHrs": "5 hours ago", + "sevenMins": "7 minutes ago", + "fortyTwoMins": "42 minutes ago", + "twoDays": "2 days ago", + "oneMonth": "1 month ago" + } } } -} \ No newline at end of file +} diff --git a/packages/react-core/src/demos/RTL/examples/translations.he.json b/packages/react-core/src/demos/RTL/examples/translations.he.json index a4b2f32cee0..7e3511f50cd 100644 --- a/packages/react-core/src/demos/RTL/examples/translations.he.json +++ b/packages/react-core/src/demos/RTL/examples/translations.he.json @@ -6,17 +6,45 @@ "category": "קטגוריה", "subCategory": "קטגוריית משנה" }, + "nav": { + "systemPanel": "פאנל מערכת", + "policy": "מְדִינִיוּת", + "authentication": "אימות", + "networkServices": "שירותי רשת", + "server": "שרת" + }, "switchBtn": "Switch to English", "table": { - "thead": { + "columns": { "servers": "שרתים", - "threads": "מעבדים", - "applications": "יישומים", - "workspaces": "חללי עבודה", "status": "סטָטוּס", "location": "מקום", "modified": "עודכן לאחרונה", "url": "כתובת אתר" + }, + "rows": { + "node": "נקודת קצה", + "status": { + "stopped": "עצר", + "running": "רץ", + "down": "מטה", + "needsMaintenance": "זקוק לתחזוקה" + }, + "locations": { + "raleigh": "Raleigh", + "boston": "Boston", + "atlanta": "Atlanta", + "sanFrancisco": "San Francisco" + }, + "lastModified": { + "oneHr": "לפני שעה", + "threeHrs": "לפני 3 שעות", + "fiveHrs": "לפני 5 שעות", + "sevenMins": "לפני 7 דקות", + "fortyTwoMins": "לפני 42 דקות", + "twoDays": "לפני יומיים", + "oneMonth": "לפני חודש" + } } } -} \ No newline at end of file +} From 7e83812c017e0effa15904ba45b19091fa82d8ed Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Wed, 11 Oct 2023 14:18:09 -0400 Subject: [PATCH 05/11] Updated demo --- packages/react-core/src/demos/RTL/RTL.md | 3 +- .../RTL/examples/TableColumnManagement.jsx | 176 +++++++++++------- 2 files changed, 108 insertions(+), 71 deletions(-) diff --git a/packages/react-core/src/demos/RTL/RTL.md b/packages/react-core/src/demos/RTL/RTL.md index 8f1cd9af564..4fb2ab888a3 100644 --- a/packages/react-core/src/demos/RTL/RTL.md +++ b/packages/react-core/src/demos/RTL/RTL.md @@ -2,7 +2,7 @@ id: RTL section: patterns --- -import DashboardWrapper from '@patternfly/react-core/src/demos/examples/DashboardWrapper'; + import translationsEn from "./examples/translations.en.json"; import translationsHe from "./examples/translations.he.json"; import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-icon'; @@ -18,4 +18,5 @@ This demonstrates how the UI adapts to the writing mode of the page. ### Table column management ```js file="./examples/TableColumnManagement.jsx" isFullscreen + ``` diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx index 445d2cc19b4..6fa2c437a37 100644 --- a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -37,65 +37,91 @@ import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; export const ColumnManagementAction = () => { - const [t, setT] = React.useState(translationsEn); + const [translation, setTranslation] = React.useState(translationsEn); + const [page, setPage] = React.useState(1); + const [perPage, setPerPage] = React.useState(10); const columns = [ - t.table.columns.servers, - t.table.columns.status, - t.table.columns.location, - t.table.columns.modified, - t.table.columns.url, + translation.table.columns.servers, + translation.table.columns.status, + translation.table.columns.location, + translation.table.columns.modified, + translation.table.columns.url ]; const numRows = 25; const getRandomInteger = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; - - const tableRows = () => { + const createRows = () => { const rows = []; for (let i = 0; i < numRows; i++) { - const num = (i + 1); - rowObj = { - name: t.table.rows.node + num, - status: [t.table.rows.status.stopped, t.table.rows.status.running, t.table.rows.status.down, t.table.rows.status.needsMaintenance][getRandomInteger(0, 3)], - location: [t.table.rows.locations.raleigh, t.table.rows.locations.boston, t.table.rows.locations.atlanta, t.table.rows.locations.sanFrancisco][getRandomInteger(0, 3)], - lastModified: [t.table.rows.lastModified.oneHr, t.table.rows.lastModified.threeHrs, t.table.rows.lastModified.fiveHrs, t.table.rows.lastModified.sevenMins, t.table.rows.lastModified.fortyTwoMins, t.table.rows.lastModified.twoDays, t.table.rows.lastModified.oneMonth][getRandomInteger(0, 6)], + const num = i + 1; + const rowObj = { + name: translation.table.rows.node + num, + status: [ + translation.table.rows.status.stopped, + translation.table.rows.status.running, + translation.table.rows.status.down, + translation.table.rows.status.needsMaintenance + ][getRandomInteger(0, 3)], + location: [ + translation.table.rows.locations.raleigh, + translation.table.rows.locations.boston, + translation.table.rows.locations.atlanta, + translation.table.rows.locations.sanFrancisco + ][getRandomInteger(0, 3)], + lastModified: [ + translation.table.rows.lastModified.oneHr, + translation.table.rows.lastModified.threeHrs, + translation.table.rows.lastModified.fiveHrs, + translation.table.rows.lastModified.sevenMins, + translation.table.rows.lastModified.fortyTwoMins, + translation.table.rows.lastModified.twoDays, + translation.table.rows.lastModified.oneMonth + ][getRandomInteger(0, 6)], url: 'http://www.redhat.com/en/office-locations/node' + num }; rows.push(rowObj); } + return rows; - } + }; - const defaultRows = tableRows(); - const [managedRows, setManagedRows] = React.useState(defaultRows); - const [page, setPage] = React.useState(1); - const [perPage, setPerPage] = React.useState(10); - const [paginatedRows, setPaginatedRows] = React.useState(tableRows()); - const [isDirRTL, setDirRTL] = React.useState(false); + const rows = createRows(); + const [managedRows, setManagedRows] = React.useState(rows); + const [paginatedRows, setPaginatedRows] = React.useState(rows.slice(0, 10)); + const [isDirRTL, setIsDirRTL] = React.useState(false); - const switchRTL = () => { - setDirRTL((prevState) => !prevState); - setManagedRows(tableRows()); + const switchTranslation = () => { + setIsDirRTL((prevIsDirRTL) => !prevIsDirRTL); + setTranslation((prevTranslation) => (prevTranslation === translationsEn ? translationsHe : translationsEn)); }; + React.useEffect(() => { + const newRows = createRows(); + setManagedRows(newRows); + setPaginatedRows(newRows.slice((page - 1) * perPage, page * perPage)); + }, [translation]); + React.useEffect(() => { const html = document.querySelector('html'); - setT(isDirRTL ? translationsHe : translationsEn); html.dir = isDirRTL ? 'rtl' : 'ltr'; }, [isDirRTL]); // Pagination logic - const handleSetPage = (_evt, newPage) => { + + const handleSetPage = (_evt, newPage, _perPage, startIdx, endIdx) => { + setPaginatedRows(managedRows.slice(startIdx, endIdx)); setPage(newPage); }; - const handlePerPageSelect = (_evt, newPerPage) => { + const handlePerPageSelect = (_evt, newPerPage, _newPage, startIdx, endIdx) => { + setPaginatedRows(managedRows.slice(startIdx, endIdx)); setPerPage(newPerPage); }; const renderPagination = (variant, isCompact) => ( { } }; - const navItems = { - systemPanel: { - url: '#system-panel' - }, - policy: { - url: '#policy' - }, - authentication: { - url: '#authentication' - }, - networkServices: { - url: '#network-services' - }, - server: { - url: 'sub-category' - } - }; - - React.useEffect(() => { - setPaginatedRows(managedRows.slice((page - 1) * perPage, page * perPage - 1)); - }, [managedRows, page, perPage]); + // Commented out for linting + // const navItems = { + // systemPanel: { + // url: '#system-panel' + // }, + // policy: { + // url: '#policy' + // }, + // authentication: { + // url: '#authentication' + // }, + // networkServices: { + // url: '#network-services' + // }, + // server: { + // url: 'sub-category' + // } + // }; const renderLabel = (labelText) => { switch (labelText) { case 'Running': + case 'רץ': return ( ); case 'Stopped': - return ; + case 'עצר': + return ( + + ); case 'Needs maintenance': - return ; + case 'זקוק לתחזוקה': + return ( + + ); case 'Down': - return ; + case 'מטה': + return ( + + ); } }; @@ -179,9 +218,9 @@ export const ColumnManagementAction = () => { } iconPosition="end" - onClick={switchRTL} + onClick={switchTranslation} > - {t.switchBtn} + {translation.switchBtn} @@ -204,19 +243,19 @@ export const ColumnManagementAction = () => { @@ -235,7 +274,7 @@ export const ColumnManagementAction = () => { {Object.keys(breadcrumbItems).map((key, idx, arr) => ( - {t.breadcrumbs[key]} + {translation.breadcrumbs[key]} {breadcrumbItems.length} ))} @@ -243,8 +282,8 @@ export const ColumnManagementAction = () => { - {t.title} - {t.body} + {translation.title} + {translation.body} @@ -268,7 +307,7 @@ export const ColumnManagementAction = () => { {renderLabel(value)} - ) + ); } else if (key === 'url') { return ( @@ -276,16 +315,13 @@ export const ColumnManagementAction = () => { {row.url} - ) + ); } else { return ( - + {value} - ) + ); } })} From a431de265f3a036139bb94a00a674c4896d1e5c7 Mon Sep 17 00:00:00 2001 From: mcoker Date: Tue, 17 Oct 2023 13:32:23 -0500 Subject: [PATCH 06/11] chore(rtl): updated demo --- packages/react-core/src/demos/RTL/RTL.md | 10 +- .../RTL/examples/TableColumnManagement.css | 7 + .../RTL/examples/TableColumnManagement.jsx | 227 ++++++++++++++---- .../demos/RTL/examples/translations.en.json | 3 +- .../demos/RTL/examples/translations.he.json | 12 + 5 files changed, 209 insertions(+), 50 deletions(-) create mode 100644 packages/react-core/src/demos/RTL/examples/TableColumnManagement.css diff --git a/packages/react-core/src/demos/RTL/RTL.md b/packages/react-core/src/demos/RTL/RTL.md index 4fb2ab888a3..4acdb73d5fb 100644 --- a/packages/react-core/src/demos/RTL/RTL.md +++ b/packages/react-core/src/demos/RTL/RTL.md @@ -9,7 +9,15 @@ import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-i import ToolsIcon from '@patternfly/react-icons/dist/esm/icons/tools-icon'; import ClockIcon from '@patternfly/react-icons/dist/esm/icons/clock-icon'; import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; -import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; +import pfLogo from '@patternfly/react-core/src/demos/assets/pf-logo.svg'; +import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon'; +import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon'; +import QuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/question-circle-icon'; +import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; +import EllipsisVIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon'; +import imgAvatar from '@patternfly/react-core/src/components/assets/avatarImg.svg'; + +import './examples/TableColumnManagement.css'; ## Demos diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.css b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.css new file mode 100644 index 00000000000..adbc05697eb --- /dev/null +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.css @@ -0,0 +1,7 @@ +.brand-language { + font-weight: var(--pf-v5-global--FontWeight--bold); + font-family: var(--pf-v5-global--FontFamily--heading); + font-size: var(--pf-v5-global--FontSize--xl); + align-self: center; + margin-inline-start: var(--pf-v5-global--spacer--md); +} \ No newline at end of file diff --git a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx index 6fa2c437a37..679f2c43d00 100644 --- a/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx +++ b/packages/react-core/src/demos/RTL/examples/TableColumnManagement.jsx @@ -10,7 +10,6 @@ import { Nav, NavItem, NavList, - Page, PageBreadcrumb, PageSection, PageSidebar, @@ -34,7 +33,9 @@ import AlignRightIcon from '@patternfly/react-icons/dist/esm/icons/align-right-i import ToolsIcon from '@patternfly/react-icons/dist/esm/icons/tools-icon'; import ClockIcon from '@patternfly/react-icons/dist/esm/icons/clock-icon'; import WalkingIcon from '@patternfly/react-icons/dist/esm/icons/walking-icon'; -import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon'; +import pfLogo from '@patternfly/react-core/src/demos/assets/pf-logo.svg'; +import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon'; +import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon'; export const ColumnManagementAction = () => { const [translation, setTranslation] = React.useState(translationsEn); @@ -128,7 +129,15 @@ export const ColumnManagementAction = () => { onPerPageSelect={handlePerPageSelect} variant={variant} titles={{ - paginationAriaLabel: `${variant} pagination` + paginationAriaLabel: `${variant} pagination`, + ofWord: translation.pagination?.ofWord, + items: translation.pagination?.items, + perPageSuffix: translation.pagination?.perPageSuffix, + toNextPageAriaLabel: translation.pagination?.toNextPageAriaLabel, + toPreviousPageAriaLabel: translation.pagination?.toPreviousPageAriaLabel, + toFirstPageAriaLabel: translation.pagination?.toFirstPageAriaLabel, + toLastPageAriaLabel: translation.pagination?.perPageSuffix, + currentPage: translation.pagination?.currentPage }} /> ); @@ -145,25 +154,6 @@ export const ColumnManagementAction = () => { } }; - // Commented out for linting - // const navItems = { - // systemPanel: { - // url: '#system-panel' - // }, - // policy: { - // url: '#policy' - // }, - // authentication: { - // url: '#authentication' - // }, - // networkServices: { - // url: '#network-services' - // }, - // server: { - // url: 'sub-category' - // } - // }; - const renderLabel = (labelText) => { switch (labelText) { case 'Running': @@ -208,31 +198,20 @@ export const ColumnManagementAction = () => { - - - - - - - - - - - - + + + {renderPagination(PaginationVariant.top)} @@ -267,9 +246,161 @@ export const ColumnManagementAction = () => { ); + const [isDropdownOpen, setIsDropdownOpen] = React.useState(false); + const [isKebabDropdownOpen, setIsKebabDropdownOpen] = React.useState(false); + const [isFullKebabDropdownOpen, setIsFullKebabDropdownOpen] = React.useState(false); + + const kebabDropdownItems = ( + <> + + Settings + + + Help + + + ); + + const userDropdownItems = ( + <> + My profile + User management + Logout + + ); + + const onDropdownToggle = () => { + setIsDropdownOpen(!isDropdownOpen); + }; + + const onDropdownSelect = () => { + setIsDropdownOpen(false); + }; + + const onKebabDropdownToggle = () => { + setIsKebabDropdownOpen(!isKebabDropdownOpen); + }; + + const onKebabDropdownSelect = () => { + setIsKebabDropdownOpen(false); + }; + + const onFullKebabToggle = () => { + setIsFullKebabDropdownOpen(!isFullKebabDropdownOpen); + }; + + const onFullKebabSelect = () => { + setIsFullKebabDropdownOpen(false); + }; + + const masthead = ( + + + + + + + + + + {translation.brandLanguage && ( + {translation.brandLanguage} + )} + + + + + + + + +