From 5241a6b7c16ea3df812fb8c39df9f4cb618391ca Mon Sep 17 00:00:00 2001 From: Maxime Golfier <25312957+maxgfr@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:56:45 +0200 Subject: [PATCH] feat(ui): replace `theme-ui` by `mui` + migration vers `dsfr` (#992) --- .github/workflows/quality.yml | 6 +- .github/workflows/release.yml | 2 +- .node-version | 2 +- targets/frontend/next.config.js | 102 ++--- targets/frontend/package.json | 5 +- .../__tests__/contenus/contentList.test.tsx | 4 + .../src/components/alerts/AlertTabs.tsx | 48 ++- .../src/components/alerts/AlertTitle.tsx | 12 +- .../frontend/src/components/alerts/Status.tsx | 10 +- .../src/components/button/CopyButton.js | 11 +- .../frontend/src/components/button/index.tsx | 365 ++++++------------ .../src/components/changes/ChangeGroup.tsx | 267 ++++++++----- .../src/components/changes/ViewDiff.js | 13 +- .../src/components/collapsible/index.js | 2 +- .../src/components/comments/Comment.js | 17 +- .../src/components/comments/CommentForm.js | 15 +- .../src/components/comments/CommentList.js | 7 +- .../frontend/src/components/comments/index.js | 54 ++- .../src/components/confirmButton/index.tsx | 53 +-- .../contributions/answers/Answer.tsx | 16 +- .../contributions/questions/EditQuestion.tsx | 23 +- .../frontend/src/components/dialog/index.js | 12 +- .../src/components/documents/Actions.js | 10 +- .../src/components/documents/Container.js | 17 +- .../frontend/src/components/documents/List.js | 90 +++-- .../src/components/documents/SearchFilters.js | 159 +++++--- .../editorialContent/ContentSections.tsx | 11 +- .../editorialContent/EditorialContent.tsx | 11 +- .../editorialContent/MarkdownPreviewModal.tsx | 9 +- .../editorialContent/ReferenceBlocks.tsx | 18 +- .../editorialContent/References.tsx | 11 +- .../components/editorialContent/Section.tsx | 26 +- .../editorialContent/SectionBlock.tsx | 5 +- .../editorialContent/SectionBlocks.tsx | 16 +- .../src/components/export-es/Status.tsx | 40 +- .../components/export-es/TriggerButton.tsx | 31 +- .../src/components/fiches-sp/addFiche.js | 6 +- .../src/components/fiches-sp/addFicheForm.js | 34 +- .../components/fiches-sp/fichesSpContainer.js | 4 +- .../frontend/src/components/fiches-sp/list.js | 122 ------ .../src/components/fiches-sp/list.tsx | 113 ++++++ .../src/components/fiches-sp/selectActions.js | 8 +- .../forms/ContentPicker/ContentSearch.js | 30 +- .../forms/ContentPicker/SortableList.js | 48 ++- .../forms/ContentPicker/ThemePicker.js | 21 +- .../forms/ContentPicker/ThemeSearch.js | 34 +- .../src/components/forms/ErrorMessage.js | 7 +- .../frontend/src/components/forms/Fieldset.js | 9 +- .../src/components/forms/IconPicker.js | 29 +- .../src/components/forms/Lister/List.js | 43 ++- .../src/components/forms/Lister/index.js | 34 +- .../src/components/glossary/TermForm.js | 48 ++- .../src/components/glossary/TermList.js | 29 +- .../src/components/home/DuplicateItems.tsx | 5 +- .../home/InvisibleLinkedDocument.tsx | 5 +- .../src/components/home/UnThemedContent.tsx | 7 +- .../src/components/layout/Container.js | 2 - .../frontend/src/components/layout/Inline.js | 32 +- .../src/components/layout/LogoAdmin.tsx | 6 +- targets/frontend/src/components/layout/Nav.js | 13 +- .../src/components/layout/NavigationItem.tsx | 11 +- .../frontend/src/components/layout/Stack.js | 7 +- .../src/components/layout/UserMenu.tsx | 35 +- .../src/components/layout/auth.layout.tsx | 7 +- .../frontend/src/components/layout/header.tsx | 2 - .../src/components/layout/password.layout.js | 12 +- .../frontend/src/components/layout/spaces.js | 3 +- targets/frontend/src/components/list/index.js | 2 +- .../frontend/src/components/login/index.js | 127 +++--- .../src/components/pagination/index.js | 6 +- .../components/prequalified/Prequalified.tsx | 18 +- .../components/prequalified/ValidationBar.tsx | 26 +- .../src/components/storage/DropZone.js | 15 +- .../frontend/src/components/table/index.tsx | 36 +- targets/frontend/src/components/tabs/index.js | 51 --- .../frontend/src/components/themes/Form.js | 51 ++- .../frontend/src/components/themes/List.js | 41 +- targets/frontend/src/components/themes/Map.js | 22 +- .../src/components/themes/MapModal.js | 25 +- targets/frontend/src/components/user/List.js | 117 ++---- .../src/components/user/PasswordForm.js | 12 +- .../frontend/src/components/user/UserForm.js | 43 ++- .../src/components/utils/BreadcrumbLink.tsx | 25 ++ .../src/components/utils/SimpleLink.tsx | 17 +- .../frontend/src/components/utils/index.ts | 1 + targets/frontend/src/pages/_app.js | 32 +- targets/frontend/src/pages/_document.js | 48 +-- .../src/pages/alerts/[[...params]].tsx | 33 +- .../frontend/src/pages/change_password.tsx | 4 +- targets/frontend/src/pages/contenus/[id].tsx | 4 +- .../pages/contenus/create/[[...source]].tsx | 20 +- .../create/createContent.mutation.graphql | 17 +- .../frontend/src/pages/contenus/edit/[id].tsx | 51 +-- .../frontend/src/pages/contenus/edit/utils.ts | 21 + targets/frontend/src/pages/duplicates.tsx | 14 +- targets/frontend/src/pages/fichiers.js | 135 ++++--- .../frontend/src/pages/ghost-documents.tsx | 12 +- .../src/pages/glossary/edit/[[...id]].js | 15 +- targets/frontend/src/pages/glossary/index.js | 60 ++- targets/frontend/src/pages/index.tsx | 10 +- targets/frontend/src/pages/kali/blocks.js | 57 ++- targets/frontend/src/pages/login.js | 11 +- targets/frontend/src/pages/mises-a-jour.tsx | 34 +- targets/frontend/src/pages/reset_password.js | 14 +- .../frontend/src/pages/themes/[[...id]].js | 75 ++-- .../frontend/src/pages/themes/[id]/create.js | 2 +- .../frontend/src/pages/themes/edit/[id].js | 14 +- targets/frontend/src/pages/unthemed.js | 88 +++-- targets/frontend/src/pages/user/account.js | 60 +-- targets/frontend/src/pages/user/edit/[id].js | 3 - targets/frontend/src/pages/user/new.js | 6 +- targets/frontend/src/pages/users.js | 12 +- targets/frontend/src/theme.ts | 2 +- yarn.lock | 218 +++++------ 114 files changed, 2020 insertions(+), 1953 deletions(-) delete mode 100644 targets/frontend/src/components/fiches-sp/list.js create mode 100644 targets/frontend/src/components/fiches-sp/list.tsx delete mode 100644 targets/frontend/src/components/tabs/index.js create mode 100644 targets/frontend/src/components/utils/BreadcrumbLink.tsx create mode 100644 targets/frontend/src/pages/contenus/edit/utils.ts diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 81a1c03a9..a17247f95 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 20.3.1 cache: "yarn" - name: Install dependencies run: | @@ -61,7 +61,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 20.3.1 cache: "yarn" - name: Lint ${{ matrix.repositories }} run: | @@ -94,7 +94,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 20.3.1 cache: "yarn" - name: Test ${{ matrix.repositories }} run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fb2f18e94..fede5954d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 20.3.1 cache: "yarn" - name: Install dependencies run: yarn install --frozen-lockfile diff --git a/.node-version b/.node-version index 209e3ef4b..2edeafb09 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20 +20 \ No newline at end of file diff --git a/targets/frontend/next.config.js b/targets/frontend/next.config.js index 5a8f1a335..756410947 100644 --- a/targets/frontend/next.config.js +++ b/targets/frontend/next.config.js @@ -5,6 +5,7 @@ const withTM = require("next-transpile-modules")([ "@shared/graphql-client", "@shared/id-generator", "@socialgouv/cdtn-ui", + "@codegouvfr/react-dsfr", ]); const basePath = ""; @@ -14,54 +15,57 @@ const securityHeaders = [ key: "X-Frame-Options", value: "deny", }, - {key: "X-XSS-Protection", value: "1; mode=block"}, - {key: "X-Content-Type-Options", value: "nosniff"}, + { key: "X-XSS-Protection", value: "1; mode=block" }, + { key: "X-Content-Type-Options", value: "nosniff" }, ]; -module.exports = - withTM( - withSourceMaps({ - basePath, - async headers() { - return [ - { - headers: securityHeaders, - // Apply these headers to all routes in your application. - source: "/:path*", - }, - ]; - }, - poweredByHeader: false, - serverRuntimeConfig: { - rootDir: __dirname, - }, - webpack: (config, {isServer, dev}) => { - config.output.chunkFilename = isServer - ? `${dev ? "[name]" : "[name].[fullhash]"}.js` - : `static/chunks/${dev ? "[name]" : "[name].[fullhash]"}.js`; - config.module.rules.push({ - exclude: /node_modules/, - loader: "graphql-tag/loader", - test: /\.(graphql|gql)$/, - }); - // In `pages/_app.js`, Sentry is imported from @sentry/node. While - // @sentry/browser will run in a Node.js environment, @sentry/node will use - // Node.js-only APIs to catch even more unhandled exceptions. - // - // This works well when Next.js is SSRing your page on a server with - // Node.js, but it is not what we want when your client-side bundle is being - // executed by a browser. - // - // Luckily, Next.js will call this webpack function twice, once for the - // server and once for the client. Read more: - // https://nextjs.org/docs#customizing-webpack-config - // - // So ask Webpack to replace @sentry/node imports with @sentry/browser when - // building the browser's bundle - if (!isServer) { - config.resolve.alias["@sentry/node"] = "@sentry/browser"; - } - return config; - }, - }) - ); +module.exports = withTM( + withSourceMaps({ + basePath, + async headers() { + return [ + { + headers: securityHeaders, + // Apply these headers to all routes in your application. + source: "/:path*", + }, + ]; + }, + poweredByHeader: false, + serverRuntimeConfig: { + rootDir: __dirname, + }, + webpack: (config, { isServer, dev }) => { + config.output.chunkFilename = isServer + ? `${dev ? "[name]" : "[name].[fullhash]"}.js` + : `static/chunks/${dev ? "[name]" : "[name].[fullhash]"}.js`; + config.module.rules.push({ + exclude: /node_modules/, + loader: "graphql-tag/loader", + test: /\.(graphql|gql)$/, + }); + // In `pages/_app.js`, Sentry is imported from @sentry/node. While + // @sentry/browser will run in a Node.js environment, @sentry/node will use + // Node.js-only APIs to catch even more unhandled exceptions. + // + // This works well when Next.js is SSRing your page on a server with + // Node.js, but it is not what we want when your client-side bundle is being + // executed by a browser. + // + // Luckily, Next.js will call this webpack function twice, once for the + // server and once for the client. Read more: + // https://nextjs.org/docs#customizing-webpack-config + // + // So ask Webpack to replace @sentry/node imports with @sentry/browser when + // building the browser's bundle + if (!isServer) { + config.resolve.alias["@sentry/node"] = "@sentry/browser"; + } + config.module.rules.push({ + test: /\.woff2$/, + type: "asset/resource", + }); + return config; + }, + }) +); diff --git a/targets/frontend/package.json b/targets/frontend/package.json index 9ce8a0855..980e0b5cc 100644 --- a/targets/frontend/package.json +++ b/targets/frontend/package.json @@ -4,8 +4,10 @@ "dependencies": { "@azure/abort-controller": "^1.0.4", "@azure/storage-blob": "^12.7.0", + "@codegouvfr/react-dsfr": "^0.74.2", "@elastic/elasticsearch": "^7.14.1", "@emotion/react": "11.10.6", + "@emotion/server": "^11.11.0", "@emotion/styled": "11.10.6", "@hapi/boom": "^9.1.4", "@hapi/joi": "^17.1.1", @@ -74,7 +76,6 @@ "strip-markdown": "^4.2.0", "styled-components": "^5.3.9", "swr": "^1.0.1", - "theme-ui": "^0.11.2", "unified": "^9.2.2", "unist-util-parents": "^1.0.3", "unist-util-select": "^4.0.1", @@ -117,6 +118,8 @@ "lint": "next lint", "precommit": "lint-staged", "start": "next start", + "predev": "only-include-used-icons", + "prebuild": "only-include-used-icons", "prepush": "yarn build && yarn lint && yarn test --bail --changedSince=master", "test": "jest" } diff --git a/targets/frontend/src/__tests__/contenus/contentList.test.tsx b/targets/frontend/src/__tests__/contenus/contentList.test.tsx index 7e5b8b295..906fc9d82 100644 --- a/targets/frontend/src/__tests__/contenus/contentList.test.tsx +++ b/targets/frontend/src/__tests__/contenus/contentList.test.tsx @@ -9,6 +9,10 @@ jest.mock("next/router", () => ({ }), })); +jest.mock("@codegouvfr/react-dsfr/useIsDark", () => ({ + useIsDark: jest.fn().mockReturnValue(false), +})); + describe("Given parameters", () => { describe("When rendering the component DocumentsPage", () => { let rendering: RenderResult; diff --git a/targets/frontend/src/components/alerts/AlertTabs.tsx b/targets/frontend/src/components/alerts/AlertTabs.tsx index 4719531c2..d48643da9 100644 --- a/targets/frontend/src/components/alerts/AlertTabs.tsx +++ b/targets/frontend/src/components/alerts/AlertTabs.tsx @@ -1,12 +1,13 @@ import Link from "next/link"; import PropTypes from "prop-types"; import { getStatusLabel, slugifyRepository } from "src/models"; -import { Spinner } from "theme-ui"; +import CircularProgress from "@mui/material/CircularProgress"; import { useQuery } from "urql"; +import { Tabs, Tab } from "@mui/material"; -import { TabItem, Tabs } from "../tabs"; import { FixedSnackBar } from "../utils/SnackBar"; import React from "react"; +import { useRouter } from "next/router"; const countAlertByStatusQuery = ` query getAlerts($repository: String!) { @@ -30,6 +31,14 @@ export function AlertTabs({ repository: string; activeStatus: string; }) { + const router = useRouter(); + + const [value, setValue] = React.useState(0); + + const handleChange = (event: React.SyntheticEvent, newValue: number) => { + setValue(newValue); + }; + const [result] = useQuery({ query: countAlertByStatusQuery, variables: { @@ -37,10 +46,19 @@ export function AlertTabs({ }, }); + React.useEffect(() => { + const status = result.data?.statuses.find( + (status: any) => status.name === activeStatus + ); + if (status) { + setValue(result.data?.statuses.indexOf(status)); + } + }, [result.data, activeStatus]); + const { fetching, error, data } = result; if (fetching) { - return ; + return ; } if (error) { @@ -52,19 +70,21 @@ export function AlertTabs({ } return ( - + {data.statuses.map((status: any) => ( - - - {getStatusLabel(status.name)} ({status.alerts.aggregate.count}) - - + label={`${getStatusLabel(status.name)} (${ + status.alerts.aggregate.count + })`} + onClick={() => { + router.push( + `/alerts/${slugifyRepository(repository)}/${status.name}`, + undefined, + { shallow: true } + ); + }} + /> ))} ); diff --git a/targets/frontend/src/components/alerts/AlertTitle.tsx b/targets/frontend/src/components/alerts/AlertTitle.tsx index 6f3cdceda..a319480d7 100644 --- a/targets/frontend/src/components/alerts/AlertTitle.tsx +++ b/targets/frontend/src/components/alerts/AlertTitle.tsx @@ -17,15 +17,15 @@ export const AlertTitle: React.FC = ({ alertId, info, children }) => { return ( -

{children}

+

{children}

{info.type === "dila" && info.num && ( - + = ({ alertId, info, children }) => { setShowComment(!showComment)} > - + {showComment && }
diff --git a/targets/frontend/src/components/alerts/Status.tsx b/targets/frontend/src/components/alerts/Status.tsx index 3b7dc6e8c..d02c758ac 100644 --- a/targets/frontend/src/components/alerts/Status.tsx +++ b/targets/frontend/src/components/alerts/Status.tsx @@ -25,16 +25,16 @@ export function AlertStatus({ alertId }: { alertId: string }) { } return ( - - updateStatus("doing")}> - + + updateStatus("doing")}> + En cours - updateStatus("done")}> + updateStatus("done")}> {" "} Traité - updateStatus("rejected")}> + updateStatus("rejected")}> {" "} Rejeté diff --git a/targets/frontend/src/components/button/CopyButton.js b/targets/frontend/src/components/button/CopyButton.js index e3cd97d75..0d4de5453 100644 --- a/targets/frontend/src/components/button/CopyButton.js +++ b/targets/frontend/src/components/button/CopyButton.js @@ -2,6 +2,7 @@ import { Button } from "@mui/material"; import PropTypes from "prop-types"; import { useEffect, useState } from "react"; import { IoMdCheckmark, IoMdClipboard } from "react-icons/io"; +import { theme } from "../../theme"; export const CopyButton = ({ onClip, @@ -34,11 +35,11 @@ export const CopyButton = ({ > {copied ? ( <> - Copié ! + Copié ! ) : ( <> - + Copier )} @@ -47,9 +48,9 @@ export const CopyButton = ({ }; const iconSx = { - height: "iconSmall", - mr: "xxsmall", - width: "iconSmall", + height: theme.sizes.iconSmall, + marginRight: theme.space.xxsmall, + width: theme.sizes.iconSmall, }; CopyButton.propTypes = { diff --git a/targets/frontend/src/components/button/index.tsx b/targets/frontend/src/components/button/index.tsx index 7f70e1e16..4ba78e4eb 100644 --- a/targets/frontend/src/components/button/index.tsx +++ b/targets/frontend/src/components/button/index.tsx @@ -1,316 +1,189 @@ -/** @jsxImportSource theme-ui */ - -import { - AccordionButton as ReachAccordionButton, - useAccordionItemContext, -} from "@reach/accordion"; -import { - Menu, - MenuButton as ReachMenuButton, - MenuItem as ReachMenuItem, - MenuItemProps, - MenuList, -} from "@reach/menu-button"; -import PropTypes from "prop-types"; import React from "react"; -import { IoIosArrowDown, IoIosArrowForward, IoMdMore } from "react-icons/io"; -import type { Theme, ThemeUIStyleObject } from "theme-ui"; import { - Box, - Button as BaseButton, - get, - IconButton as BaseIconButton, - NavLink, -} from "theme-ui"; + ButtonProps, + Button as MuiButton, + IconButton as MuiIconButton, +} from "@mui/material"; +import { Menu, MenuItem as MenuItemButton } from "@mui/material"; +import { + ExpandMore as ExpandMoreIcon, + ChevronRight as ChevronRightIcon, + MoreVert as MoreVertIcon, +} from "@mui/icons-material"; +import { Box } from "@mui/material"; +import { theme } from "src/theme"; type ButtonPropTypes = { children: React.ReactNode; type?: "button" | "reset" | "submit"; disabled?: boolean; - size?: "small" | "normal"; - variant?: "accent" | "secondary" | "primary" | "link"; + variant?: "contained" | "outlined" | "text"; onClick?: (e: unknown) => void; -}; - -declare module "react" { - interface Attributes { - sx?: ThemeUIStyleObject; - } -} + sx?: Record; +} & ButtonProps; -const defaultButtonStyles = { - alignItems: "center", - appearance: "none", - borderRadius: "small", - borderStyle: "solid", - borderWidth: 2, - cursor: "pointer", - display: "inline-flex", - fontFamily: "muli", - fontSize: "inherit", - fontWeight: "bold", - lineHeight: "inherit", - m: 0, - minWidth: 0, - textAlign: "center", - textDecoration: "none", -} as const; -const normalSize = { - px: "xsmall", - py: "xsmall", -}; -const smallSize = { - px: "xxsmall", - py: "xxsmall", -}; - -type ButtonPropTypesWithRef = ButtonPropTypes & { - ref: React.Ref; -}; - -const SolidButton: React.FC = React.forwardRef< - HTMLButtonElement, - ButtonPropTypes ->(function _SolidButton( - { variant = "primary", size = "normal", ...props }, - ref -) { +const SolidButton: React.FC = ({ + variant = "contained", + ...props +}) => { return ( - get(theme, `buttons.${variant}.bgHover`), - borderColor: (theme: Theme) => - get(theme, `buttons.${variant}.bgHover`), - }, - "&[disabled]": { - bg: "muted", - borderColor: "muted", - cursor: "default", - }, - bg: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - borderColor: (theme) => get(theme, `buttons.${variant}.bg`), borderRadius: "small", - color: (theme: Theme) => get(theme, `buttons.${variant}.color`), + fontWeight: "bold", + textTransform: "none", }} /> ); -}); +}; -const OutlineButton: React.FC = React.forwardRef< - HTMLButtonElement, - ButtonPropTypes ->(function _OutlineButton( - { variant = "primary", size = "normal", ...props }, - ref -) { +const OutlineButton: React.FC = ({ + variant = "outlined", + size = "medium", + ...props +}) => { return ( - - get(theme, `buttons.${variant}.bgHover`), - color: (theme: Theme) => get(theme, `buttons.${variant}.bgHover`), - }, - "&[disabled]": { - borderColor: "muted", - color: "muted", - }, - bg: (theme: Theme) => get(theme, `buttons.${variant}.color`), - borderColor: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - color: (theme: Theme) => get(theme, `buttons.${variant}.bg`), + fontWeight: "bold", + textTransform: "none", }} /> ); -}); +}; type OutlineOrSolidButtonProps = ButtonPropTypes & { outline?: boolean }; -export const Button: React.FC = React.forwardRef< - HTMLButtonElement, - OutlineOrSolidButtonProps ->(function _Button({ outline = false, ...props }, ref) { - return outline ? ( - - ) : ( - - ); -}); +export const Button: React.FC = ({ + outline = false, + ...props +}) => { + return outline ? : ; +}; type ButtonPropTypesWithSx = ButtonPropTypes & { - size?: "small" | "large" | "normal"; - sx?: ThemeUIStyleObject; - variant?: "primary" | "secondary"; + size?: "small" | "large" | "medium"; + sx?: React.CSSProperties; + variant?: "contained" | "outlined"; }; -export const IconButton: React.FC = React.forwardRef< - HTMLButtonElement, - ButtonPropTypesWithSx ->(function _IconButton( - { variant = "primary", sx = {}, size = "large", ...props }, - ref -) { +export const IconButton: React.FC = ({ + variant = "contained", + sx = {}, + size = "large", + ...props +}) => { return ( - get(theme, "buttons.icon.bgHover"), - color: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - }, - "&[disabled]": { - bg: "neutral", - color: "text", - }, - border: "none", borderRadius: 32, - color: (theme: Theme) => get(theme, `buttons.${variant}.bg`), fontSize: size, - lineHeight: 1, overflow: "hidden", ...sx, }} /> ); -}); +}; + +export const MenuButton: React.FC = ({ children }) => { + const [anchorEl, setAnchorEl] = React.useState(null); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; -export const MenuButton: React.FC = ({ - variant = "primary", - size = "large", - children, -}) => { return ( - - + get(theme, "buttons.icon.bgHover"), - color: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - }, - "&[disabled]": { - bg: "neutral", - color: "text", - }, - bg: "transparent", - border: "none", borderRadius: 32, - color: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - fontSize: size, - height: 32, - justifyContent: "center", - lineHeight: 1, + color: "primary.main", + fontSize: "large", overflow: "hidden", - padding: 0, - width: 32, }} > -
- -
-
- + + + {children} - - +
+ ); }; -export function MenuItem( - props: Pick< - MenuItemProps, - "children" | "onSelect" | "disabled" | "index" | "valueText" - > -): JSX.Element { +type AccordionProps = { + items: React.ReactNode[] | React.ReactNode; + children: React.ReactNode; +}; + +export function AccordionButton({ + children, + items, +}: AccordionProps): JSX.Element { + const [isExpanded, setIsExpanded] = React.useState(false); return ( - + <> + setIsExpanded(!isExpanded)} + > + {isExpanded ? : } + {children} + + {isExpanded && items} + ); } -export function AccordionButton({ - children, - ...props -}: React.ButtonHTMLAttributes): JSX.Element { +export const MenuItem: React.FC = ({ children, ...props }) => { return ( - - - - {children} - + ); -} -AccordionButton.propTypes = { - children: PropTypes.node, }; -export function ExpandedIcon(): JSX.Element { - const { isExpanded } = useAccordionItemContext(); - return isExpanded ? : ; -} - -export const NavButton: React.FC = React.forwardRef< - HTMLAnchorElement, - ButtonPropTypes ->(function _SolidButton({ variant = "primary", ...props }, ref) { +export const NavButton: React.FC = ({ + variant = "contained", + ...props +}) => { return ( - get(theme, `buttons.${variant}.bgHover`), - borderColor: (theme: Theme) => - get(theme, `buttons.${variant}.bgHover`), - color: (theme: Theme) => get(theme, `buttons.${variant}.color`), - }, - "&[disabled]": { - bg: "muted", - borderColor: "muted", - }, - bg: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - borderColor: (theme: Theme) => get(theme, `buttons.${variant}.bg`), - borderRadius: "small", - color: (theme: Theme) => get(theme, `buttons.${variant}.color`), - display: "inline-flex", + borderRadius: theme.space.small, fontWeight: "bold", + textTransform: "none", }} - {...props} /> ); -}); +}; diff --git a/targets/frontend/src/components/changes/ChangeGroup.tsx b/targets/frontend/src/components/changes/ChangeGroup.tsx index f4ceb09c6..56d84f51f 100644 --- a/targets/frontend/src/components/changes/ChangeGroup.tsx +++ b/targets/frontend/src/components/changes/ChangeGroup.tsx @@ -1,6 +1,3 @@ -/** @jsxImportSource theme-ui */ - -import { AccordionItem, AccordionPanel } from "@reach/accordion"; import type { AlertChanges, DilaAddedNode, @@ -14,8 +11,7 @@ import type { } from "@shared/types"; import slugify from "@socialgouv/cdtn-slugify"; import { getRouteBySource } from "@socialgouv/cdtn-sources"; -import { Badge, Box, Card } from "@theme-ui/components"; -import { Divider } from "@mui/material"; +import { Badge, Box, Card, List, ListItem } from "@mui/material"; import Link from "next/link"; import React, { useState } from "react"; @@ -25,6 +21,7 @@ import { AccordionButton, Button } from "src/components/button"; import { jsxJoin } from "../../lib/jsx"; import { Stack } from "../layout/Stack"; import { ViewDiff } from "./ViewDiff"; +import { theme } from "src/theme"; type Props = { label: string; @@ -32,12 +29,21 @@ type Props = { export const ChangesGroup: React.FC = ({ label, children }) => { return ( - - {label} - -
    {children}
-
-
+ + {children} + + } + > + {label} + ); }; @@ -54,9 +60,12 @@ export function AlertRelatedDocuments({ return ( <> {changes?.documents.map((change, i) => ( -
  • + -
  • + ))} ); @@ -85,9 +94,9 @@ export function DilaRelatedDocuments({ {jsxJoin( docReferences.references.map((node, i) => (
    {" "}
    @@ -135,12 +144,23 @@ export function AddedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.added.map((change) => ( -
  • + {" "} - + {change.etat} -
  • + ))} ); @@ -149,9 +169,12 @@ export function AddedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.added.map((change) => ( -
  • + -
  • + ))} ); @@ -160,9 +183,12 @@ export function AddedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.added.map((change) => ( -
  • + -
  • + ))} ); @@ -176,9 +202,12 @@ export function RemovedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.removed.map((change) => ( -
  • + -
  • + ))} ); @@ -187,9 +216,12 @@ export function RemovedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.removed.map((change) => ( -
  • + -
  • + ))} ); @@ -198,9 +230,12 @@ export function RemovedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.removed.map((change) => ( -
  • + -
  • + ))} ); @@ -221,45 +256,67 @@ export function ModifiedChanges({ changes }: ChangesProps): JSX.Element { ({ type }) => type !== "etat" ); return ( -
  • + {" "} - {statusUpdate && ( - <> - - {statusUpdate.previousText} - - {" › "} - - )} - - {change.etat} - + + {statusUpdate && ( + <> + + {statusUpdate.previousText} + + + {"›"} + + + )} + + {change.etat} + + {textChanges.length > 0 && ( - {jsxJoin( - textChanges.map((diff) => { - return ( - <> - Modification du {diff.type} - - - ); - }), - - )} + {textChanges.map((diff) => { + return ( + <> + Modification du {diff.type} + + + ); + })} )} -
  • + ); })} @@ -269,27 +326,27 @@ export function ModifiedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.modified.map((change) => ( -
  • + - {jsxJoin( - change.addedSections - .concat(change.removedSections, change.modifiedSections) - .map((diff) => { - return ( - <> - {diff.title} - - - ); - }), - - )} + {change.addedSections + .concat(change.removedSections, change.modifiedSections) + .map((diff) => { + return ( + <> + {diff.title} + + + ); + })} -
  • + ))} ); @@ -298,7 +355,10 @@ export function ModifiedChanges({ changes }: ChangesProps): JSX.Element { return ( <> {changes.modified.map((change) => ( -
  • + {change.title} @@ -307,7 +367,7 @@ export function ModifiedChanges({ changes }: ChangesProps): JSX.Element { current={change.currentText} /> -
  • + ))} ); @@ -318,14 +378,14 @@ export function ModifiedChanges({ changes }: ChangesProps): JSX.Element { function getBadgeColor(etat: string) { switch (etat) { case "VIGUEUR": - return "positive"; + return theme.colors.positive; case "MOIFIE": - return "caution"; + return theme.colors.caution; case "ABROGE": case "ABROGE_DIFF": - return "critical"; + return theme.colors.critical; default: - return "info"; + return theme.colors.info; } } @@ -424,9 +484,9 @@ function FicheLink({ change, documents = [] }: FicheLinkProps) { {linkedDocuments.length > 0 && ( @@ -449,9 +509,9 @@ function FicheLink({ change, documents = [] }: FicheLinkProps) {
    {linkedDocuments.length > 0 && ( @@ -472,29 +532,36 @@ export const ModificationViewer: React.FC = ({ const [isVisible, setVisible] = useState(false); const id = `collapsible-component-${COLLAPSIBLE_ID++}`; return ( - <> + {isVisible && ( - + {children} )} - + ); }; + +const styles = { + listItem: { + display: "flex", + flexDirection: "column", + alignItems: "flex-start", + }, +} as const; diff --git a/targets/frontend/src/components/changes/ViewDiff.js b/targets/frontend/src/components/changes/ViewDiff.js index 3be0022af..e3bdc85b3 100644 --- a/targets/frontend/src/components/changes/ViewDiff.js +++ b/targets/frontend/src/components/changes/ViewDiff.js @@ -1,8 +1,8 @@ -/** @jsxImportSource theme-ui */ - -import { Spinner } from "@theme-ui/components"; +import Spinner from "@mui/material/CircularProgress"; import PropTypes from "prop-types"; import { useEffect, useRef, useState } from "react"; +import { theme } from "src/theme"; +import { Box } from "@mui/material"; export const ViewDiff = ({ sx = {}, previous, current }) => { const workerRef = useRef(); @@ -19,11 +19,10 @@ export const ViewDiff = ({ sx = {}, previous, current }) => { }, [current, previous]); return htmlDiff ? ( -
    setVisible(!isVisible)} > diff --git a/targets/frontend/src/components/comments/Comment.js b/targets/frontend/src/components/comments/Comment.js index 2f720ce7a..ea6570cc2 100644 --- a/targets/frontend/src/components/comments/Comment.js +++ b/targets/frontend/src/components/comments/Comment.js @@ -1,20 +1,21 @@ import PropTypes from "prop-types"; -import { Box, Text } from "theme-ui"; +import { Box } from "@mui/material"; export function Comment({ comment }) { return ( - +

    {comment.user.name} - {" "} - +

    {" "} +

    {new Date(comment.createdAt).toLocaleDateString()} - +

    - - {comment.text} - +

    {comment.text}

    ); } diff --git a/targets/frontend/src/components/comments/CommentForm.js b/targets/frontend/src/components/comments/CommentForm.js index bd427fd51..27f6b7d1a 100644 --- a/targets/frontend/src/components/comments/CommentForm.js +++ b/targets/frontend/src/components/comments/CommentForm.js @@ -1,7 +1,7 @@ import VisuallyHidden from "@reach/visually-hidden"; import PropTypes from "prop-types"; import { useForm } from "react-hook-form"; -import { Input, Label } from "theme-ui"; +import { TextField } from "@mui/material"; import { Button } from "../button"; @@ -19,25 +19,20 @@ export function CommentForm({ onSubmit }) { return (
    - +
    ); } diff --git a/targets/frontend/src/components/comments/CommentList.js b/targets/frontend/src/components/comments/CommentList.js index 25d3a001a..44784770b 100644 --- a/targets/frontend/src/components/comments/CommentList.js +++ b/targets/frontend/src/components/comments/CommentList.js @@ -1,9 +1,10 @@ import PropTypes from "prop-types"; import { useLayoutEffect, useRef } from "react"; -import { Box, Text } from "theme-ui"; +import { Box } from "@mui/material"; import { Stack } from "../layout/Stack"; import { Comment, commentPropTypes } from "./Comment"; +import { theme } from "src/theme"; export function CommentList({ comments }) { const scrollContainer = useRef(); @@ -23,9 +24,7 @@ export function CommentList({ comments }) { )) ) : ( - - Aucun commentaire - +

    Aucun commentaire

    )}
    diff --git a/targets/frontend/src/components/comments/index.js b/targets/frontend/src/components/comments/index.js index 8314fd122..2bedc3124 100644 --- a/targets/frontend/src/components/comments/index.js +++ b/targets/frontend/src/components/comments/index.js @@ -1,14 +1,13 @@ -/** @jsxImportSource theme-ui */ - import PropTypes from "prop-types"; import { useMemo } from "react"; import { useUser } from "src/hooks/useUser"; -import { Card, Message } from "theme-ui"; +import { Card, Alert } from "@mui/material"; import { useMutation, useQuery } from "urql"; import { Stack } from "../layout/Stack"; import { CommentForm } from "./CommentForm"; import { CommentList } from "./CommentList"; +import { theme } from "src/theme"; const commentMutation = ` mutation insertNote($data: alert_notes_insert_input!) { @@ -25,29 +24,6 @@ query getComments($alertId: uuid!) { } `; -function CommentsContainer({ alertId }) { - return ( -
    - - - -
    - ); -} -CommentsContainer.propTypes = { - alertId: PropTypes.string.isRequired, -}; - function Comments({ alertId }) { const [, postComment] = useMutation(commentMutation); const { user } = useUser(); @@ -72,9 +48,9 @@ function Comments({ alertId }) { if (fetching) return chargement...; if (error) { return ( - +
    {JSON.stringify(error, 0, null)}
    -
    + ); } return ( @@ -88,4 +64,26 @@ Comments.propTypes = { alertId: PropTypes.string.isRequired, }; +function CommentsContainer({ alertId }) { + return ( + + + + ); +} +CommentsContainer.propTypes = { + alertId: PropTypes.string.isRequired, +}; + export { CommentsContainer as Comments }; diff --git a/targets/frontend/src/components/confirmButton/index.tsx b/targets/frontend/src/components/confirmButton/index.tsx index 69a2f4f58..b145e9d53 100644 --- a/targets/frontend/src/components/confirmButton/index.tsx +++ b/targets/frontend/src/components/confirmButton/index.tsx @@ -1,7 +1,7 @@ import PropTypes from "prop-types"; import React, { useState } from "react"; import { MdClose } from "react-icons/md"; -import { Button as BaseButton } from "theme-ui"; +import { Button as BaseButton } from "@mui/material"; const buttonPropTypes = { children: PropTypes.oneOfType([ @@ -11,36 +11,11 @@ const buttonPropTypes = { disabled: PropTypes.bool, onClick: PropTypes.func, size: PropTypes.oneOf(["small", "normal"]), - variant: PropTypes.oneOf(["accent", "secondary", "primary", "link"]), -}; - -const defaultButtonStyles = { - alignItems: "center", - appearance: "none", - borderRadius: "small", - borderStyle: "solid", - borderWidth: 2, - cursor: "pointer", - display: "inline-flex", - fontSize: "inherit", - fontWeight: "bold", - lineHeight: "inherit", - m: 0, - minWidth: 0, - textAlign: "center", - textDecoration: "none", -}; -const normalSize = { - px: "xsmall", - py: "xsmall", -}; -const smallSize = { - px: "xxsmall", - py: "xxsmall", + variant: PropTypes.oneOf(["contained", "outlined", "text"]), }; export const ConfirmButton = React.forwardRef(function _ConfirmButton( - { variant = "primary", size = "normal", children, onClick, ...props }: any, + { size = "normal", children, onClick, ...props }: any, ref ) { const [needConfirm, setNeedConfirm] = useState(false); @@ -58,27 +33,7 @@ export const ConfirmButton = React.forwardRef(function _ConfirmButton( setNeedConfirm(false); }; return ( - theme.buttons[variant].bgHover, - borderColor: (theme: any) => theme.buttons[variant].bgHover, - }, - "&[disabled]": { - bg: "muted", - borderColor: "muted", - }, - bg: (theme: any) => theme.buttons[variant].bg, - borderColor: (theme: any) => theme.buttons[variant].bg, - borderRadius: "small", - color: (theme: any) => theme.buttons[variant].color, - }} - onClick={onClickCustom} - > + {needConfirm ? ( <> Vraiment ? diff --git a/targets/frontend/src/components/contributions/answers/Answer.tsx b/targets/frontend/src/components/contributions/answers/Answer.tsx index 902f841f6..6d9fe4a40 100644 --- a/targets/frontend/src/components/contributions/answers/Answer.tsx +++ b/targets/frontend/src/components/contributions/answers/Answer.tsx @@ -32,8 +32,8 @@ import { } from "./references"; import { statusesMapping } from "../status/data"; import { getNextStatus, getPrimaryButtonLabel } from "../status/utils"; -import { SimpleLink } from "../../utils/SimpleLink"; import { SnackBar } from "../../utils/SnackBar"; +import { BreadcrumbLink } from "src/components/utils"; export type ContributionsAnswerProps = { id: string; @@ -132,15 +132,17 @@ export const ContributionsAnswer = ({ <> - - Contributions - + + Contributions + + {answer?.question?.content} - -
    {answer?.agreement?.id}
    -
    + + {answer?.agreement?.id} +
    {answer?.status && ( diff --git a/targets/frontend/src/components/contributions/questions/EditQuestion.tsx b/targets/frontend/src/components/contributions/questions/EditQuestion.tsx index f6c86fe8d..9e6967857 100644 --- a/targets/frontend/src/components/contributions/questions/EditQuestion.tsx +++ b/targets/frontend/src/components/contributions/questions/EditQuestion.tsx @@ -1,19 +1,12 @@ import SentimentVeryDissatisfiedIcon from "@mui/icons-material/SentimentVeryDissatisfied"; -import { - Breadcrumbs, - Skeleton, - Stack, - Typography, - Box, - Tab, - Tabs, -} from "@mui/material"; +import { Skeleton, Stack, Typography, Box, Tab, Tabs } from "@mui/material"; import Link from "next/link"; import React from "react"; import { EditQuestionAnswerList } from "./EditQuestionAnswerList"; import { EditQuestionForm } from "./EditQuestionForm"; import { useQuestionQuery } from "./Question.query"; +import { BreadcrumbLink } from "src/components/utils"; export type EditQuestionProps = { questionId: string; @@ -77,12 +70,10 @@ export const EditQuestion = ({ } const Header = () => ( - <> - - Contributions -
    {data?.question?.content}
    -
    - +
      + Contributions + {data?.question?.content} +
    ); const handleTabChange = (event: React.SyntheticEvent, newValue: TabValue) => { @@ -125,7 +116,7 @@ export const EditQuestion = ({ spacing={2} >
    - + - +

    Êtes vous sûr de vouloir modifier la publication des contenus ? - +

    - @@ -75,7 +75,7 @@ function Recap({ publications }) { ); return ( - Détails +

    Détails

      {items.published > 0 && (
    • diff --git a/targets/frontend/src/components/documents/Container.js b/targets/frontend/src/components/documents/Container.js index 477bfb767..23470e40c 100644 --- a/targets/frontend/src/components/documents/Container.js +++ b/targets/frontend/src/components/documents/Container.js @@ -5,7 +5,7 @@ import PropTypes from "prop-types"; import { useCallback, useMemo } from "react"; import { IoMdAdd } from "react-icons/io"; import { useSelectionContext } from "src/pages/contenus"; -import { Card, Flex, Message } from "theme-ui"; +import { Card, Alert, Box } from "@mui/material"; import { useMutation, useQuery } from "urql"; import { Stack } from "../layout/Stack"; @@ -13,6 +13,7 @@ import { Pagination } from "../pagination"; import { DocumentsListActions } from "./Actions"; import { DocumentList } from "./List"; import { SearchFilters } from "./SearchFilters"; +import { theme } from "src/theme"; export function DocumentListContainer({ initialFilterValues }) { const router = useRouter(); @@ -67,11 +68,11 @@ export function DocumentListContainer({ initialFilterValues }) { const { fetching, error, data } = result; if (error) { - return {error.message}; + return {error.message}; } return ( - + Ajouter un contenu - - + + - - - - Document - Publié - Disponible - - - + + + + + Document + Publié + Disponible + + + {documents.map((doc) => ( ))} - -
      + + ); } DocumentList.propTypes = { @@ -54,20 +59,28 @@ const DocumentRow = function DocumentRow({ }; return ( - - - - - + + +
      + +
      +
      + - - + + {isPublished ? ( @@ -94,8 +107,8 @@ const DocumentRow = function DocumentRow({ )} - - + + {isAvailable ? ( @@ -105,8 +118,8 @@ const DocumentRow = function DocumentRow({ )} - - + +
      ); }; @@ -132,10 +145,3 @@ export const sourceToRoute = ({ cdtnId, source }) => { return `/contenus/${cdtnId}`; } }; - -const checkboxStyles = { - cursor: "pointer", - display: "block", - m: "0 0 0 small", - padding: 0, -}; diff --git a/targets/frontend/src/components/documents/SearchFilters.js b/targets/frontend/src/components/documents/SearchFilters.js index 996aad215..c0feaf713 100644 --- a/targets/frontend/src/components/documents/SearchFilters.js +++ b/targets/frontend/src/components/documents/SearchFilters.js @@ -2,7 +2,15 @@ import { getLabelBySource, SOURCES } from "@socialgouv/cdtn-sources"; import PropTypes from "prop-types"; import { useForm } from "react-hook-form"; import { IoMdSearch } from "react-icons/io"; -import { Box, Input, Label, Radio, Select } from "theme-ui"; +import { + Box, + Input, + Select, + Radio, + FormControlLabel, + FormLabel, + MenuItem, +} from "@mui/material"; import { useQuery } from "urql"; import { Button } from "../button"; @@ -59,7 +67,8 @@ export function SearchFilters({ initialValues, onSearchUpdate }) { console.log("update filters"); onSearchUpdate({ ...initialValues, - [event.target.name]: event.target.value, + [event.target.name]: + event.target.value === "no-filter" ? "" : event.target.value, }); } @@ -69,36 +78,37 @@ export function SearchFilters({ initialValues, onSearchUpdate }) { return (
      - + - - - - - - Publication : -